mirror of
https://github.com/apache/nuttx.git
synced 2026-09-13 06:00:17 +00:00
Added DMA support for H5. Also added ADC DMA support.
Added logic to set hasdma to false. This is needed to enable or not enable interrupts on a per ADC basis. Made other minor formatting changes. Fixed build issues with non ADC/DMA configurations.
This commit is contained in:
parent
156ef05205
commit
0c1f9d482d
9 changed files with 1589 additions and 178 deletions
|
|
@ -881,6 +881,75 @@ config ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG
|
|||
---help---
|
||||
Enables special, board-specific STM32 clock configuration.
|
||||
|
||||
menu "ADC Configuration"
|
||||
depends on STM32H5_ADC
|
||||
|
||||
config STM32H5_ADC_MAX_SAMPLES
|
||||
int "The maximum number of channels that can be sampled"
|
||||
default 16
|
||||
---help---
|
||||
The maximum number of samples which can be handled without
|
||||
overrun depends on various factors. This is the user's
|
||||
responsibility to correctly select this value.
|
||||
Since the interface to update the sampling time is available
|
||||
for all supported devices, the user can change the default
|
||||
values in the board initialization logic and avoid ADC overrun.
|
||||
|
||||
config STM32H5_ADC1_DMA
|
||||
bool "ADC1 DMA Enable"
|
||||
depends on STM32H5_ADC1 && STM32H5_DMA
|
||||
default n
|
||||
---help---
|
||||
If DMA is selected, then the ADC may be configured to support DMA
|
||||
transfer, which is necessary if multiple channels are read or if
|
||||
very high trigger frequencies are used.
|
||||
|
||||
config STM32H5_ADC1_DMA_BATCH
|
||||
int "ADC1 DMA number of conversions"
|
||||
depends on STM32H5_ADC1 && STM32H5_ADC1_DMA
|
||||
default 1
|
||||
---help---
|
||||
This option allows you to select the number of regular group conversions
|
||||
that will trigger a DMA callback transerring data to the upper-half driver.
|
||||
By default, this value is 1, which means that data is transferred after
|
||||
each group conversion.
|
||||
|
||||
config STM32H5_ADC1_DMA_CFG
|
||||
bool "ADC1 DMA configuration"
|
||||
depends on STM32H5_ADC1 && STM32H5_ADC1_DMA
|
||||
default n
|
||||
---help---
|
||||
0 - ADC1 DMA in One Shot Mode, 1 - ADC1 DMA in Circular Mode
|
||||
|
||||
config STM32H5_ADC2_DMA
|
||||
bool "ADC2 DMA Enable"
|
||||
depends on STM32H5_ADC2 && STM32H5_DMA
|
||||
default n
|
||||
---help---
|
||||
If DMA is selected, then the ADC may be configured to support DMA
|
||||
transfer, which is necessary if multiple channels are read or if
|
||||
very high trigger frequencies are used.
|
||||
|
||||
config STM32H5_ADC2_DMA_BATCH
|
||||
int "ADC2 DMA number of conversions"
|
||||
depends on STM32H5_ADC2 && STM32H5_ADC2_DMA
|
||||
default 1
|
||||
---help---
|
||||
This option allows you to select the number of regular group conversions
|
||||
that will trigger a DMA callback transerring data to the upper-half driver.
|
||||
By default, this value is 1, which means that data is transferred after
|
||||
each group conversion.
|
||||
|
||||
config STM32H5_ADC2_DMA_CFG
|
||||
int "ADC2 DMA configuration"
|
||||
depends on STM32H5_ADC2_DMA && STM32H5_DMA
|
||||
range 0 1
|
||||
default 0
|
||||
---help---
|
||||
0 - ADC2 DMA in One Shot Mode, 1 - ADC2 DMA in Circular Mode
|
||||
|
||||
endmenu # ADC Configuration
|
||||
|
||||
menu "SPI Configuration"
|
||||
depends on STM32H5_SPI
|
||||
|
||||
|
|
@ -4550,60 +4619,6 @@ endif # STM32H5_SERIALDRIVER
|
|||
|
||||
endmenu # U[S]ART Configuration
|
||||
|
||||
menu "ADC Configuration"
|
||||
depends on STM32H5_ADC
|
||||
|
||||
config STM32H5_ADC_MAX_SAMPLES
|
||||
int "The maximum number of channels that can be sampled"
|
||||
default 16
|
||||
---help---
|
||||
The maximum number of samples which can be handled without
|
||||
overrun depends on various factors. This is the user's
|
||||
responsibility to correctly select this value.
|
||||
Since the interface to update the sampling time is available
|
||||
for all supported devices, the user can change the default
|
||||
values in the board initialization logic and avoid ADC overrun.
|
||||
|
||||
config STM32H5_ADC1_DMA
|
||||
bool "ADC1 DMA (not supported yet)"
|
||||
depends on STM32H5_ADC1 && EXPERIMENTAL
|
||||
default n
|
||||
---help---
|
||||
If DMA is selected, then the ADC may be configured to support
|
||||
DMA transfer, which is necessary if multiple channels are read
|
||||
or if very high trigger frequencies are used.
|
||||
|
||||
config STM32H5_ADC1_DMA_BATCH
|
||||
int "ADC1 DMA number of conversions"
|
||||
depends on STM32H5_ADC1 && STM32H5_ADC1_DMA
|
||||
default 1
|
||||
---help---
|
||||
This option allows you to select the number of regular group conversions
|
||||
that will trigger a DMA callback transerring data to the upper-half driver.
|
||||
By default, this value is 1, which means that data is transferred after
|
||||
each group conversion.
|
||||
|
||||
config STM32H5_ADC2_DMA
|
||||
bool "ADC2 DMA (not supported yet)"
|
||||
depends on STM32H5_ADC2 && EXPERIMENTAL
|
||||
default n
|
||||
---help---
|
||||
If DMA is selected, then the ADC may be configured to support
|
||||
DMA transfer, which is necessary if multiple channels are read
|
||||
or if very high trigger frequencies are used.
|
||||
|
||||
config STM32H5_ADC2_DMA_BATCH
|
||||
int "ADC2 DMA number of conversions"
|
||||
depends on STM32H5_ADC2 && STM32H5_ADC2_DMA
|
||||
default 1
|
||||
---help---
|
||||
This option allows you to select the number of regular group conversions
|
||||
that will trigger a DMA callback transerring data to the upper-half driver.
|
||||
By default, this value is 1, which means that data is transferred after
|
||||
each group conversion.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Ethernet MAC Configuration"
|
||||
depends on STM32H5_ETHMAC
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,10 @@ ifeq ($(CONFIG_STM32H5_ETHMAC),y)
|
|||
CHIP_CSRCS += stm32_ethernet.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_STM32H5_DMA),y)
|
||||
CHIP_CSRCS += stm32_dma.c
|
||||
endif
|
||||
|
||||
# Required chip type specific files
|
||||
|
||||
ifeq ($(CONFIG_STM32H5_STM32H5XXXX),y)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,12 @@
|
|||
#include <nuttx/config.h>
|
||||
#include "chip.h"
|
||||
|
||||
#if defined(CONFIG_STM32H5_STM32H56XXX) || defined(CONFIG_STM32H5_STM32H57XXX)
|
||||
# include "stm32h56x_dmasigmap.h"
|
||||
#else
|
||||
# error "Unsupported STM32 H5 DMA map"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
|
@ -455,6 +461,8 @@
|
|||
#define GPDMA_CXCR_PRIO_SHIFT (22) /* Bits 22-23: Priority level of ch x GPDMA transfer */
|
||||
#define GPDMA_CXCR_PRIO_MASK (0b11 << GPDMA_CXCR_PRIO_SHIFT)
|
||||
|
||||
#define GPDMA_CXCR_ALLINTS (GPDMA_CXCR_TOIE|GPDMA_CXCR_SUSPEI|GPDMA_CXCR_USEIE|GPDMA_CXCR_ULEIE|GPDMA_CXCR_DTEIE|GPDMA_CXCR_HTIE|GPDMA_CXCR_TCIE)
|
||||
|
||||
/* Channel x transfer register 1 */
|
||||
|
||||
#define GPDMA_CXTR1_SDW_LOG2_SHIFT (0)
|
||||
|
|
@ -485,7 +493,7 @@
|
|||
#define GPDMA_CXTR1_DBL_1(l) ((l) - 1 << GPDMA_CXTR1_DBL_1_SHIFT)
|
||||
|
||||
#define GPDMA_CXTR1_DBX (1 << 26) /* Destination byte exchange */
|
||||
#define GPDMA_CXTR1_DHX (1 << 17) /* Destination half-word exchange */
|
||||
#define GPDMA_CXTR1_DHX (1 << 27) /* Destination half-word exchange */
|
||||
#define GPDMA_CXTR1_DAP (1 << 30) /* Destination allocated port */
|
||||
#define GPDMA_CXTR1_DSEC (1 << 31) /* Security attribute of transfer to the destination */
|
||||
|
||||
|
|
|
|||
218
arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h
Normal file
218
arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32H56X_DMASIGMAP_H
|
||||
#define __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32H56X_DMASIGMAP_H
|
||||
|
||||
/* This file is valid for STM32H562/563/573 devices */
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* GPDMA Request Number */
|
||||
|
||||
#define GPDMA_REQ_ADC1 (0)
|
||||
#define GPDMA_REQ_ADC2 (1)
|
||||
#define GPDMA_REQ_DAC1_CH1 (2)
|
||||
#define GPDMA_REQ_DAC1_CH2 (3)
|
||||
#define GPDMA_REQ_TIM6_UPD (4)
|
||||
#define GPDMA_REQ_TIM7_UPD (5)
|
||||
#define GPDMA_REQ_SPI1_RX (6)
|
||||
#define GPDMA_REQ_SPI1_TX (7)
|
||||
#define GPDMA_REQ_SPI2_RX (8)
|
||||
#define GPDMA_REQ_SPI2_TX (9)
|
||||
#define GPDMA_REQ_SPI3_RX (10)
|
||||
#define GPDMA_REQ_SPI3_TX (11)
|
||||
#define GPDMA_REQ_I2C1_RX (12)
|
||||
#define GPDMA_REQ_I2C1_TX (13)
|
||||
/* (14) RESERVED */
|
||||
#define GPDMA_REQ_I2C2_RX (15)
|
||||
#define GPDMA_REQ_I2C2_TX (16)
|
||||
/* (17) RESERVED */
|
||||
#define GPDMA_REQ_I2C3_RX (18)
|
||||
#define GPDMA_REQ_I2C3_TX (19)
|
||||
/* (20) RESERVED */
|
||||
#define GPDMA_REQ_USART1_RX (21)
|
||||
#define GPDMA_REQ_USART1_TX (22)
|
||||
#define GPDMA_REQ_USART2_RX (23)
|
||||
#define GPDMA_REQ_USART2_TX (24)
|
||||
#define GPDMA_REQ_USART3_RX (25)
|
||||
#define GPDMA_REQ_USART3_TX (26)
|
||||
#define GPDMA_REQ_UART4_RX (27)
|
||||
#define GPDMA_REQ_UART4_TX (28)
|
||||
#define GPDMA_REQ_UART5_RX (29)
|
||||
#define GPDMA_REQ_UART5_TX (30)
|
||||
#define GPDMA_REQ_USART6_RX (31)
|
||||
#define GPDMA_REQ_USART6_TX (32)
|
||||
#define GPDMA_REQ_UART7_RX (33)
|
||||
#define GPDMA_REQ_UART7_TX (34)
|
||||
#define GPDMA_REQ_UART8_RX (35)
|
||||
#define GPDMA_REQ_UART8_TX (36)
|
||||
#define GPDMA_REQ_UART9_RX (37)
|
||||
#define GPDMA_REQ_UART9_TX (38)
|
||||
#define GPDMA_REQ_UART10_RX (39)
|
||||
#define GPDMA_REQ_UART10_TX (40)
|
||||
#define GPDMA_REQ_UART11_RX (41)
|
||||
#define GPDMA_REQ_UART11_TX (42)
|
||||
#define GPDMA_REQ_UART12_RX (43)
|
||||
#define GPDMA_REQ_UART12_TX (44)
|
||||
#define GPDMA_REQ_LPUART1_RX (45)
|
||||
#define GPDMA_REQ_LPUART1_TX (46)
|
||||
#define GPDMA_REQ_SPI4_RX (47)
|
||||
#define GPDMA_REQ_SPI4_TX (48)
|
||||
#define GPDMA_REQ_SPI5_RX (49)
|
||||
#define GPDMA_REQ_SPI5_TX (50)
|
||||
#define GPDMA_REQ_SPI6_RX (51)
|
||||
#define GPDMA_REQ_SPI6_TX (52)
|
||||
#define GPDMA_REQ_SAI1_A (53)
|
||||
#define GPDMA_REQ_SAI1_B (54)
|
||||
#define GPDMA_REQ_SAI2_A (55)
|
||||
#define GPDMA_REQ_SAI2_B (56)
|
||||
#define GPDMA_REQ_OSPI1 (57)
|
||||
#define GPDMA_REQ_TIM1_CC1 (58)
|
||||
#define GPDMA_REQ_TIM1_CC2 (59)
|
||||
#define GPDMA_REQ_TIM1_CC3 (60)
|
||||
#define GPDMA_REQ_TIM1_CC4 (61)
|
||||
#define GPDMA_REQ_TIM1_UPD (62)
|
||||
#define GPDMA_REQ_TIM1_TRG (63)
|
||||
#define GPDMA_REQ_TIM1_COM (64)
|
||||
#define GPDMA_REQ_TIM8_CC1 (65)
|
||||
#define GPDMA_REQ_TIM8_CC2 (66)
|
||||
#define GPDMA_REQ_TIM8_CC3 (67)
|
||||
#define GPDMA_REQ_TIM8_CC4 (68)
|
||||
#define GPDMA_REQ_TIM8_UPD (69)
|
||||
#define GPDMA_REQ_TIM8_TIG (70)
|
||||
#define GPDMA_REQ_TIM8_COM (71)
|
||||
#define GPDMA_REQ_TIM2_CC1 (72)
|
||||
#define GPDMA_REQ_TIM2_CC2 (73)
|
||||
#define GPDMA_REQ_TIM2_CC3 (74)
|
||||
#define GPDMA_REQ_TIM2_CC4 (75)
|
||||
#define GPDMA_REQ_TIM2_UPD (76)
|
||||
#define GPDMA_REQ_TIM3_CC1 (77)
|
||||
#define GPDMA_REQ_TIM3_CC2 (78)
|
||||
#define GPDMA_REQ_TIM3_CC3 (79)
|
||||
#define GPDMA_REQ_TIM3_CC4 (80)
|
||||
#define GPDMA_REQ_TIM3_UPD (81)
|
||||
#define GPDMA_REQ_TIM3_TRG (82)
|
||||
#define GPDMA_REQ_TIM4_CC1 (83)
|
||||
#define GPDMA_REQ_TIM4_CC2 (84)
|
||||
#define GPDMA_REQ_TIM4_CC3 (85)
|
||||
#define GPDMA_REQ_TIM4_CC4 (86)
|
||||
#define GPDMA_REQ_TIM4_UPD (87)
|
||||
#define GPDMA_REQ_TIM5_CC1 (88)
|
||||
#define GPDMA_REQ_TIM5_CC2 (89)
|
||||
#define GPDMA_REQ_TIM5_CC3 (90)
|
||||
#define GPDMA_REQ_TIM5_CC4 (91)
|
||||
#define GPDMA_REQ_TIM5_UPD (92)
|
||||
#define GPDMA_REQ_TIM5_TRG (93)
|
||||
#define GPDMA_REQ_TIM15_CC1 (94)
|
||||
#define GPDMA_REQ_TIM15_UPD (95)
|
||||
#define GPDMA_REQ_TIM15_TRG (96)
|
||||
#define GPDMA_REQ_TIM15_COM (97)
|
||||
#define GPDMA_REQ_TIM16_CC1 (98)
|
||||
#define GPDMA_REQ_TIM16_UPD (99)
|
||||
#define GPDMA_REQ_TIM17_CC1 (100)
|
||||
#define GPDMA_REQ_TIM17_UPD (101)
|
||||
#define GPDMA_REQ_LPTIM1_IC1 (102)
|
||||
#define GPDMA_REQ_LPTIM1_IC2 (103)
|
||||
#define GPDMA_REQ_LPTIM1_UE (104)
|
||||
#define GPDMA_REQ_LPTIM2_IC1 (105)
|
||||
#define GPDMA_REQ_LPTIM2_IC2 (106)
|
||||
#define GPDMA_REQ_LPTIM2_UE (107)
|
||||
#define GPDMA_REQ_DCMI_PSSI (108)
|
||||
#define GPDMA_REQ_AES_OUT (109)
|
||||
#define GPDMA_REQ_AES_IN (110)
|
||||
#define GPDMA_REQ_HASH_IN (111)
|
||||
#define GPDMA_REQ_UCPD1_RX (112)
|
||||
#define GPDMA_REQ_UCPD1_TX (113)
|
||||
#define GPDMA_REQ_CORDIC_R (114)
|
||||
#define GPDMA_REQ_CORDIC_W (115)
|
||||
#define GPDMA_REQ_FMAC_R (116)
|
||||
#define GPDMA_REQ_FMAC_W (117)
|
||||
#define GPDMA_REQ_SAES_OUT (118)
|
||||
#define GPDMA_REQ_SAES_IN (119)
|
||||
#define GPDMA_REQ_I3C1_RX (120)
|
||||
#define GPDMA_REQ_I3C1_TX (121)
|
||||
#define GPDMA_REQ_I3C1_TC (122)
|
||||
#define GPDMA_REQ_I3C1_RS (123)
|
||||
#define GPDMA_REQ_I2C4_RX (124)
|
||||
#define GPDMA_REQ_I2C4_TX (125)
|
||||
/* (126) RESERVED */
|
||||
#define GPDMA_REQ_LPTIM3_IC1 (127)
|
||||
#define GPDMA_REQ_LPTIM3_IC2 (128)
|
||||
#define GPDMA_REQ_LPTIM3_UE (129)
|
||||
#define GPDMA_REQ_LPTIM5_IC1 (130)
|
||||
#define GPDMA_REQ_LPTIM5_IC2 (131)
|
||||
#define GPDMA_REQ_LPTIM5_UE (132)
|
||||
#define GPDMA_REQ_LPTIM6_IC1 (133)
|
||||
#define GPDMA_REQ_LPTIM6_IC2 (134)
|
||||
#define GPDMA_REQ_LPTIM6_UE (135)
|
||||
|
||||
/* GPDMA Trigger Number */
|
||||
|
||||
#define GPDMA_TRIG_EXTI0 (0)
|
||||
#define GPDMA_TRIG_EXTI1 (1)
|
||||
#define GPDMA_TRIG_EXTI2 (2)
|
||||
#define GPDMA_TRIG_EXTI3 (3)
|
||||
#define GPDMA_TRIG_EXTI4 (4)
|
||||
#define GPDMA_TRIG_EXTI5 (5)
|
||||
#define GPDMA_TRIG_EXTI6 (6)
|
||||
#define GPDMA_TRIG_EXTI7 (7)
|
||||
#define GPDMA_TRIG_TAMP_TRG1 (8)
|
||||
#define GPDMA_TRIG_TAMP_TRG2 (9)
|
||||
#define GPDMA_TRIG_TAMP_TRG4 (10)
|
||||
#define GPDMA_TRIG_LPTIM1_CH1 (11)
|
||||
#define GPDMA_TRIG_LPTIM1_CH2 (12)
|
||||
#define GPDMA_TRIG_LPTIM2_CH1 (13)
|
||||
#define GPDMA_TRIG_LPTIM2_CH2 (14)
|
||||
#define GPDMA_TRIG_RTC_ALRA_TRG (15)
|
||||
#define GPDMA_TRIG_RTC_ALRB_TRG (16)
|
||||
#define GPDMA_TRIG_RTC_WUT_TRG (17)
|
||||
#define GPDMA_TRIG_GPDMA1_CH0_TC (18)
|
||||
#define GPDMA_TRIG_GPDMA1_CH1_TC (19)
|
||||
#define GPDMA_TRIG_GPDMA1_CH2_TC (20)
|
||||
#define GPDMA_TRIG_GPDMA1_CH3_TC (21)
|
||||
#define GPDMA_TRIG_GPDMA1_CH4_TC (22)
|
||||
#define GPDMA_TRIG_GPDMA1_CH5_TC (23)
|
||||
#define GPDMA_TRIG_GPDMA1_CH6_TC (24)
|
||||
#define GPDMA_TRIG_GPDMA1_CH7_TC (25)
|
||||
#define GPDMA_TRIG_GPDMA2_CH0_TC (26)
|
||||
#define GPDMA_TRIG_GPDMA2_CH1_TC (27)
|
||||
#define GPDMA_TRIG_GPDMA2_CH2_TC (28)
|
||||
#define GPDMA_TRIG_GPDMA2_CH3_TC (29)
|
||||
#define GPDMA_TRIG_GPDMA2_CH4_TC (30)
|
||||
#define GPDMA_TRIG_GPDMA2_CH5_TC (31)
|
||||
#define GPDMA_TRIG_GPDMA2_CH6_TC (32)
|
||||
#define GPDMA_TRIG_GPDMA2_CH7_TC (33)
|
||||
#define GPDMA_TRIG_TIM2_TRGO (34)
|
||||
#define GPDMA_TRIG_TIM15_TRG0 (35)
|
||||
#define GPDMA_TRIG_TIM12_TRGO (36)
|
||||
#define GPDMA_TRIG_LPTIM3_CH1 (37)
|
||||
#define GPDMA_TRIG_LPTIM3_CH2 (38)
|
||||
#define GPDMA_TRIG_LPTIM4_AIT (39)
|
||||
#define GPDMA_TRIG_LPTIM5_CH1 (40)
|
||||
#define GPDMA_TRIG_LPTIM5_CH2 (41)
|
||||
#define GPDMA_TRIG_LPTIM6_CH1 (42)
|
||||
#define GPDMA_TRIG_LPTIM6_CH2 (43)
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32H56X_DMASIGMAP_H */
|
||||
|
|
@ -3,8 +3,6 @@
|
|||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
|
|
@ -49,6 +47,9 @@
|
|||
#include "stm32_adc.h"
|
||||
#include "stm32_tim.h"
|
||||
#include "stm32_rcc.h"
|
||||
#include "stm32_dma.h"
|
||||
|
||||
/* ADC "upper half" support must be enabled */
|
||||
|
||||
#ifdef CONFIG_ADC
|
||||
|
||||
|
|
@ -64,11 +65,6 @@
|
|||
|
||||
/* ADC Channels/DMA *********************************************************/
|
||||
|
||||
#ifdef ADC_HAVE_DMA
|
||||
# error "STM32H5 ADC does not have DMA support."
|
||||
# undef ADC_HAVE_DMA
|
||||
#endif
|
||||
|
||||
#define ADC_SMPR_DEFAULT ADC_SMPR_640p5
|
||||
#define ADC_SMPR1_DEFAULT ((ADC_SMPR_DEFAULT << ADC_SMPR1_SMP0_SHIFT) | \
|
||||
(ADC_SMPR_DEFAULT << ADC_SMPR1_SMP1_SHIFT) | \
|
||||
|
|
@ -105,10 +101,10 @@ struct stm32_dev_s
|
|||
uint8_t cchannels; /* Number of configured channels */
|
||||
uint8_t intf; /* ADC interface number */
|
||||
uint8_t current; /* Current ADC channel being converted */
|
||||
bool hasdma; /* True: This ADC supports DMA */
|
||||
#ifdef ADC_HAVE_DMA
|
||||
uint8_t dmachan; /* DMA channel needed by this ADC */
|
||||
bool hasdma; /* True: This ADC supports DMA */
|
||||
uint16_t dmabatch; /* Number of conversions for DMA batch */
|
||||
bool circular; /* 0 = one-shot, 1 = circular */
|
||||
#endif
|
||||
#ifdef ADC_HAVE_TIMER
|
||||
uint8_t trigger; /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3,
|
||||
|
|
@ -187,6 +183,13 @@ static void adc_timstart(struct stm32_dev_s *priv, bool enable);
|
|||
static int adc_timinit(struct stm32_dev_s *priv);
|
||||
#endif
|
||||
|
||||
#ifdef ADC_HAVE_DMA
|
||||
static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t status,
|
||||
void *arg);
|
||||
static void adc_dmacfg(struct stm32_dev_s *priv,
|
||||
struct stm32_gpdma_cfg_s *cfg);
|
||||
#endif
|
||||
|
||||
/* ADC Interrupt Handler */
|
||||
|
||||
static int adc_interrupt(struct adc_dev_s *dev, uint32_t regval);
|
||||
|
|
@ -245,10 +248,16 @@ static struct stm32_dev_s g_adcpriv1 =
|
|||
.freq = CONFIG_STM32H5_ADC1_SAMPLE_FREQUENCY,
|
||||
#endif
|
||||
#ifdef ADC1_HAVE_DMA
|
||||
.dmachan = ADC1_DMA_CHAN,
|
||||
.hasdma = true,
|
||||
.r_dmabuffer = g_adc1_dmabuffer,
|
||||
.dmabatch = CONFIG_STM32H5_ADC1_DMA_BATCH
|
||||
.dmabatch = CONFIG_STM32H5_ADC1_DMA_BATCH,
|
||||
# ifdef CONFIG_STM32H5_ADC1_DMA_CFG
|
||||
.circular = true,
|
||||
# else
|
||||
.circular = false,
|
||||
# endif
|
||||
#else
|
||||
.hasdma = false,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
@ -262,6 +271,12 @@ static struct adc_dev_s g_adcdev1 =
|
|||
/* ADC2 state */
|
||||
|
||||
#ifdef CONFIG_STM32H5_ADC2
|
||||
|
||||
#ifdef ADC2_HAVE_DMA
|
||||
static uint16_t g_adc2_dmabuffer[CONFIG_STM32H5_ADC_MAX_SAMPLES *
|
||||
CONFIG_STM32H5_ADC2_DMA_BATCH];
|
||||
#endif
|
||||
|
||||
static struct stm32_dev_s g_adcpriv2 =
|
||||
{
|
||||
.irq = STM32_IRQ_ADC2,
|
||||
|
|
@ -279,6 +294,18 @@ static struct stm32_dev_s g_adcpriv2 =
|
|||
.pclck = ADC2_TIMER_PCLK_FREQUENCY,
|
||||
.freq = CONFIG_STM32H5_ADC2_SAMPLE_FREQUENCY,
|
||||
#endif
|
||||
#ifdef ADC2_HAVE_DMA
|
||||
.hasdma = true,
|
||||
.r_dmabuffer = g_adc2_dmabuffer,
|
||||
.dmabatch = CONFIG_STM32H5_ADC2_DMA_BATCH,
|
||||
# ifdef CONFIG_STM32H5_ADC2_DMA_CFG
|
||||
.circular = true,
|
||||
# else
|
||||
.circular = false,
|
||||
# endif
|
||||
#else
|
||||
.hasdma = false,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct adc_dev_s g_adcdev2 =
|
||||
|
|
@ -777,6 +804,104 @@ static void adc_reset(struct adc_dev_s *dev)
|
|||
adc_rccreset(priv, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc_dmaconvcallback
|
||||
*
|
||||
* Description:
|
||||
* Callback for DMA. Called from the DMA transfer complete interrupt after
|
||||
* all channels have been converted and transferred with DMA.
|
||||
*
|
||||
* Input Parameters:
|
||||
*
|
||||
* handle - handle to DMA
|
||||
* status -
|
||||
* arg - adc device
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef ADC_HAVE_DMA
|
||||
static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t status, void *arg)
|
||||
{
|
||||
struct adc_dev_s *dev = (struct adc_dev_s *)arg;
|
||||
struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
|
||||
struct stm32_gpdma_cfg_s dmacfg;
|
||||
int i;
|
||||
|
||||
/* Verify that the upper-half has bound its callback */
|
||||
|
||||
if (priv->cb != NULL)
|
||||
{
|
||||
DEBUGASSERT(priv->cb->au_receive != NULL);
|
||||
|
||||
/* Deliver one sample per configured channel */
|
||||
|
||||
for (i = 0; i < priv->rnchannels * priv->dmabatch; i++)
|
||||
{
|
||||
priv->cb->au_receive(dev,
|
||||
priv->chanlist[priv->current],
|
||||
priv->r_dmabuffer[i]);
|
||||
priv->current++;
|
||||
if (priv->current >= priv->rnchannels)
|
||||
{
|
||||
priv->current = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restart DMA for the next conversion series */
|
||||
|
||||
if (priv->circular == 0)
|
||||
{
|
||||
adc_dmacfg(priv, &dmacfg);
|
||||
stm32_dmasetup(priv->dma, &dmacfg);
|
||||
stm32_dmastart(priv->dma, adc_dmaconvcallback, dev, false);
|
||||
adc_startconv(priv, true);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc_dmacfg
|
||||
*
|
||||
* Description:
|
||||
* Generate the required DMA configuration structure for oneshot mode based
|
||||
* on the ADC configuration.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - ADC instance structure
|
||||
* cfg - DMA configuration structure
|
||||
* circular - 0 = oneshot, 1 = circular
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
****************************************************************************/
|
||||
|
||||
static void adc_dmacfg(struct stm32_dev_s *priv,
|
||||
struct stm32_gpdma_cfg_s *cfg)
|
||||
{
|
||||
const uint32_t sdw_log2 = 1; /* Always 16-bit half-word for ADC_DR */
|
||||
|
||||
cfg->src_addr = priv->base + STM32_ADC_DR_OFFSET;
|
||||
cfg->dest_addr = (uintptr_t)priv->r_dmabuffer;
|
||||
|
||||
cfg->request = (priv->base == STM32_ADC1_BASE)
|
||||
? GPDMA_REQ_ADC1
|
||||
: GPDMA_REQ_ADC2;
|
||||
|
||||
cfg->priority = GPMDACFG_PRIO_LH;
|
||||
|
||||
cfg->mode = priv->circular ? GPDMACFG_MODE_CIRC : 0;
|
||||
|
||||
cfg->ntransfers = priv->cchannels * priv->dmabatch * (1u << sdw_log2);
|
||||
|
||||
cfg->tr1 = (sdw_log2 << GPDMA_CXTR1_SDW_LOG2_SHIFT)
|
||||
| (sdw_log2 << GPDMA_CXTR1_DDW_LOG2_SHIFT)
|
||||
| GPDMA_CXTR1_DINC; /* dest-inc, source fixed */
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc_setup
|
||||
*
|
||||
|
|
@ -795,6 +920,9 @@ static void adc_reset(struct adc_dev_s *dev)
|
|||
static int adc_setup(struct adc_dev_s *dev)
|
||||
{
|
||||
struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
|
||||
#ifdef ADC_HAVE_DMA
|
||||
struct stm32_gpdma_cfg_s dmacfg;
|
||||
#endif
|
||||
int ret;
|
||||
irqstate_t flags;
|
||||
uint32_t clrbits;
|
||||
|
|
@ -842,15 +970,29 @@ static int adc_setup(struct adc_dev_s *dev)
|
|||
#ifdef ADC_HAVE_DMA
|
||||
if (priv->hasdma)
|
||||
{
|
||||
/* Enable One shot DMA */
|
||||
/* Enable One-shot or Circular DMA.
|
||||
* WARNING: This doesn't work in dual-ADC modes. [RM0481] ADC_CFGR
|
||||
* register description (pg. 1122) - "In dual-ADC modes, this bit is
|
||||
* not relevant and replaced by control bit DMACFG of the ADC_CCR
|
||||
* register"
|
||||
*/
|
||||
|
||||
setbits |= ADC_CFGR_DMAEN;
|
||||
|
||||
if (priv->circular)
|
||||
{
|
||||
setbits |= ADC_CFGR_DMACFG;
|
||||
setbits |= ADC_CFGR_CONT;
|
||||
}
|
||||
else
|
||||
{
|
||||
clrbits |= ADC_CFGR_DMACFG;
|
||||
clrbits |= ADC_CFGR_CONT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disable continuous mode */
|
||||
|
||||
#else
|
||||
clrbits |= ADC_CFGR_CONT;
|
||||
#endif
|
||||
|
||||
/* Disable external trigger for regular channels */
|
||||
|
||||
|
|
@ -903,17 +1045,14 @@ static int adc_setup(struct adc_dev_s *dev)
|
|||
stm32_dmafree(priv->dma);
|
||||
}
|
||||
|
||||
priv->dma = stm32_dmachannel(priv->dmachan);
|
||||
priv->dma = stm32_dmachannel(GPDMA_TTYPE_P2M);
|
||||
|
||||
stm32_dmasetup(priv->dma,
|
||||
priv->base + STM32_ADC_DR_OFFSET,
|
||||
(uint32_t)priv->r_dmabuffer,
|
||||
priv->rnchannels * priv->dmabatch,
|
||||
ADC_DMA_CONTROL_WORD);
|
||||
adc_dmacfg(priv, &dmacfg);
|
||||
|
||||
stm32_dmasetup(priv->dma, &dmacfg);
|
||||
|
||||
stm32_dmastart(priv->dma, adc_dmaconvcallback, dev, false);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Set ADEN to wake up the ADC from Power Down. */
|
||||
|
|
@ -949,10 +1088,14 @@ static int adc_setup(struct adc_dev_s *dev)
|
|||
adc_getreg(priv, STM32_ADC_SQR4_OFFSET));
|
||||
ainfo("CCR: 0x%08" PRIx32 "\n", adc_getregm(priv, STM32_ADC_CCR_OFFSET));
|
||||
|
||||
/* Enable the ADC interrupt */
|
||||
if (!priv->hasdma)
|
||||
{
|
||||
/* Enable the ADC interrupt */
|
||||
|
||||
ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq);
|
||||
up_enable_irq(priv->irq);
|
||||
ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq);
|
||||
|
||||
up_enable_irq(priv->irq);
|
||||
}
|
||||
|
||||
priv->initialized = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,52 +43,58 @@
|
|||
/* Timer devices may be used for different purposes. One special purpose is
|
||||
* to control periodic ADC sampling. If CONFIG_STM32H5_TIMn is defined then
|
||||
* CONFIG_STM32H5_TIMn_ADC must also be defined to indicate that timer "n"
|
||||
* is intended to be used for that purpose. Timers 1,2,3,6 and 15 may be
|
||||
* used on STM32H5X3, while STM32H5X6 adds support for timers 4 and 8 as
|
||||
* well.
|
||||
* is intended to be used for that purpose.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_STM32H5_TIM1
|
||||
# undef CONFIG_STM32H5_TIM1_ADC
|
||||
# undef CONFIG_STM32H5_TIM1_ADC1
|
||||
# undef CONFIG_STM32H5_TIM1_ADC2
|
||||
# undef CONFIG_STM32H5_TIM1_ADC3
|
||||
#endif
|
||||
#ifndef CONFIG_STM32H5_TIM2
|
||||
# undef CONFIG_STM32H5_TIM2_ADC
|
||||
# undef CONFIG_STM32H5_TIM2_ADC1
|
||||
# undef CONFIG_STM32H5_TIM2_ADC2
|
||||
# undef CONFIG_STM32H5_TIM2_ADC3
|
||||
#endif
|
||||
#ifndef CONFIG_STM32H5_TIM3
|
||||
# undef CONFIG_STM32H5_TIM3_ADC
|
||||
# undef CONFIG_STM32H5_TIM3_ADC1
|
||||
# undef CONFIG_STM32H5_TIM3_ADC2
|
||||
# undef CONFIG_STM32H5_TIM3_ADC3
|
||||
#endif
|
||||
#ifndef CONFIG_STM32H5_TIM4
|
||||
# undef CONFIG_STM32H5_TIM4_ADC
|
||||
# undef CONFIG_STM32H5_TIM4_ADC1
|
||||
# undef CONFIG_STM32H5_TIM4_ADC2
|
||||
# undef CONFIG_STM32H5_TIM4_ADC3
|
||||
#endif
|
||||
#ifndef CONFIG_STM32H5_TIM6
|
||||
# undef CONFIG_STM32H5_TIM6_ADC
|
||||
# undef CONFIG_STM32H5_TIM6_ADC1
|
||||
# undef CONFIG_STM32H5_TIM6_ADC2
|
||||
# undef CONFIG_STM32H5_TIM6_ADC3
|
||||
#endif
|
||||
#ifndef CONFIG_STM32H5_TIM8
|
||||
# undef CONFIG_STM32H5_TIM8_ADC
|
||||
# undef CONFIG_STM32H5_TIM8_ADC1
|
||||
# undef CONFIG_STM32H5_TIM8_ADC2
|
||||
# undef CONFIG_STM32H5_TIM8_ADC3
|
||||
#endif
|
||||
#ifndef CONFIG_STM32H5_TIM15
|
||||
# undef CONFIG_STM32H5_TIM15_ADC
|
||||
# undef CONFIG_STM32H5_TIM15_ADC1
|
||||
# undef CONFIG_STM32H5_TIM15_ADC2
|
||||
# undef CONFIG_STM32H5_TIM15_ADC3
|
||||
#endif
|
||||
|
||||
/* DMA support */
|
||||
|
||||
#undef ADC_HAVE_DMA
|
||||
#if defined(CONFIG_STM32H5_ADC1_DMA) || defined(CONFIG_STM32H5_ADC2_DMA)
|
||||
# define ADC_HAVE_DMA 1
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_STM32H5_ADC1_DMA)
|
||||
# define ADC1_HAVE_DMA 1
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_STM32H5_ADC2_DMA)
|
||||
# define ADC2_HAVE_DMA 1
|
||||
#endif
|
||||
|
||||
/* Timer configuration: If a timer trigger is specified, then get
|
||||
|
|
@ -213,72 +219,19 @@
|
|||
# undef ADC_HAVE_TIMER
|
||||
#endif
|
||||
|
||||
/* Timer 1 */
|
||||
|
||||
#define ADC1_EXTSEL_T1CC1 ADC_CFGR_EXTSEL_T1CC1
|
||||
#define ADC1_EXTSEL_T1CC2 ADC_CFGR_EXTSEL_T1CC2
|
||||
#define ADC1_EXTSEL_T1CC3 ADC_CFGR_EXTSEL_T1CC3
|
||||
#define ADC1_EXTSEL_T1CC4 ADC_CFGR_EXTSEL_T1CC4
|
||||
#define ADC1_EXTSEL_T1TRGO ADC_CFGR_EXTSEL_T1TRGO
|
||||
#define ADC1_EXTSEL_T1TRGO2 ADC_CFGR_EXTSEL_T1TRGO2
|
||||
#define ADC2_EXTSEL_T1CC1 ADC_CFGR_EXTSEL_T1CC1
|
||||
#define ADC2_EXTSEL_T1CC2 ADC_CFGR_EXTSEL_T1CC2
|
||||
#define ADC2_EXTSEL_T1CC3 ADC_CFGR_EXTSEL_T1CC3
|
||||
#define ADC2_EXTSEL_T1CC4 ADC_CFGR_EXTSEL_T1CC4
|
||||
#define ADC2_EXTSEL_T1TRGO ADC_CFGR_EXTSEL_T1TRGO
|
||||
#define ADC2_EXTSEL_T1TRGO2 ADC_CFGR_EXTSEL_T1TRGO2
|
||||
|
||||
/* Timer 2 */
|
||||
|
||||
#define ADC1_EXTSEL_T2CC2 ADC_CFGR_EXTSEL_T2CC2
|
||||
#define ADC1_EXTSEL_T2TRGO ADC_CFGR_EXTSEL_T2TRGO
|
||||
#define ADC2_EXTSEL_T2CC2 ADC_CFGR_EXTSEL_T2CC2
|
||||
#define ADC2_EXTSEL_T2TRGO ADC_CFGR_EXTSEL_T2TRGO
|
||||
|
||||
/* Timer 3 */
|
||||
|
||||
#define ADC1_EXTSEL_T3CC4 ADC_CFGR_EXTSEL_T3CC4
|
||||
#define ADC1_EXTSEL_T3TRGO ADC_CFGR_EXTSEL_T3TRGO
|
||||
#define ADC2_EXTSEL_T3CC4 ADC_CFGR_EXTSEL_T3CC4
|
||||
#define ADC2_EXTSEL_T3TRGO ADC_CFGR_EXTSEL_T3TRGO
|
||||
|
||||
/* Timer 4 */
|
||||
|
||||
#define ADC1_EXTSEL_T4CC4 ADC_CFGR_EXTSEL_T4CC4
|
||||
#define ADC1_EXTSEL_T4TRGO ADC_CFGR_EXTSEL_T4TRGO
|
||||
#define ADC2_EXTSEL_T4CC4 ADC_CFGR_EXTSEL_T4CC4
|
||||
#define ADC2_EXTSEL_T4TRGO ADC_CFGR_EXTSEL_T4TRGO
|
||||
|
||||
/* Timer 6 */
|
||||
|
||||
#define ADC1_EXTSEL_T6TRGO ADC_CFGR_EXTSEL_T6TRGO
|
||||
#define ADC2_EXTSEL_T6TRGO ADC_CFGR_EXTSEL_T6TRGO
|
||||
|
||||
/* Timer 8 */
|
||||
|
||||
#define ADC1_EXTSEL_T8TRGO ADC_CFGR_EXTSEL_T8TRGO
|
||||
#define ADC1_EXTSEL_T8TRGO2 ADC_CFGR_EXTSEL_T8TRGO2
|
||||
#define ADC2_EXTSEL_T8TRGO ADC_CFGR_EXTSEL_T8TRGO
|
||||
#define ADC2_EXTSEL_T8TRGO2 ADC_CFGR_EXTSEL_T8TRGO2
|
||||
|
||||
/* Timer 15 */
|
||||
|
||||
#define ADC1_EXTSEL_T15TRGO ADC_CFGR_EXTSEL_T15TRGO
|
||||
#define ADC2_EXTSEL_T15TRGO ADC_CFGR_EXTSEL_T15TRGO
|
||||
|
||||
#if defined(CONFIG_STM32H5_TIM1_ADC1)
|
||||
# if CONFIG_STM32H5_ADC1_TIMTRIG == 0
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC1
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC1
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC2
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC2
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC3
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR__EXTSEL_T1CC3
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC4
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC4
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1TRGO
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1TRGO
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1TRGO2
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1TRGO2
|
||||
# else
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM1)"
|
||||
# endif
|
||||
|
|
@ -286,13 +239,13 @@
|
|||
# if CONFIG_STM32H5_ADC1_TIMTRIG == 0
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2CC2
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T2CC2
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2TRGO
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T2TRGO
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
|
||||
# else
|
||||
|
|
@ -306,9 +259,9 @@
|
|||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM3)"
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3CC4
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T3CC4
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3TRGO
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T3TRGO
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM3)"
|
||||
# else
|
||||
|
|
@ -322,9 +275,9 @@
|
|||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM4)"
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4CC4
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T4CC4
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4TRGO
|
||||
# define ADC1_EXTSEL_VALUE ADC_CRFT_EXTSEL_T4TRGO
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM4)"
|
||||
# else
|
||||
|
|
@ -340,7 +293,7 @@
|
|||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM6)"
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T6TRGO
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T6TRGO
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM6)"
|
||||
# else
|
||||
|
|
@ -356,9 +309,9 @@
|
|||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM8)"
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8TRGO
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T8TRGO
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8TRGO2
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T8TRGO2
|
||||
# else
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM8)"
|
||||
# endif
|
||||
|
|
@ -372,7 +325,7 @@
|
|||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM15)"
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
|
||||
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T15TRGO
|
||||
# define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T15TRGO
|
||||
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM15)"
|
||||
# else
|
||||
|
|
@ -382,17 +335,17 @@
|
|||
|
||||
#if defined(CONFIG_STM32H5_TIM1_ADC2)
|
||||
# if CONFIG_STM32H5_ADC2_TIMTRIG == 0
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC1
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC1
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC2
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC2
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC3
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC3
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC4
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC4
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1TRGO
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1TRGO
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1TRGO2
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1TRGO2
|
||||
# else
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM1)"
|
||||
# endif
|
||||
|
|
@ -400,13 +353,13 @@
|
|||
# if CONFIG_STM32H5_ADC2_TIMTRIG == 0
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2CC2
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T2CC2
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2TRGO
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T2TRGO
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
|
||||
# else
|
||||
|
|
@ -420,9 +373,9 @@
|
|||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM3)"
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3CC4
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T3CC4
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3TRGO
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T3TRGO
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM3)"
|
||||
# else
|
||||
|
|
@ -436,9 +389,9 @@
|
|||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM4)"
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4CC4
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T4CC4
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4TRGO
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T4TRGO
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM4)"
|
||||
# else
|
||||
|
|
@ -454,7 +407,7 @@
|
|||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM6)"
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T6TRGO
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T6TRGO
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM6)"
|
||||
# else
|
||||
|
|
@ -470,9 +423,9 @@
|
|||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM8)"
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8TRGO
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T8TRGO
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8TRGO2
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T8TRGO2
|
||||
# else
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM8)"
|
||||
# endif
|
||||
|
|
@ -486,7 +439,7 @@
|
|||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM15)"
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
|
||||
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T15TRGO
|
||||
# define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T15TRGO
|
||||
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
|
||||
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM15)"
|
||||
# else
|
||||
|
|
|
|||
763
arch/arm/src/stm32h5/stm32_dma.c
Normal file
763
arch/arm/src/stm32h5/stm32_dma.c
Normal file
|
|
@ -0,0 +1,763 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/stm32h5/stm32_dma.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/signal.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "sched/sched.h"
|
||||
#include "stm32_dma.h"
|
||||
#include "hardware/stm32_gpdma.h"
|
||||
#include "hardware/stm32_memorymap.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* For GPDMA peripheral, each channel has channel specific addresses that are
|
||||
* at a base offset based on channel. Channel reg references will be based
|
||||
* off this in this file.
|
||||
*/
|
||||
|
||||
#define CH_BASE_OFFSET(ch) (0x80*(ch))
|
||||
#define CH_CXLBAR_OFFSET 0x50
|
||||
#define CH_CXFCR_OFFSET 0x5C
|
||||
#define CH_CXSR_OFFSET 0x60
|
||||
#define CH_CXCR_OFFSET 0x64
|
||||
#define CH_CXTR1_OFFSET 0x90
|
||||
#define CH_CXTR2_OFFSET 0x94
|
||||
#define CH_CXBR1_OFFSET 0x98
|
||||
#define CH_CXSAR_OFFSET 0x9C
|
||||
#define CH_CXDAR_OFFSET 0xA0
|
||||
#define CH_CXTR3_OFFSET 0xA4
|
||||
#define CH_CXBR2_OFFSET 0xA8
|
||||
#define CH_CXLLR_OFFSET 0xCC
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct stm32_gpdma_lli_s
|
||||
{
|
||||
uint32_t tr1; /* GPDMA_CxTR1 value */
|
||||
uint32_t tr2; /* GPDMA_CxTR2 value */
|
||||
uint32_t br1; /* GPDMA_CxBR1 value (block size in bytes) */
|
||||
uint32_t sar; /* GPDMA_CxSAR (source address) */
|
||||
uint32_t dar; /* GPDMA_CxDAR (dest address) */
|
||||
uint32_t llr; /* GPDMA_CxLLR (pointer+update bits) */
|
||||
}
|
||||
__attribute__ ((aligned(32)));
|
||||
|
||||
struct gpdma_ch_s
|
||||
{
|
||||
uint8_t dma_instance; /* GPDMA1 or GPDMA2 */
|
||||
uint8_t channel;
|
||||
uint8_t irq;
|
||||
enum gpdma_ttype_e type;
|
||||
bool free; /* Is this channel free to use. */
|
||||
uint32_t base; /* Channel base address */
|
||||
dma_callback_t callback;
|
||||
void *arg;
|
||||
struct stm32_gpdma_cfg_s cfg; /* Configuration passed at channel setup */
|
||||
struct stm32_gpdma_lli_s lli[2];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint32_t gpdmach_getreg(struct gpdma_ch_s *chan,
|
||||
uint32_t offset);
|
||||
static inline void gpdmach_putreg(struct gpdma_ch_s *chan, uint32_t offset,
|
||||
uint32_t value);
|
||||
static inline void gpdmach_modifyreg32(struct gpdma_ch_s *chan,
|
||||
uint32_t offset, uint32_t clrbits,
|
||||
uint32_t setbits);
|
||||
static void gpdma_ch_abort(struct gpdma_ch_s *chan);
|
||||
static void gpdma_ch_disable(struct gpdma_ch_s *chan);
|
||||
|
||||
static int gpdma_setup(struct gpdma_ch_s *chan,
|
||||
struct stm32_gpdma_cfg_s *cfg);
|
||||
static int gpdma_setup_circular(struct gpdma_ch_s *chan,
|
||||
struct stm32_gpdma_cfg_s *cfg);
|
||||
static int gpdma_dmainterrupt(int irq, void *context, void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_STM32H5_DMA1
|
||||
static struct gpdma_ch_s g_chan[] =
|
||||
{
|
||||
{
|
||||
.dma_instance = 1,
|
||||
.channel = 0,
|
||||
.irq = STM32_IRQ_GPDMA1_CH0,
|
||||
.free = true,
|
||||
.base = STM32_DMA1_BASE + CH_BASE_OFFSET(0)
|
||||
},
|
||||
{
|
||||
.dma_instance = 1,
|
||||
.channel = 1,
|
||||
.irq = STM32_IRQ_GPDMA1_CH1,
|
||||
.free = true,
|
||||
.base = STM32_DMA1_BASE + CH_BASE_OFFSET(1)
|
||||
},
|
||||
{
|
||||
.dma_instance = 1,
|
||||
.channel = 2,
|
||||
.irq = STM32_IRQ_GPDMA1_CH2,
|
||||
.free = true,
|
||||
.base = STM32_DMA1_BASE + CH_BASE_OFFSET(2)
|
||||
},
|
||||
{
|
||||
.dma_instance = 1,
|
||||
.channel = 3,
|
||||
.irq = STM32_IRQ_GPDMA1_CH3,
|
||||
.free = true,
|
||||
.base = STM32_DMA1_BASE + CH_BASE_OFFSET(3)
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_STM32H5_DMA2
|
||||
{
|
||||
.dma_instance = 2,
|
||||
.channel = 0,
|
||||
.irq = STM32_IRQ_GPDMA2_CH0,
|
||||
.free = true,
|
||||
.base = STM32_DMA2_BASE + CH_BASE_OFFSET(0)
|
||||
},
|
||||
{
|
||||
.dma_instance = 2,
|
||||
.channel = 1,
|
||||
.irq = STM32_IRQ_GPDMA2_CH1,
|
||||
.free = true,
|
||||
.base = STM32_DMA2_BASE + CH_BASE_OFFSET(1)
|
||||
},
|
||||
{
|
||||
.dma_instance = 2,
|
||||
.channel = 2,
|
||||
.irq = STM32_IRQ_GPDMA2_CH2,
|
||||
.free = true,
|
||||
.base = STM32_DMA2_BASE + CH_BASE_OFFSET(2)
|
||||
},
|
||||
{
|
||||
.dma_instance = 2,
|
||||
.channel = 3,
|
||||
.irq = STM32_IRQ_GPDMA2_CH3,
|
||||
.free = true,
|
||||
.base = STM32_DMA2_BASE + CH_BASE_OFFSET(3)
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static uint32_t circ_addr_1;
|
||||
|
||||
static uint32_t circ_addr_1;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint32_t gpdmach_getreg(struct gpdma_ch_s *chan,
|
||||
uint32_t offset)
|
||||
{
|
||||
return getreg32(chan->base + offset);
|
||||
}
|
||||
|
||||
static inline void gpdmach_putreg(struct gpdma_ch_s *chan, uint32_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
putreg32(value, chan->base + offset);
|
||||
}
|
||||
|
||||
static inline void gpdmach_modifyreg32(struct gpdma_ch_s *chan,
|
||||
uint32_t offset, uint32_t clrbits,
|
||||
uint32_t setbits)
|
||||
{
|
||||
modifyreg32(chan->base + offset, clrbits, setbits);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gpdma_dmainterrupt
|
||||
*
|
||||
* Description:
|
||||
* DMA interrupt handler.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int gpdma_dmainterrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct gpdma_ch_s *chan = NULL;
|
||||
uint32_t status;
|
||||
|
||||
/* Get the channel that generated the interrupt */
|
||||
|
||||
if (irq >= STM32_IRQ_GPDMA1_CH0 && irq <= STM32_IRQ_GPDMA1_CH7)
|
||||
{
|
||||
chan = &g_chan[irq - STM32_IRQ_GPDMA1_CH0];
|
||||
}
|
||||
else if (irq >= STM32_IRQ_GPDMA2_CH0 && irq <= STM32_IRQ_GPDMA2_CH7)
|
||||
{
|
||||
chan = &g_chan[irq - STM32_IRQ_GPDMA2_CH0 + 4];
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGPANIC();
|
||||
}
|
||||
|
||||
/* Get the interrupt status for this channel */
|
||||
|
||||
status = (gpdmach_getreg(chan, CH_CXSR_OFFSET) >> 8) & 0x7f;
|
||||
|
||||
/* Clear the fetched channel interrupts by setting bits in the flag
|
||||
* clear register
|
||||
*/
|
||||
|
||||
gpdmach_putreg(chan, CH_CXFCR_OFFSET, ~0);
|
||||
|
||||
/* Invoke the callback */
|
||||
|
||||
if (chan->callback)
|
||||
{
|
||||
chan->callback(chan, (uint8_t)status, chan->arg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gpdma_ch_abort
|
||||
*
|
||||
* Description:
|
||||
* For the given channel, suspend and abort any ongoing channel transfers.
|
||||
* Returns after the abort has complete and taken effect.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void gpdma_ch_abort(struct gpdma_ch_s *chan)
|
||||
{
|
||||
if ((gpdmach_getreg(chan, CH_CXCR_OFFSET) & GPDMA_CXCR_EN) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* 1. Software writes 1 to the GPDMA_CxCR.SUSP bit */
|
||||
|
||||
gpdmach_putreg(chan, CH_CXCR_OFFSET, GPDMA_CXCR_SUSP);
|
||||
|
||||
/* 2. Polls suspend flag GPDMA_CxSR.SUSPF until SUSPF = 1, or waits for an
|
||||
* interrupt previously enabled by writing 1 to GPDMA_CxCR.SUSPIE.
|
||||
*/
|
||||
|
||||
while ((gpdmach_getreg(chan, CH_CXSR_OFFSET) & GPDMA_CXSR_SUSPF) == 0)
|
||||
{
|
||||
}
|
||||
|
||||
/* 3. Reset chan by writing 1 to GPDMA_CxCR.RESET */
|
||||
|
||||
gpdmach_putreg(chan, CH_CXCR_OFFSET, GPDMA_CXCR_RESET);
|
||||
|
||||
/* 4. Wait for GPDMA_CxCR.EN and GPDMA_CxCR.SUSP bits to be reset */
|
||||
|
||||
while ((gpdmach_getreg(chan, CH_CXCR_OFFSET) &
|
||||
(GPDMA_CXCR_EN | GPDMA_CXCR_SUSP)) != 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gpdma_ch_disable
|
||||
*
|
||||
* Description:
|
||||
* Disable the DMA channel.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void gpdma_ch_disable(struct gpdma_ch_s *chan)
|
||||
{
|
||||
DEBUGASSERT(chan != NULL);
|
||||
|
||||
gpdma_ch_abort(chan);
|
||||
|
||||
/* Disable and clear all interrupts. */
|
||||
|
||||
gpdmach_modifyreg32(chan, CH_CXCR_OFFSET, GPDMA_CXCR_ALLINTS, 0);
|
||||
gpdmach_modifyreg32(chan, CH_CXFCR_OFFSET, 0, ~0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gpdma_setup
|
||||
*
|
||||
* Assumptions:
|
||||
* - EN bit not set. Channel must have been aborted before this is called.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int gpdma_setup(struct gpdma_ch_s *chan,
|
||||
struct stm32_gpdma_cfg_s *cfg)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* Make sure not to use linked list mode. */
|
||||
|
||||
gpdmach_modifyreg32(chan, CH_CXLLR_OFFSET, ~0, 0);
|
||||
gpdmach_putreg(chan, CH_CXLBAR_OFFSET, 0);
|
||||
|
||||
/* Set source and destination addresses. */
|
||||
|
||||
gpdmach_putreg(chan, CH_CXSAR_OFFSET, cfg->src_addr);
|
||||
gpdmach_putreg(chan, CH_CXDAR_OFFSET, cfg->dest_addr);
|
||||
|
||||
/* Set the channel priority according to configuration. */
|
||||
|
||||
gpdmach_modifyreg32(chan, CH_CXCR_OFFSET, GPDMA_CXCR_PRIO_MASK,
|
||||
cfg->priority << GPDMA_CXCR_PRIO_SHIFT);
|
||||
|
||||
/* Set channels TR1 register based on configuration provided. */
|
||||
|
||||
gpdmach_putreg(chan, CH_CXTR1_OFFSET, cfg->tr1);
|
||||
|
||||
/* Assemble the required config for TR2 */
|
||||
|
||||
reg = (uint32_t)cfg->request &
|
||||
(GPDMA_CXTR2_REQSEL_MASK | GPDMA_CXTR2_DREQ | GPDMA_CXTR2_SWREQ);
|
||||
gpdmach_putreg(chan, CH_CXTR2_OFFSET, reg);
|
||||
|
||||
/* Calculate block number of data bytes to transfer, update BR1 */
|
||||
|
||||
reg = cfg->ntransfers;
|
||||
|
||||
if (cfg->mode & GPDMACFG_MODE_CIRC)
|
||||
{
|
||||
/* This only targets peripheral to memory, with memory increment */
|
||||
|
||||
circ_addr_1 = cfg->dest_addr;
|
||||
gpdmach_putreg(chan, CH_CXLBAR_OFFSET,
|
||||
(uint32_t)&circ_addr_1 & (0xffff << 16));
|
||||
|
||||
reg = GPDMA_CXLLR_UDA | ((uint32_t)&circ_addr_1 & GPDMA_CXLLR_LA_MASK);
|
||||
gpdmach_putreg(chan, CH_CXLLR_OFFSET, reg);
|
||||
}
|
||||
|
||||
gpdmach_putreg(chan, CH_CXBR1_OFFSET, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gpdma_setup_circular
|
||||
*
|
||||
* Description:
|
||||
* Circular DMA requires linked list items (LLI) to setup properly. This
|
||||
* function handles LLI allocation and handling necessary to implement
|
||||
* circular DMA.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int gpdma_setup_circular(struct gpdma_ch_s *chan,
|
||||
struct stm32_gpdma_cfg_s *cfg)
|
||||
{
|
||||
struct stm32_gpdma_lli_s *lli = chan->lli;
|
||||
|
||||
lli[0].tr1 = cfg->tr1;
|
||||
lli[0].tr2 = (2U << GPDMA_CXTR2_TCEM_SHIFT)
|
||||
| (cfg->request & GPDMA_CXTR2_REQSEL_MASK);
|
||||
lli[0].br1 = cfg->ntransfers;
|
||||
lli[0].sar = cfg->src_addr;
|
||||
lli[0].dar = cfg->dest_addr;
|
||||
lli[0].llr = (GPDMA_CXLLR_UT1 /* reload TR1 */
|
||||
| GPDMA_CXLLR_UT2 /* reload TR2 */
|
||||
| GPDMA_CXLLR_UB1 /* reload BR1 */
|
||||
| GPDMA_CXLLR_USA /* reload SAR */
|
||||
| GPDMA_CXLLR_UDA /* reload DAR */
|
||||
| GPDMA_CXLLR_ULL) /* reload LLR */
|
||||
| (((uint32_t)&lli[1]) & GPDMA_CXLLR_LA_MASK);
|
||||
|
||||
lli[1].tr1 = lli[0].tr1;
|
||||
lli[1].tr2 = lli[0].tr2;
|
||||
lli[1].br1 = lli[0].br1;
|
||||
lli[1].sar = lli[0].sar;
|
||||
lli[1].dar = lli[0].dar;
|
||||
lli[1].llr = (lli[0].llr & ~GPDMA_CXLLR_LA_MASK)
|
||||
| (((uint32_t)&lli[0]) & GPDMA_CXLLR_LA_MASK);
|
||||
|
||||
gpdmach_putreg(chan, CH_CXSAR_OFFSET, lli[0].sar);
|
||||
gpdmach_putreg(chan, CH_CXDAR_OFFSET, lli[0].dar);
|
||||
gpdmach_putreg(chan, CH_CXTR1_OFFSET, lli[0].tr1);
|
||||
gpdmach_putreg(chan, CH_CXTR2_OFFSET, lli[0].tr2);
|
||||
gpdmach_putreg(chan, CH_CXBR1_OFFSET, lli[0].br1);
|
||||
gpdmach_putreg(chan, CH_CXLBAR_OFFSET, (uint32_t)&lli[0]);
|
||||
gpdmach_putreg(chan, CH_CXLLR_OFFSET, lli[0].llr);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: arm_dma_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the DMA subsystem
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void weak_function arm_dma_initialize(void)
|
||||
{
|
||||
struct gpdma_ch_s *chan;
|
||||
int i;
|
||||
|
||||
/* Initialize each DMA stream */
|
||||
|
||||
for (i = 0; i < sizeof(g_chan) / sizeof(struct gpdma_ch_s); i++)
|
||||
{
|
||||
chan = &g_chan[i];
|
||||
|
||||
/* Attach DMA interrupt vectors */
|
||||
|
||||
irq_attach(chan->irq, gpdma_dmainterrupt, chan);
|
||||
|
||||
/* Disable the DMA channel */
|
||||
|
||||
gpdma_ch_disable(chan);
|
||||
|
||||
/* Enable the IRQ at the NVIC (still disabled at the DMA controller) */
|
||||
|
||||
up_enable_irq(chan->irq);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmachannel
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
DMA_HANDLE stm32_dmachannel(enum gpdma_ttype_e type)
|
||||
{
|
||||
/* On the H5, peripherals can kind of be mapped to any number of different
|
||||
* channels.
|
||||
*
|
||||
* P2M and M2P should be on channels with 8 byte FIFOs. GPDMA1/2 CH[0-3]
|
||||
*
|
||||
* Linear M2M should be on channels with 32 byte FIFOs. GPDMA1/2 CH[4-5]
|
||||
* Some peripherals (e.g. OCTOSPI) can also use these for burst transfers.
|
||||
*
|
||||
* 2D addressed transfers should be on GPDMA1/2 CH[6-7]
|
||||
*
|
||||
* Note: Currently, only P2M and M2P modes are supported and implemented.
|
||||
*/
|
||||
|
||||
DMA_HANDLE handle = NULL;
|
||||
irqstate_t flags;
|
||||
int i;
|
||||
|
||||
/* Currently no support for M2M or 2D addressing modes.
|
||||
* TODO: Remove when support is added!
|
||||
*/
|
||||
|
||||
DEBUGASSERT(type != GPDMA_TTYPE_M2M_LINEAR);
|
||||
DEBUGASSERT(type != GPDMA_TTYPE_2D);
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
if (type == GPDMA_TTYPE_M2P || type == GPDMA_TTYPE_P2M)
|
||||
{
|
||||
for (i = 0; i < (sizeof(g_chan) / sizeof(struct gpdma_ch_s)); i++)
|
||||
{
|
||||
struct gpdma_ch_s *chan = &g_chan[i];
|
||||
|
||||
if (chan->free && chan->channel <= 3)
|
||||
{
|
||||
chan->free = false;
|
||||
chan->type = type;
|
||||
handle = (DMA_HANDLE)chan;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
if (handle == NULL)
|
||||
{
|
||||
/* Failed to allocate channel. */
|
||||
|
||||
dmainfo("No available DMA chan for transfer type=%" PRIu8 "\n",
|
||||
type);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmafree
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel and unmap DMAMUX if required.
|
||||
*
|
||||
* NOTE: The 'handle' used in this argument must NEVER be used again
|
||||
* until stm32_dmachannel() is called again to re-gain access to the
|
||||
* channel.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* - The caller holds the DMA channel.
|
||||
* - There is no DMA in progress
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmafree(DMA_HANDLE handle)
|
||||
{
|
||||
struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
|
||||
|
||||
DEBUGASSERT(handle != NULL);
|
||||
|
||||
chan->free = true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmasetup
|
||||
*
|
||||
* Description:
|
||||
* Configure DMA before using
|
||||
*
|
||||
* Input Parameters:
|
||||
* TODO: Figure out what the input parameter needs to be!!! H7 and F7 have
|
||||
* very different implementations.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmasetup(DMA_HANDLE handle, struct stm32_gpdma_cfg_s *cfg)
|
||||
{
|
||||
struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
|
||||
|
||||
DEBUGASSERT(handle != NULL);
|
||||
|
||||
/* Store the configuration so it can be referenced later by start. */
|
||||
|
||||
chan->cfg = *cfg;
|
||||
|
||||
/* Drivers using DMA should manage channel usage. If a DMA request is not
|
||||
* made on an error or an abort occurs, the driver should stop the DMA. If
|
||||
* it fails to do so, we can not just hang waiting on the HW that will not
|
||||
* change state.
|
||||
*
|
||||
* If at the end of waiting the HW is still not ready, there is a HW
|
||||
* or software usage problem.
|
||||
*/
|
||||
|
||||
gpdma_ch_disable(chan);
|
||||
|
||||
/* if ((gpdmach_getreg(chan, CH_CXCR_OFFSET) & GPDMA_CXCR_EN) != 0)
|
||||
* {
|
||||
* gpdma_ch_abort(chan);
|
||||
* }
|
||||
*/
|
||||
|
||||
/* Clear any unhandled flags from previous transactions */
|
||||
|
||||
/* gpdmach_putreg(chan, CH_CXFCR_OFFSET, 0x7f << 8); */
|
||||
|
||||
if (cfg->mode & GPDMACFG_MODE_CIRC)
|
||||
{
|
||||
gpdma_setup_circular(chan, cfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpdma_setup(chan, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmastart
|
||||
*
|
||||
* Description:
|
||||
* Start the DMA transfer.
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by stm32_dmachannel()
|
||||
* - No DMA in progress
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg,
|
||||
bool half)
|
||||
{
|
||||
struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
|
||||
uint32_t cr;
|
||||
|
||||
DEBUGASSERT(handle != NULL);
|
||||
|
||||
/* Save the callback info. This will be invoked when the DMA completes */
|
||||
|
||||
chan->callback = callback;
|
||||
chan->arg = arg;
|
||||
|
||||
/* Activate channel by setting ENABLE bin in the GPDMA_CXCR register.
|
||||
* As soon as the channel is enabled, it can serve any DMA request from the
|
||||
* peripheral connected to the stream.
|
||||
*/
|
||||
|
||||
cr = gpdmach_getreg(chan, CH_CXCR_OFFSET);
|
||||
cr |= GPDMA_CXCR_EN;
|
||||
|
||||
/* In normal mode, interrupt at either half or full completion. In circular
|
||||
* mode, always interrupt on wrap and optionally interrupt at halfway.
|
||||
*/
|
||||
|
||||
if (chan->cfg.mode & (GPDMACFG_MODE_CIRC))
|
||||
{
|
||||
/* In circular mode, when transfer completes it resets and starts
|
||||
* again. The transfer-complete interrupt is thus always enabled, and
|
||||
* the half-complete interrupt can be used to determine when the buffer
|
||||
* is half-full.
|
||||
*/
|
||||
|
||||
cr |= ((half ? GPDMA_CXCR_HTIE : 0) |
|
||||
GPDMA_CXCR_TCIE |
|
||||
GPDMA_CXCR_DTEIE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Once half of the bytes are transferred, the half-transfer flag
|
||||
* (HTIF) is set and an interrupt is generated if the
|
||||
* Half-Transfer Interrupt Enable bit (HTIE) is set. At the end of the
|
||||
* transfer, the Transfer Complete Flag (TCIF) is set and an interrupt
|
||||
* is generated if the Transfer Complete Interrupt Enable bit (TCIE) is
|
||||
* set.
|
||||
*/
|
||||
|
||||
cr |= (half ? (GPDMA_CXCR_HTIE | GPDMA_CXCR_DTEIE) :
|
||||
(GPDMA_CXCR_TCIE | GPDMA_CXCR_DTEIE));
|
||||
}
|
||||
|
||||
gpdmach_putreg(chan, CH_CXCR_OFFSET, cr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmastop
|
||||
*
|
||||
* Description:
|
||||
* Cancel the DMA. After stm32_dmastop() is called, the DMA channel is
|
||||
* reset and stm32_dmasetup() must be called before stm32_dmastart() can be
|
||||
* called again.
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by stm32_dmachannel()
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmastop(DMA_HANDLE handle)
|
||||
{
|
||||
struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
|
||||
gpdma_ch_disable(chan);
|
||||
|
||||
/* gpdma_ch_abort(chan); */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STM32H5_DMACAPABLE
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmacapable
|
||||
*
|
||||
* Description:
|
||||
* Check if the DMA controller can transfer data to/from given memory
|
||||
* address. This depends on the internal connections in the ARM bus matrix
|
||||
* of the processor. Note that this only applies to memory addresses, it
|
||||
* will return false for any peripheral address.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cfg - DMA transfer configuration
|
||||
*
|
||||
* Returned Value:
|
||||
* True, if transfer is possible.
|
||||
*
|
||||
* NOTE: No implementation yet.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool stm32_dmacapable(DMA_HANDLE handle, stm32_gpdma_cfg_s *cfg)
|
||||
{
|
||||
# warning "stm32_dma_capable not implemented yet"
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_DMA_INFO
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmadump
|
||||
*
|
||||
* Description:
|
||||
* Dump previously sampled DMA register contents
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by stm32_dmachannel()
|
||||
*
|
||||
* NOTE: No implementation yet.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_dmadump(DMA_HANDLE handle, const char *msg)
|
||||
{
|
||||
# warning "stm32_dma_dump not implemented yet!"
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_DMA_INFO
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmasample
|
||||
*
|
||||
* Description:
|
||||
* Sample DMA register contents
|
||||
*
|
||||
* Input Parameters:
|
||||
* TODO: Figure these out!! Not sure if I need the struct like F7 or not?
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by stm32_dmachannel()
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmasample(DMA_HANDLE handle, struct stm32_dmaregs_s *regs)
|
||||
{
|
||||
#warning "stm32_dmasample() not implemented yet!"
|
||||
}
|
||||
#endif
|
||||
|
|
@ -30,12 +30,150 @@
|
|||
#include <nuttx/config.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hardware/stm32_gpdma.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_DMA_INFO
|
||||
# error "CONFIG_DEBUG_DMA_INFO not yet implemented."
|
||||
# undef CONFIG_DEBUG_DMA_INFO
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STM32H5_DMACAPABLE
|
||||
# error "CONFIG_STM32H5_DMACAPABLE not yet implemented."
|
||||
# undef CONFIG_STM32H5_DMACAPABLE
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* These definitions provide the bit encoding of the 'status' parameter
|
||||
* passed to the DMA callback function (see dma_callback_t).
|
||||
*/
|
||||
|
||||
#define DMA_STATUS_TCF (1 << 0) /* Transfer Complete */
|
||||
#define DMA_STATUS_HTF (1 << 1) /* Half Transfer */
|
||||
#define DMA_STATUS_DTEF (1 << 2) /* Data transfer error */
|
||||
#define DMA_STATUS_ULEF (1 << 3) /* Update link transfer error */
|
||||
#define DMA_STATUS_USEF (1 << 4) /* User setting error */
|
||||
#define DMA_STATUS_SUSPF (1 << 5) /* Completed suspension flag */
|
||||
#define DMA_STATUS_TOF (1 << 6) /* Trigger overrun flag */
|
||||
|
||||
#define DMA_STATUS_ERROR (DMA_STATUS_DTEF | DMA_STATUS_ULEF | DMA_STATUS_USEF | DMA_STATUS_TOF)
|
||||
#define DMA_STATUS_SUCCESS (DMA_STATUS_TCF | DMA_STATUS_HTEF)
|
||||
|
||||
/* GPDMA Mode Flags: WARNING!! NOT YET IMPLEMENTED! */
|
||||
|
||||
#define GPDMACFG_MODE_CIRC (1 << 0) /* Enable Circular mode */
|
||||
#define GPDMACFG_MODE_PFC (1 << 1) /* Enable Peripheral flow control */
|
||||
#define GPDMACFG_MODE_DB (1 << 2) /* Enable Double buffer mode */
|
||||
|
||||
/* Channel priority level
|
||||
* Refer to PRIO field in GPDMA_CxCR register description (RM0481)
|
||||
*/
|
||||
|
||||
#define GPDMACFG_PRIO_LL (0) /* Low priority, low weight */
|
||||
#define GPDMACFG_PRIO_LM (1) /* Low priority, mid weight */
|
||||
#define GPMDACFG_PRIO_LH (2) /* Low priority, high weight */
|
||||
#define GPDMACFG_PRIO_H (3) /* High priority */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* GPDMA transfer type enumeration */
|
||||
|
||||
enum gpdma_ttype_e
|
||||
{
|
||||
/* Peripheral-to-memory transfer */
|
||||
|
||||
GPDMA_TTYPE_P2M = 0,
|
||||
|
||||
/* Memory-to-peripheral transfer */
|
||||
|
||||
GPDMA_TTYPE_M2P,
|
||||
|
||||
/* Memory-to-memory transfer, linear addressing */
|
||||
|
||||
GPDMA_TTYPE_M2M_LINEAR,
|
||||
|
||||
/* 2D Addressing needed (NOT IMPLEMENTED YET) */
|
||||
|
||||
GPDMA_TTYPE_2D
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_DMA_INFO
|
||||
struct stm32_gpdma_reg_s
|
||||
{
|
||||
uint32_t cxlbar;
|
||||
uint32_t cxfcr;
|
||||
uint32_t cxsr;
|
||||
uint32_t cxcr;
|
||||
uint32_t cxtr1;
|
||||
uint32_t cxtr2;
|
||||
uint32_t cxbr1;
|
||||
uint32_t cxsar;
|
||||
uint32_t cxdar;
|
||||
uint32_t cxtr3;
|
||||
uint32_t cxbr2;
|
||||
uint32_t cxllr;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct stm32_gpdma_cfg_s
|
||||
{
|
||||
uint32_t src_addr;
|
||||
uint32_t dest_addr;
|
||||
|
||||
/* CxTR1 register for specified channel. */
|
||||
|
||||
uint32_t tr1;
|
||||
|
||||
/* request: Accepts GPDMA_CXTR2_SWREQ, GPDMA_CXTR2_DREQ, and
|
||||
* GPDMA_CXTR2_REQSEL(r) for r given by GPDMA_REQ_x
|
||||
* macros defined in hardware/stm32h56x_dmasigmap.h
|
||||
*/
|
||||
|
||||
uint16_t request;
|
||||
|
||||
/* Number of transfers, in units of the data width
|
||||
* specified in tr1.
|
||||
*/
|
||||
|
||||
uint16_t ntransfers;
|
||||
|
||||
/* Priority level: refer to GPDMACFG_PRIO defines above */
|
||||
|
||||
uint8_t priority;
|
||||
|
||||
/* mode flags, refer to GPDMACFG_MODE_X defines above. */
|
||||
|
||||
uint8_t mode;
|
||||
};
|
||||
|
||||
/* DMA_HANDLE Provides an opaque reference that can be used to represent a
|
||||
* DMA stream.
|
||||
*/
|
||||
|
||||
typedef void *DMA_HANDLE;
|
||||
|
||||
/* Description:
|
||||
* This is the type of the callback that is used to inform the user of the
|
||||
* completion of the DMA. NOTE: The DMA module does *NOT* perform any
|
||||
* cache operations. It is the responsibility of the DMA client to
|
||||
* invalidate DMA buffers after completion of the DMA RX operations.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - Refers to the DMA channel or stream
|
||||
* status - A bit encoded value that provides the completion status. See
|
||||
* the DMA_STATUS_* definitions above.
|
||||
* arg - A user-provided value that was provided when stm32_dmastart()
|
||||
* was called.
|
||||
*/
|
||||
|
||||
typedef void (*dma_callback_t)(DMA_HANDLE handle, uint8_t status, void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
|
@ -55,6 +193,175 @@ extern "C"
|
|||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmachannel
|
||||
*
|
||||
* Description:
|
||||
* Allocate a DMA channel based on provided transfer type. The driver will
|
||||
* return the first available DMA channel compatible with the transfer type
|
||||
*
|
||||
* Input Parameters:
|
||||
* type - Type of DMA transfer required
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, this function returns a non-NULL, void* DMA channel handle.
|
||||
* NULL is returned on any failure. This function can fail only if no DMA
|
||||
* channel is available.
|
||||
*
|
||||
* Assumptions:
|
||||
* - The caller does not hold he DMA channel.
|
||||
* - The caller can wait for the DMA channel to be freed if it is no
|
||||
* available.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
DMA_HANDLE stm32_dmachannel(enum gpdma_ttype_e type);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmafree
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel.
|
||||
*
|
||||
* NOTE: The 'handle' used in this argument must NEVER be used again
|
||||
* until stm32_dmachannel() is called again to re-gain access to the
|
||||
* channel.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* - The caller holds the DMA channel.
|
||||
* - There is no DMA in progress
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmafree(DMA_HANDLE handle);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmasetup
|
||||
*
|
||||
* Description:
|
||||
* Configure DMA before using
|
||||
*
|
||||
* Input Parameters:
|
||||
* TODO: Figure out what the input parameter needs to be!!! H7 and F7 have
|
||||
* very different implementations.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmasetup(DMA_HANDLE handle, struct stm32_gpdma_cfg_s *cfg);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmastart
|
||||
*
|
||||
* Description:
|
||||
* Start the DMA transfer. NOTE: The DMA module does *NOT* perform any
|
||||
* cache operations. It is the responsibility of the DMA client to clean
|
||||
* DMA buffers after starting of the DMA TX operations.
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by stm32_dmachannel()
|
||||
* - No DMA in progress
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg,
|
||||
bool half);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmastop
|
||||
*
|
||||
* Description:
|
||||
* Cancel the DMA. After stm32_dmastop() is called, the DMA channel is
|
||||
* reset and stm32_dmasetup() must be called before stm32_dmastart() can be
|
||||
* called again
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by stm32_dmachannel()
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void stm32_dmastop(DMA_HANDLE handle);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmaresidual
|
||||
*
|
||||
* Description:
|
||||
* Returns the number of bytes remaining to be transferred
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by stm32_dmachannel()
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
size_t stm32_dmaresidual(DMA_HANDLE handle);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmacapable
|
||||
*
|
||||
* Description:
|
||||
* Check if the DMA controller can transfer data to/from given memory
|
||||
* address with the given configuration. This depends on the internal
|
||||
* connections in the ARM bus matrix of the processor. Note that this only
|
||||
* applies to memory addresses, it will return false for any peripheral
|
||||
* address.
|
||||
*
|
||||
* Input Parameters:
|
||||
*
|
||||
* maddr - starting memory address
|
||||
* count - number of unit8 or uint16 or uint32 items as defined by MSIZE
|
||||
* of ccr.
|
||||
* ccr - DMA stream configuration register
|
||||
*
|
||||
* Returned Value:
|
||||
* True, if transfer is possible.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_STM32H5_DMACAPABLE
|
||||
bool stm32_dmacapable(DMA_HANDLE handle, struct stm32_gpdma_cfg_s *cfg);
|
||||
#else
|
||||
# define stm32_dmacapable(handle, cfg) (true)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmasample
|
||||
*
|
||||
* Description:
|
||||
* Sample DMA register contents
|
||||
*
|
||||
* Input Parameters:
|
||||
* TODO: Figure these out!! Not sure if I need the struct like F7 or not?
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by stm32_dmachannel()
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DEBUG_DMA_INFO
|
||||
void stm32_dmasample(DMA_HANDLE handle, struct stm32_dmaregs_s *regs);
|
||||
#else
|
||||
# define stm32_dmasample(handle,regs)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmadump
|
||||
*
|
||||
* Description:
|
||||
* Dump previously sampled DMA register contents
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by stm32_dmachannel()
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DEBUG_DMA_INFO
|
||||
void stm32_dmadump(DMA_HANDLE handle, const char *msg);
|
||||
#else
|
||||
# define stm32_dmadump(handle,msg)
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,13 +89,13 @@ static inline void rcc_enableahb1(void)
|
|||
|
||||
regval = getreg32(STM32_RCC_AHB1ENR);
|
||||
|
||||
#ifdef CONFIG_STM32H5_GPDMA1
|
||||
#ifdef CONFIG_STM32H5_DMA1
|
||||
/* DMA 1 clock enable */
|
||||
|
||||
regval |= RCC_AHB1ENR_GPDMA1EN;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STM32H5_GPDMA2
|
||||
#ifdef CONFIG_STM32H5_DMA2
|
||||
/* DMA 2 clock enable */
|
||||
|
||||
regval |= RCC_AHB1ENR_GPDMA2EN;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue