From 48026bb824fd2d9cfb00ecd040db6ef3a416bae9 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Fri, 22 Jan 2021 21:43:36 -0500 Subject: upload initial port --- .../os/hal/ports/STM32/LLD/ADCv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c | 485 +++ .../os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.h | 415 +++ .../os/hal/ports/STM32/LLD/ADCv1/notes.txt | 16 + .../os/hal/ports/STM32/LLD/ADCv2/driver.mk | 9 + .../os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c | 452 +++ .../os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h | 486 +++ .../os/hal/ports/STM32/LLD/ADCv2/notes.txt | 13 + .../os/hal/ports/STM32/LLD/ADCv3/driver.mk | 9 + .../os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c | 1009 ++++++ .../os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.h | 1026 +++++++ .../os/hal/ports/STM32/LLD/ADCv3/notes.txt | 22 + .../os/hal/ports/STM32/LLD/ADCv4/driver.mk | 9 + .../os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c | 822 +++++ .../os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h | 737 +++++ .../os/hal/ports/STM32/LLD/ADCv4/notes.txt | 13 + .../os/hal/ports/STM32/LLD/ADCv5/driver.mk | 9 + .../os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c | 476 +++ .../os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.h | 401 +++ .../os/hal/ports/STM32/LLD/ADCv5/notes.txt | 16 + .../os/hal/ports/STM32/LLD/BDMAv1/driver.mk | 2 + .../os/hal/ports/STM32/LLD/BDMAv1/notes.txt | 11 + .../os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c | 455 +++ .../os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.h | 441 +++ .../os/hal/ports/STM32/LLD/CANv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c | 1032 +++++++ .../os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h | 471 +++ .../os/hal/ports/STM32/LLD/CRYPv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c | 1901 ++++++++++++ .../os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h | 618 ++++ .../os/hal/ports/STM32/LLD/DACv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c | 769 +++++ .../os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c.bak | 735 +++++ .../os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h | 662 ++++ .../os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h.bak | 662 ++++ .../os/hal/ports/STM32/LLD/DMAv1/driver.mk | 2 + .../os/hal/ports/STM32/LLD/DMAv1/notes.txt | 26 + .../os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c | 816 +++++ .../os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h | 554 ++++ .../hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch23.inc | 78 + .../ports/STM32/LLD/DMAv1/stm32_dma1_ch4567.inc | 84 + .../os/hal/ports/STM32/LLD/DMAv2/driver.mk | 2 + .../os/hal/ports/STM32/LLD/DMAv2/notes.txt | 18 + .../os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c | 675 +++++ .../os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h | 682 +++++ .../os/hal/ports/STM32/LLD/EXTIv1/driver.mk | 2 + .../os/hal/ports/STM32/LLD/EXTIv1/notes.txt | 14 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c | 216 ++ .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.h | 257 ++ .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0.inc | 95 + .../hal/ports/STM32/LLD/EXTIv1/stm32_exti0_1.inc | 96 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti1.inc | 95 + .../hal/ports/STM32/LLD/EXTIv1/stm32_exti10_15.inc | 101 + .../ports/STM32/LLD/EXTIv1/stm32_exti16-35_38.inc | 130 + .../ports/STM32/LLD/EXTIv1/stm32_exti16-40_41.inc | 119 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16.inc | 100 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti17.inc | 100 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti18.inc | 100 + .../hal/ports/STM32/LLD/EXTIv1/stm32_exti19-21.inc | 104 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19.inc | 100 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2.inc | 95 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20.inc | 100 + .../hal/ports/STM32/LLD/EXTIv1/stm32_exti20_21.inc | 104 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21.inc | 100 + .../ports/STM32/LLD/EXTIv1/stm32_exti21_22-29.inc | 109 + .../hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22.inc | 104 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti22.inc | 100 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti23.inc | 100 + .../hal/ports/STM32/LLD/EXTIv1/stm32_exti2_3.inc | 96 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti3.inc | 95 + .../hal/ports/STM32/LLD/EXTIv1/stm32_exti30_32.inc | 119 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti33.inc | 100 + .../os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4.inc | 95 + .../hal/ports/STM32/LLD/EXTIv1/stm32_exti4_15.inc | 108 + .../hal/ports/STM32/LLD/EXTIv1/stm32_exti5_9.inc | 100 + .../os/hal/ports/STM32/LLD/FDCANv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c | 566 ++++ .../os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h | 470 +++ .../hal/ports/STM32/LLD/FDCANv1/stm32_fdcan1.inc | 106 + .../hal/ports/STM32/LLD/FDCANv1/stm32_fdcan2.inc | 106 + .../hal/ports/STM32/LLD/FDCANv1/stm32_fdcan3.inc | 106 + .../os/hal/ports/STM32/LLD/GPIOv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c | 300 ++ .../os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.h | 459 +++ .../os/hal/ports/STM32/LLD/GPIOv2/driver.mk | 9 + .../os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c | 271 ++ .../os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.h | 514 ++++ .../os/hal/ports/STM32/LLD/GPIOv2/stm32_gpio.h | 111 + .../os/hal/ports/STM32/LLD/GPIOv3/driver.mk | 9 + .../os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c | 249 ++ .../os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.h | 554 ++++ .../os/hal/ports/STM32/LLD/GPIOv3/stm32_gpio.h | 113 + .../os/hal/ports/STM32/LLD/I2Cv1/driver.mk | 21 + .../os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c | 889 ++++++ .../os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h | 513 ++++ .../os/hal/ports/STM32/LLD/I2Cv2/driver.mk | 21 + .../os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c | 1169 +++++++ .../os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.h | 509 ++++ .../os/hal/ports/STM32/LLD/I2Cv3/driver.mk | 21 + .../os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c | 1316 ++++++++ .../os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.h | 603 ++++ .../os/hal/ports/STM32/LLD/MACv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c | 758 +++++ .../os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.h | 359 +++ .../os/hal/ports/STM32/LLD/MDMAv1/driver.mk | 2 + .../os/hal/ports/STM32/LLD/MDMAv1/notes.txt | 11 + .../os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c | 355 +++ .../os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.h | 448 +++ .../os/hal/ports/STM32/LLD/OCTOSPIv1/driver.mk | 9 + .../hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c | 464 +++ .../hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.h | 334 ++ .../os/hal/ports/STM32/LLD/OTGv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c | 1265 ++++++++ .../os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.h | 610 ++++ .../os/hal/ports/STM32/LLD/OTGv1/stm32_otg.h | 927 ++++++ .../os/hal/ports/STM32/LLD/QUADSPIv1/driver.mk | 9 + .../hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c | 375 +++ .../hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.h | 313 ++ .../os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk | 9 + .../hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c | 356 +++ .../hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.h | 279 ++ .../ports/STM32/LLD/QUADSPIv2/stm32_quadspi1.inc | 110 + .../os/hal/ports/STM32/LLD/RNGv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c | 179 ++ .../os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.h | 141 + .../os/hal/ports/STM32/LLD/RNGv1/notes.txt | 10 + .../os/hal/ports/STM32/LLD/RTCv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c | 447 +++ .../os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.h | 152 + .../os/hal/ports/STM32/LLD/RTCv2/driver.mk | 9 + .../os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c | 843 ++++++ .../os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.h | 249 ++ .../os/hal/ports/STM32/LLD/RTCv3/driver.mk | 9 + .../os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c | 717 +++++ .../os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h | 289 ++ .../os/hal/ports/STM32/LLD/SDIOv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c | 876 ++++++ .../os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.h | 353 +++ .../os/hal/ports/STM32/LLD/SDMMCv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c | 981 ++++++ .../os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.h | 400 +++ .../os/hal/ports/STM32/LLD/SDMMCv2/driver.mk | 9 + .../os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c | 865 ++++++ .../os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h | 301 ++ .../hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc1.inc | 110 + .../hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc2.inc | 110 + .../os/hal/ports/STM32/LLD/SPIv1/driver.mk | 13 + .../os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c | 584 ++++ .../os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.h | 371 +++ .../os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c | 679 +++++ .../os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.h | 495 +++ .../os/hal/ports/STM32/LLD/SPIv2/driver.mk | 13 + .../os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c | 572 ++++ .../os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.h | 371 +++ .../os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c | 720 +++++ .../os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.h | 552 ++++ .../os/hal/ports/STM32/LLD/SPIv3/driver.mk | 9 + .../os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c | 1140 +++++++ .../os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.h | 590 ++++ .../os/hal/ports/STM32/LLD/TIMv1/driver.mk | 19 + .../os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c | 1153 +++++++ .../os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.h | 980 ++++++ .../os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c | 1135 +++++++ .../os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.h | 893 ++++++ .../os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c | 1302 ++++++++ .../os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.h | 1034 +++++++ .../os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c | 492 +++ .../os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.h | 701 +++++ .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h | 552 ++++ .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim1.inc | 172 ++ .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim14.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim15.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim16.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim17.inc | 133 + .../ports/STM32/LLD/TIMv1/stm32_tim1_15_16_17.inc | 341 +++ .../ports/STM32/LLD/TIMv1/stm32_tim1_9_10_11.inc | 343 +++ .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim2.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim20.inc | 170 ++ .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim21.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim22.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim3.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim4.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim5.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim6.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim7.inc | 133 + .../os/hal/ports/STM32/LLD/TIMv1/stm32_tim8.inc | 172 ++ .../ports/STM32/LLD/TIMv1/stm32_tim8_12_13_14.inc | 343 +++ .../hal/ports/STM32/LLD/TIMv1/tim_irq_mapping.txt | 14 + .../os/hal/ports/STM32/LLD/USARTv1/driver.mk | 13 + .../hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c | 650 ++++ .../hal/ports/STM32/LLD/USARTv1/hal_serial_lld.h | 362 +++ .../os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c | 1008 ++++++ .../os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.h | 758 +++++ .../os/hal/ports/STM32/LLD/USARTv2/driver.mk | 13 + .../hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c | 913 ++++++ .../hal/ports/STM32/LLD/USARTv2/hal_serial_lld.h | 534 ++++ .../os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c | 1075 +++++++ .../os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h | 842 ++++++ .../hal/ports/STM32/LLD/USARTv2/stm32_lpuart1.inc | 110 + .../os/hal/ports/STM32/LLD/USARTv2/stm32_uart4.inc | 121 + .../os/hal/ports/STM32/LLD/USARTv2/stm32_uart5.inc | 121 + .../os/hal/ports/STM32/LLD/USARTv2/stm32_uart7.inc | 121 + .../os/hal/ports/STM32/LLD/USARTv2/stm32_uart8.inc | 121 + .../hal/ports/STM32/LLD/USARTv2/stm32_usart1.inc | 121 + .../hal/ports/STM32/LLD/USARTv2/stm32_usart2.inc | 121 + .../hal/ports/STM32/LLD/USARTv2/stm32_usart3.inc | 121 + .../ports/STM32/LLD/USARTv2/stm32_usart3_4_lp1.inc | 157 + .../hal/ports/STM32/LLD/USARTv2/stm32_usart4_5.inc | 144 + .../hal/ports/STM32/LLD/USARTv2/stm32_usart6.inc | 121 + .../os/hal/ports/STM32/LLD/USBv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c | 874 ++++++ .../os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.h | 521 ++++ .../os/hal/ports/STM32/LLD/USBv1/stm32_usb.h | 266 ++ .../os/hal/ports/STM32/LLD/xWDGv1/driver.mk | 9 + .../os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c | 144 + .../os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.h | 183 ++ .../os/hal/ports/STM32/STM32H7xx/hal_lld.c | 452 +++ .../os/hal/ports/STM32/STM32H7xx/hal_lld.h | 3199 ++++++++++++++++++++ .../os/hal/ports/STM32/STM32H7xx/platform.mk | 50 + .../os/hal/ports/STM32/STM32H7xx/stm32_dmamux.h | 206 ++ .../os/hal/ports/STM32/STM32H7xx/stm32_isr.c | 198 ++ .../os/hal/ports/STM32/STM32H7xx/stm32_isr.h | 384 +++ .../os/hal/ports/STM32/STM32H7xx/stm32_rcc.h | 1834 +++++++++++ .../os/hal/ports/STM32/STM32H7xx/stm32_registry.h | 778 +++++ ChibiOS_20.3.2/os/hal/ports/STM32/todo.txt | 4 + 225 files changed, 77610 insertions(+) create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c.bak create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h.bak create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch23.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch4567.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0_1.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti1.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti10_15.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-35_38.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-40_41.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti17.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti18.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19-21.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20_21.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22-29.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti22.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti23.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2_3.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti3.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti30_32.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti33.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4_15.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti5_9.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan1.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan2.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan3.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/stm32_gpio.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/stm32_gpio.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/stm32_otg.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/stm32_quadspi1.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/notes.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc1.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc2.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim14.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim15.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim16.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim17.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_15_16_17.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_9_10_11.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim2.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim20.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim21.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim22.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim3.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim4.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim5.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim6.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim7.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8_12_13_14.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/tim_irq_mapping.txt create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_lpuart1.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart4.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart5.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart7.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart8.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart1.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart2.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3_4_lp1.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart4_5.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart6.inc create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/stm32_usb.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/driver.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/platform.mk create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_dmamux.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.c create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_rcc.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_registry.h create mode 100644 ChibiOS_20.3.2/os/hal/ports/STM32/todo.txt (limited to 'ChibiOS_20.3.2/os/hal/ports/STM32') diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/driver.mk new file mode 100644 index 0000000..a3b7649 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c new file mode 100644 index 0000000..a8733f9 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c @@ -0,0 +1,485 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv1/hal_adc_lld.c + * @brief STM32 ADC subsystem low level driver source. + * + * @addtogroup ADC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define ADC1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_CHN) + +/* Headers differences patches.*/ +#if defined(ADC_IER_AWDIE) && !defined(ADC_IER_AWD1IE) +#define ADC_IER_AWD1IE ADC_IER_AWDIE +#endif + +#if defined(ADC_ISR_AWD) && !defined(ADC_ISR_AWD1) +#define ADC_ISR_AWD1 ADC_ISR_AWD +#endif + +#define TR1 TR + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief ADC1 driver identifier.*/ +#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) +ADCDriver ADCD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief ADC voltage regulator enable. + * + * @param[in] adc pointer to the ADC registers block + */ +NOINLINE static void adc_lld_vreg_on(ADC_TypeDef *adc) { + + osalDbgAssert(adc->CR == 0, "invalid register state"); + +#if defined(ADC_CR_ADVREGEN) + adc->CR = ADC_CR_ADVREGEN; + volatile uint32_t loop = (STM32_HCLK >> 20) << 4; + do { + loop--; + } while (loop > 0); +#else +#endif +} + +/** + * @brief Stops an ongoing conversion, if any. + * + * @param[in] adc pointer to the ADC registers block + */ +static void adc_lld_stop_adc(ADC_TypeDef *adc) { + + if (adc->CR & ADC_CR_ADSTART) { + adc->CR |= ADC_CR_ADSTP; + while (adc->CR & ADC_CR_ADSTP) + ; + adc->IER = 0; + } +} + +/** + * @brief ADC DMA service routine. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + /* DMA, this could help only if the DMA tries to access an unmapped + address space or violates alignment rules.*/ + _adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE); + } + else { + /* It is possible that the conversion group has already be reset by the + ADC error handler, in this case this interrupt is spurious.*/ + if (adcp->grpp != NULL) { + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } + else if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) +#if !defined(STM32_ADC1_HANDLER) +#error "STM32_ADC1_HANDLER not defined" +#endif +/** + * @brief ADC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_ADC1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + adc_lld_serve_interrupt(&ADCD1); + +#if defined(STM32_ADC_ADC1_IRQ_HOOK) + STM32_ADC_ADC1_IRQ_HOOK +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ADC driver initialization. + * + * @notapi + */ +void adc_lld_init(void) { + +#if STM32_ADC_USE_ADC1 + /* Driver initialization.*/ + adcObjectInit(&ADCD1); + ADCD1.adc = ADC1; + ADCD1.dmastp = NULL; + ADCD1.dmamode = STM32_DMA_CR_CHSEL(ADC1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + + /* The vector is initialized on driver initialization and never + disabled.*/ + nvicEnableVector(12, STM32_ADC_ADC1_IRQ_PRIORITY); +#endif + + /* Calibration procedure.*/ + rccEnableADC1(true); + + /* CCR setup.*/ +#if STM32_ADC_SUPPORTS_PRESCALER + ADC->CCR = STM32_ADC_PRESC << 18; +#else + ADC->CCR = 0; +#endif + + /* Regulator enabled and stabilized before calibration.*/ + adc_lld_vreg_on(ADC1); + + ADC1->CR |= ADC_CR_ADCAL; + while (ADC1->CR & ADC_CR_ADCAL) + ; + ADC1->CR = 0; + rccDisableADC1(); +} + +/** + * @brief Configures and activates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start(ADCDriver *adcp) { + + /* If in stopped state then enables the ADC and DMA clocks.*/ + if (adcp->state == ADC_STOP) { +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) { + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC1_DMA_STREAM, + STM32_ADC_ADC1_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_rx_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); + rccEnableADC1(true); + + /* DMA setup.*/ + dmaStreamSetPeripheral(adcp->dmastp, &ADC1->DR); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC1); +#endif + + /* Clock settings.*/ + adcp->adc->CFGR2 = STM32_ADC_ADC1_CKMODE; + } +#endif /* STM32_ADC_USE_ADC1 */ + + /* Regulator enabled and stabilized before calibration.*/ + adc_lld_vreg_on(ADC1); + + /* ADC initial setup, starting the analog part here in order to reduce + the latency when starting a conversion.*/ + adcp->adc->CR = ADC_CR_ADEN; + while (!(adcp->adc->ISR & ADC_ISR_ADRDY)) + ; + } +} + +/** + * @brief Deactivates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop(ADCDriver *adcp) { + + /* If in ready state then disables the ADC clock and analog part.*/ + if (adcp->state == ADC_READY) { + + dmaStreamFreeI(adcp->dmastp); + adcp->dmastp = NULL; + + /* Restoring CCR default.*/ +#if STM32_ADC_SUPPORTS_PRESCALER + ADC->CCR = STM32_ADC_PRESC << 18; +#else + ADC->CCR = 0; +#endif + + /* Disabling ADC.*/ + if (adcp->adc->CR & ADC_CR_ADEN) { + adc_lld_stop_adc(adcp->adc); + adcp->adc->CR |= ADC_CR_ADDIS; + while (adcp->adc->CR & ADC_CR_ADDIS) + ; + } + + /* Regulator and anything else off.*/ + adcp->adc->CR = 0; + +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) + rccDisableADC1(); +#endif + } +} + +/** + * @brief Starts an ADC conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start_conversion(ADCDriver *adcp) { + uint32_t mode, cfgr1; + const ADCConversionGroup *grpp = adcp->grpp; + + /* DMA setup.*/ + mode = adcp->dmamode; + cfgr1 = grpp->cfgr1 | ADC_CFGR1_DMAEN; + if (grpp->circular) { + mode |= STM32_DMA_CR_CIRC; + cfgr1 |= ADC_CFGR1_DMACFG; + if (adcp->depth > 1) { + /* If circular buffer depth > 1, then the half transfer interrupt + is enabled in order to allow streaming processing.*/ + mode |= STM32_DMA_CR_HTIE; + } + } + dmaStreamSetMemory0(adcp->dmastp, adcp->samples); + dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * + (uint32_t)adcp->depth); + dmaStreamSetMode(adcp->dmastp, mode); + dmaStreamEnable(adcp->dmastp); + + /* ADC setup, if it is defined a callback for the analog watch dog then it + is enabled.*/ + adcp->adc->ISR = adcp->adc->ISR; + adcp->adc->IER = ADC_IER_OVRIE | ADC_IER_AWD1IE; + adcp->adc->TR1 = grpp->tr; + adcp->adc->SMPR = grpp->smpr; + adcp->adc->CHSELR = grpp->chselr; + + /* ADC configuration and start.*/ + adcp->adc->CFGR1 = cfgr1; +#if STM32_ADC_SUPPORTS_OVERSAMPLING == TRUE + { + uint32_t cfgr2 = adcp->adc->CFGR2 & STM32_ADC_CKMODE_MASK; + adcp->adc->CFGR2 = cfgr2 | grpp->cfgr2; + } +#endif + + /* ADC conversion start.*/ + adcp->adc->CR |= ADC_CR_ADSTART; +} + +/** + * @brief Stops an ongoing conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop_conversion(ADCDriver *adcp) { + + dmaStreamDisable(adcp->dmastp); + adc_lld_stop_adc(adcp->adc); +} + +/** + * @brief ISR code. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_serve_interrupt(ADCDriver *adcp) { + uint32_t isr; + + isr = adcp->adc->ISR; + adcp->adc->ISR = isr; + + /* It could be a spurious interrupt caused by overflows after DMA disabling, + just ignore it in this case.*/ + if (adcp->grpp != NULL) { + /* Note, an overflow may occur after the conversion ended before the driver + is able to stop the ADC, this is why the DMA channel is checked too.*/ + if ((isr & ADC_ISR_OVR) && + (dmaStreamGetTransactionSize(adcp->dmastp) > 0)) { + /* ADC overflow condition, this could happen only if the DMA is unable + to read data fast enough.*/ + _adc_isr_error_code(adcp, ADC_ERR_OVERFLOW); + } + if (isr & ADC_ISR_AWD1) { + /* Analog watchdog error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD); + } + } +} + +/** + * @brief Enables the VREFEN bit. + * @details The VREFEN bit is required in order to sample the VREF channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableVREF(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR |= ADC_CCR_VREFEN; +} + +/** + * @brief Disables the VREFEN bit. + * @details The VREFEN bit is required in order to sample the VREF channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableVREF(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR &= ~ADC_CCR_VREFEN; +} + +/** + * @brief Enables the TSEN bit. + * @details The TSEN bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableTS(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR |= ADC_CCR_TSEN; +} + +/** + * @brief Disables the TSEN bit. + * @details The TSEN bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableTS(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR &= ~ADC_CCR_TSEN; +} + +#if defined(ADC_CCR_VBATEN) || defined(__DOXYGEN__) +/** + * @brief Enables the VBATEN bit. + * @details The VBATEN bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableVBAT(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR |= ADC_CCR_VBATEN; +} + +/** + * @brief Disables the VBATEN bit. + * @details The VBATEN bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableVBAT(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR &= ~ADC_CCR_VBATEN; +} +#endif /* defined(ADC_CCR_VBATEN) */ + +#endif /* HAL_USE_ADC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.h new file mode 100644 index 0000000..cc478d5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.h @@ -0,0 +1,415 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv1/hal_adc_lld.h + * @brief STM32 ADC subsystem low level driver header. + * + * @addtogroup ADC + * @{ + */ + +#ifndef HAL_ADC_LLD_H +#define HAL_ADC_LLD_H + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Sampling rates + * @{ + */ +#if defined(STM32F0XX) || defined(__DOXYGEN__) +#define ADC_SMPR_SMP_1P5 0U /**< @brief 14 cycles conversion time */ +#define ADC_SMPR_SMP_7P5 1U /**< @brief 21 cycles conversion time. */ +#define ADC_SMPR_SMP_13P5 2U /**< @brief 28 cycles conversion time. */ +#define ADC_SMPR_SMP_28P5 3U /**< @brief 41 cycles conversion time. */ +#define ADC_SMPR_SMP_41P5 4U /**< @brief 54 cycles conversion time. */ +#define ADC_SMPR_SMP_55P5 5U /**< @brief 68 cycles conversion time. */ +#define ADC_SMPR_SMP_71P5 6U /**< @brief 84 cycles conversion time. */ +#define ADC_SMPR_SMP_239P5 7U /**< @brief 252 cycles conversion time. */ +#elif defined(STM32L0XX) +#define ADC_SMPR_SMP_1P5 0U /**< @brief 14 cycles conversion time */ +#define ADC_SMPR_SMP_3P5 1U /**< @brief 16 cycles conversion time. */ +#define ADC_SMPR_SMP_7P5 2U /**< @brief 20 cycles conversion time. */ +#define ADC_SMPR_SMP_12P5 3U /**< @brief 25 cycles conversion time. */ +#define ADC_SMPR_SMP_19P5 4U /**< @brief 31 cycles conversion time. */ +#define ADC_SMPR_SMP_39P5 5U /**< @brief 52 cycles conversion time. */ +#define ADC_SMPR_SMP_79P5 6U /**< @brief 92 cycles conversion time. */ +#define ADC_SMPR_SMP_160P5 7U /**< @brief 173 cycles conversion time. */ +#endif +/** @} */ + +/** + * @name CFGR1 register configuration helpers + * @{ + */ +#define ADC_CFGR1_RES_12BIT (0U << 3U) +#define ADC_CFGR1_RES_10BIT (1U << 3U) +#define ADC_CFGR1_RES_8BIT (2U << 3U) +#define ADC_CFGR1_RES_6BIT (3U << 3U) + +#define ADC_CFGR1_EXTSEL_MASK (15U << 6U) +#define ADC_CFGR1_EXTSEL_SRC(n) ((n) << 6U) + +#define ADC_CFGR1_EXTEN_MASK (3U << 10U) +#define ADC_CFGR1_EXTEN_DISABLED (0U << 10U) +#define ADC_CFGR1_EXTEN_RISING (1U << 10U) +#define ADC_CFGR1_EXTEN_FALLING (2U << 10U) +#define ADC_CFGR1_EXTEN_BOTH (3U << 10U) +/** @} */ + +/** + * @name CFGR2 register configuration helpers + * @{ + */ +#define STM32_ADC_CKMODE_MASK (3U << 30U) +#define STM32_ADC_CKMODE_ADCCLK (0U << 30U) +#define STM32_ADC_CKMODE_PCLK_DIV2 (1U << 30U) +#define STM32_ADC_CKMODE_PCLK_DIV4 (2U << 30U) +#define STM32_ADC_CKMODE_PCLK (3U << 30U) + +#if (STM32_ADC_SUPPORTS_OVERSAMPLING == TRUE) || defined(__DOXYGEN__) +#define ADC_CFGR2_OVSR_MASK (7U << 2U) +#define ADC_CFGR2_OVSR_2X (0U << 2U) +#define ADC_CFGR2_OVSR_4X (1U << 2U) +#define ADC_CFGR2_OVSR_8X (2U << 2U) +#define ADC_CFGR2_OVSR_16X (3U << 2U) +#define ADC_CFGR2_OVSR_32X (4U << 2U) +#define ADC_CFGR2_OVSR_64X (5U << 2U) +#define ADC_CFGR2_OVSR_128X (6U << 2U) +#define ADC_CFGR2_OVSR_256X (7U << 2U) + +#define ADC_CFGR2_OVSS_MASK (15 << 5U) +#define ADC_CFGR2_OVSS_SHIFT(n) ((n) << 5U) +#endif +/** @} */ + +/** + * @name Threashold register initializer + * @{ + */ +#define ADC_TR(low, high) (((uint32_t)(high) << 16U) | \ + (uint32_t)(low)) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief ADC1 driver enable switch. + * @details If set to @p TRUE the support for ADC1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC1) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC1 FALSE +#endif + +/** + * @brief ADC1 clock source selection. + */ +#if !defined(STM32_ADC_ADC1_CKMODE) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_CKMODE STM32_ADC_CKMODE_ADCCLK +#endif + +/** + * @brief ADC1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_IRQ_PRIORITY 2 +#endif + +/** + * @brief ADC1 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 2 +#endif + +#if (STM32_ADC_SUPPORTS_PRESCALER == TRUE) || defined(__DOXYGEN__) +/* + * @brief ADC prescaler setting. + * @note This setting has effect only in asynchronous clock mode (the + * default, @p STM32_ADC_CKMODE_ADCCLK). + */ +#if !defined(STM32_ADC_PRESCALER_VALUE) || defined(__DOXYGEN__) +#define STM32_ADC_PRESCALER_VALUE 2 +#endif +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Supported devices checks.*/ +#if !defined(STM32F0XX) && !defined(STM32L0XX) +#error "ADCv1 only supports F0 and L0 STM32 devices" +#endif + +#if defined(STM32L0XX) || defined(__DOXYGEN__) +#define STM32_ADCV1_OVERSAMPLING TRUE +#else +#define STM32_ADCV1_OVERSAMPLING FALSE +#endif + +/* Registry checks.*/ +#if !defined(STM32_HAS_ADC1) +#error "STM32_HAS_ADC1 not defined in registry" +#endif + +#if !defined(STM32_ADC_SUPPORTS_PRESCALER) +#error "STM32_ADC_SUPPORTS_PRESCALER not defined in registry" +#endif + +#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_HANDLER)) +#error "STM32_ADC1_HANDLER not defined in registry" +#endif + +#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_NUMBER)) +#error "STM32_ADC1_NUMBER not defined in registry" +#endif + +#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1 +#error "ADC1 not present in the selected device" +#endif + +/* Units checks.*/ +#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1 +#error "ADC1 not present in the selected device" +#endif + +/* At least one ADC must be assigned.*/ +#if !STM32_ADC_USE_ADC1 +#error "ADC driver activated but no ADC peripheral assigned" +#endif + +/* ADC IRQ priority tests.*/ +#if STM32_ADC_USE_ADC1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC1" +#endif + +/* DMA IRQ priority tests.*/ +#if STM32_ADC_USE_ADC1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC1_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC1 DMA" +#endif + +/* DMA priority tests.*/ +#if STM32_ADC_USE_ADC1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC1" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_ADC_USE_ADC1 && !defined(STM32_ADC_ADC1_DMA_STREAM) +#error "ADC DMA stream not defined" +#endif +#if STM32_DMA_SUPPORTS_DMAMUX + +#else /* !STM32_DMA_SUPPORTS_DMAMUX */ + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_ADC_USE_ADC1 && \ + !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_MSK) +#error "invalid DMA stream associated to ADC1" +#endif + +#endif /* !STM32_DMA_SUPPORTS_DMAMUX */ + +/* ADC clock source checks.*/ +#if STM32_ADC_SUPPORTS_PRESCALER == TRUE +#if STM32_ADC_PRESCALER_VALUE == 2 +#define STM32_ADC_PRESC 1U +#elif STM32_ADC_PRESCALER_VALUE == 4 +#define STM32_ADC_PRESC 2U +#elif STM32_ADC_PRESCALER_VALUE == 6 +#define STM32_ADC_PRESC 3U +#elif STM32_ADC_PRESCALER_VALUE == 8 +#define STM32_ADC_PRESC 4U +#elif STM32_ADC_PRESCALER_VALUE == 10 +#define STM32_ADC_PRESC 5U +#elif STM32_ADC_PRESCALER_VALUE == 12 +#define STM32_ADC_PRESC 6U +#elif STM32_ADC_PRESCALER_VALUE == 16 +#define STM32_ADC_PRESC 7U +#elif STM32_ADC_PRESCALER_VALUE == 32 +#define STM32_ADC_PRESC 8U +#elif STM32_ADC_PRESCALER_VALUE == 64 +#define STM32_ADC_PRESC 9U +#elif STM32_ADC_PRESCALER_VALUE == 128 +#define STM32_ADC_PRESC 10U +#elif STM32_ADC_PRESCALER_VALUE == 256 +#define STM32_ADC_PRESC 11U +#else +#error "Invalid value assigned to STM32_ADC_PRESCALER_VALUE" +#endif +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief ADC sample data type. + */ +typedef uint16_t adcsample_t; + +/** + * @brief Channels number in a conversion group. + */ +typedef uint16_t adc_channels_num_t; + +/** + * @brief Possible ADC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ + ADC_ERR_OVERFLOW = 1, /**< ADC overflow condition. */ + ADC_ERR_AWD = 2 /**< Analog watchdog triggered. */ +} adcerror_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the ADC driver structure. + */ +#define adc_lld_driver_fields \ + /* Pointer to the ADCx registers block.*/ \ + ADC_TypeDef *adc; \ + /* Pointer to associated DMA channel.*/ \ + const stm32_dma_stream_t *dmastp; \ + /* DMA mode bit mask.*/ \ + uint32_t dmamode + +/** + * @brief Low level fields of the ADC configuration structure. + */ +#define adc_lld_config_fields \ + /* Dummy configuration, it is not needed.*/ \ + uint32_t dummy + +/** + * @brief Low level fields of the ADC configuration structure. + */ +#if (STM32_ADC_SUPPORTS_OVERSAMPLING == TRUE) || defined(__DOXYGEN__) +#define adc_lld_configuration_group_fields \ + /* ADC CFGR1 register initialization data. \ + NOTE: The bits DMAEN and DMACFG are enforced internally \ + to the driver, keep them to zero. \ + NOTE: The bits @p ADC_CFGR1_CONT or @p ADC_CFGR1_DISCEN must be \ + specified in continuous more or if the buffer depth is \ + greater than one.*/ \ + uint32_t cfgr1; \ + /* ADC CFGR2 register initialization data. \ + NOTE: CKMODE bits must not be specified in this field and left to \ + zero.*/ \ + uint32_t cfgr2; \ + /* ADC TR register initialization data.*/ \ + uint32_t tr; \ + /* ADC SMPR register initialization data.*/ \ + uint32_t smpr; \ + /* ADC CHSELR register initialization data. \ + NOTE: The number of bits at logic level one in this register must \ + be equal to the number in the @p num_channels field.*/ \ + uint32_t chselr +#else +#define adc_lld_configuration_group_fields \ + /* ADC CFGR1 register initialization data. \ + NOTE: The bits DMAEN and DMACFG are enforced internally \ + to the driver, keep them to zero. \ + NOTE: The bits @p ADC_CFGR1_CONT or @p ADC_CFGR1_DISCEN must be \ + specified in continuous more or if the buffer depth is \ + greater than one.*/ \ + uint32_t cfgr1; \ + /* ADC TR register initialization data.*/ \ + uint32_t tr; \ + /* ADC SMPR register initialization data.*/ \ + uint32_t smpr; \ + /* ADC CHSELR register initialization data. \ + NOTE: The number of bits at logic level one in this register must \ + be equal to the number in the @p num_channels field.*/ \ + uint32_t chselr +#endif + +/** + * @brief Changes the value of the ADC CCR register. + * @details Use this function in order to enable or disable the internal + * analog sources. See the documentation in the STM32 Reference + * Manual. + * @note PRESC bits must not be specified and left to zero. + */ +#define adcSTM32SetCCR(ccr) (ADC->CCR = (ccr)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 && !defined(__DOXYGEN__) +extern ADCDriver ADCD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void adc_lld_init(void); + void adc_lld_start(ADCDriver *adcp); + void adc_lld_stop(ADCDriver *adcp); + void adc_lld_start_conversion(ADCDriver *adcp); + void adc_lld_stop_conversion(ADCDriver *adcp); + void adc_lld_serve_interrupt(ADCDriver *adcp); + void adcSTM32EnableVREF(ADCDriver *adcp); + void adcSTM32DisableVREF(ADCDriver *adcp); + void adcSTM32EnableTS(ADCDriver *adcp); + void adcSTM32DisableTS(ADCDriver *adcp); +#if defined(ADC_CCR_VBATEN) + void adcSTM32EnableVBAT(ADCDriver *adcp); + void adcSTM32DisableVBAT(ADCDriver *adcp); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_ADC */ + +#endif /* HAL_ADC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/notes.txt new file mode 100644 index 0000000..9224117 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/notes.txt @@ -0,0 +1,16 @@ +STM32 ADCv1 driver. + +Driver capability: + +- Supports the STM32 "simple" ADC, the one found on small devices (F0, L0). + +The file registry must export: + +STM32_HAS_ADC1 - ADC1 presence flag. +STM32_ADC_SUPPORTS_PRESCALER - Support of CCR PRESC field. +STM32_ADC_SUPPORTS_OVERSAMPLING - Support of oversampling-related fields. +STM32_ADC1_IRQ_SHARED_WITH_EXTI - TRUE if the IRQ is shared with EXTI. +STM32_ADC1_HANDLER - IRQ vector name. +STM32_ADC1_NUMBER - IRQ vector number. +STM32_ADC1_DMA_MSK - Mask of the compatible DMA channels. +STM32_ADC1_DMA_CHN - Mask of the channels mapping. diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/driver.mk new file mode 100644 index 0000000..9be6513 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv2 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c new file mode 100644 index 0000000..53a5439 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c @@ -0,0 +1,452 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv2/hal_adc_lld.c + * @brief STM32 ADC subsystem low level driver source. + * + * @addtogroup ADC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define ADC1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_CHN) + +#define ADC2_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_ADC_ADC2_DMA_STREAM, STM32_ADC2_DMA_CHN) + +#define ADC3_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_ADC_ADC3_DMA_STREAM, STM32_ADC3_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief ADC1 driver identifier.*/ +#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) +ADCDriver ADCD1; +#endif + +/** @brief ADC2 driver identifier.*/ +#if STM32_ADC_USE_ADC2 || defined(__DOXYGEN__) +ADCDriver ADCD2; +#endif + +/** @brief ADC3 driver identifier.*/ +#if STM32_ADC_USE_ADC3 || defined(__DOXYGEN__) +ADCDriver ADCD3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief ADC DMA service routine. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + /* DMA, this could help only if the DMA tries to access an unmapped + address space or violates alignment rules.*/ + _adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE); + } + else { + /* It is possible that the conversion group has already be reset by the + ADC error handler, in this case this interrupt is spurious.*/ + if (adcp->grpp != NULL) { + + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } + else if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2 || STM32_ADC_USE_ADC3 || \ + defined(__DOXYGEN__) +/** + * @brief ADC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_ADC_HANDLER) { + uint32_t sr; + + OSAL_IRQ_PROLOGUE(); + +#if STM32_ADC_USE_ADC1 + sr = ADC1->SR; + ADC1->SR = 0; + /* Note, an overflow may occur after the conversion ended before the driver + is able to stop the ADC, this is why the DMA channel is checked too.*/ + if ((sr & ADC_SR_OVR) && (dmaStreamGetTransactionSize(ADCD1.dmastp) > 0)) { + /* ADC overflow condition, this could happen only if the DMA is unable + to read data fast enough.*/ + if (ADCD1.grpp != NULL) + _adc_isr_error_code(&ADCD1, ADC_ERR_OVERFLOW); + } + if (sr & ADC_SR_AWD) { + if (ADCD1.grpp != NULL) { + _adc_isr_error_code(&ADCD1, ADC_ERR_WATCHDOG); + } + } +#if defined(STM32_ADC_ADC1_IRQ_HOOK) + STM32_ADC_ADC1_IRQ_HOOK +#endif +#endif /* STM32_ADC_USE_ADC1 */ + +#if STM32_ADC_USE_ADC2 + sr = ADC2->SR; + ADC2->SR = 0; + /* Note, an overflow may occur after the conversion ended before the driver + is able to stop the ADC, this is why the DMA channel is checked too.*/ + if ((sr & ADC_SR_OVR) && (dmaStreamGetTransactionSize(ADCD2.dmastp) > 0)) { + /* ADC overflow condition, this could happen only if the DMA is unable + to read data fast enough.*/ + if (ADCD2.grpp != NULL) + _adc_isr_error_code(&ADCD2, ADC_ERR_OVERFLOW); + } + if (sr & ADC_SR_AWD) { + if (ADCD2.grpp != NULL) { + _adc_isr_error_code(&ADCD2, ADC_ERR_WATCHDOG); + } + } +#if defined(STM32_ADC_ADC2_IRQ_HOOK) + STM32_ADC_ADC2_IRQ_HOOK +#endif +#endif /* STM32_ADC_USE_ADC2 */ + +#if STM32_ADC_USE_ADC3 + sr = ADC3->SR; + ADC3->SR = 0; + /* Note, an overflow may occur after the conversion ended before the driver + is able to stop the ADC, this is why the DMA channel is checked too.*/ + if ((sr & ADC_SR_OVR) && (dmaStreamGetTransactionSize(ADCD3.dmastp) > 0)) { + /* ADC overflow condition, this could happen only if the DMA is unable + to read data fast enough.*/ + if (ADCD3.grpp != NULL) + _adc_isr_error_code(&ADCD3, ADC_ERR_OVERFLOW); + } + if (sr & ADC_SR_AWD) { + if (ADCD3.grpp != NULL) { + _adc_isr_error_code(&ADCD3, ADC_ERR_WATCHDOG); + } + } +#if defined(STM32_ADC_ADC3_IRQ_HOOK) + STM32_ADC_ADC3_IRQ_HOOK +#endif +#endif /* STM32_ADC_USE_ADC3 */ + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ADC driver initialization. + * + * @notapi + */ +void adc_lld_init(void) { + +#if STM32_ADC_USE_ADC1 + /* Driver initialization.*/ + adcObjectInit(&ADCD1); + ADCD1.adc = ADC1; + ADCD1.dmastp = NULL; + ADCD1.dmamode = STM32_DMA_CR_CHSEL(ADC1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; +#endif + +#if STM32_ADC_USE_ADC2 + /* Driver initialization.*/ + adcObjectInit(&ADCD2); + ADCD2.adc = ADC2; + ADCD2.dmastp = NULL; + ADCD2.dmamode = STM32_DMA_CR_CHSEL(ADC2_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_ADC_ADC2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; +#endif + +#if STM32_ADC_USE_ADC3 + /* Driver initialization.*/ + adcObjectInit(&ADCD3); + ADCD3.adc = ADC3; + ADCD3.dmastp = NULL; + ADCD3.dmamode = STM32_DMA_CR_CHSEL(ADC3_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_ADC_ADC3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; +#endif + + /* The shared vector is initialized on driver initialization and never + disabled because sharing.*/ + nvicEnableVector(STM32_ADC_NUMBER, STM32_ADC_IRQ_PRIORITY); +} + +/** + * @brief Configures and activates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start(ADCDriver *adcp) { + + /* If in stopped state then enables the ADC and DMA clocks.*/ + if (adcp->state == ADC_STOP) { +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) { + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC1_DMA_STREAM, + STM32_ADC_ADC1_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_rx_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); + dmaStreamSetPeripheral(adcp->dmastp, &ADC1->DR); + rccEnableADC1(true); + } +#endif /* STM32_ADC_USE_ADC1 */ + +#if STM32_ADC_USE_ADC2 + if (&ADCD2 == adcp) { + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC2_DMA_STREAM, + STM32_ADC_ADC2_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_rx_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); + dmaStreamSetPeripheral(adcp->dmastp, &ADC2->DR); + rccEnableADC2(true); + } +#endif /* STM32_ADC_USE_ADC2 */ + +#if STM32_ADC_USE_ADC3 + if (&ADCD3 == adcp) { + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC3_DMA_STREAM, + STM32_ADC_ADC3_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_rx_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); + dmaStreamSetPeripheral(adcp->dmastp, &ADC3->DR); + rccEnableADC3(true); + } +#endif /* STM32_ADC_USE_ADC3 */ + + /* This is a common register but apparently it requires that at least one + of the ADCs is clocked in order to allow writing, see bug 3575297.*/ + ADC->CCR = (ADC->CCR & (ADC_CCR_TSVREFE | ADC_CCR_VBATE)) | + (STM32_ADC_ADCPRE << 16); + + /* ADC initial setup, starting the analog part here in order to reduce + the latency when starting a conversion.*/ + adcp->adc->CR1 = 0; + adcp->adc->CR2 = 0; + adcp->adc->CR2 = ADC_CR2_ADON; + } +} + +/** + * @brief Deactivates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop(ADCDriver *adcp) { + + /* If in ready state then disables the ADC clock.*/ + if (adcp->state == ADC_READY) { + + dmaStreamFreeI(adcp->dmastp); + adcp->dmastp = NULL; + + adcp->adc->CR1 = 0; + adcp->adc->CR2 = 0; + +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) + rccDisableADC1(); +#endif + +#if STM32_ADC_USE_ADC2 + if (&ADCD2 == adcp) + rccDisableADC2(); +#endif + +#if STM32_ADC_USE_ADC3 + if (&ADCD3 == adcp) + rccDisableADC3(); +#endif + } +} + +/** + * @brief Starts an ADC conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start_conversion(ADCDriver *adcp) { + uint32_t mode; + uint32_t cr2; + const ADCConversionGroup *grpp = adcp->grpp; + + /* DMA setup.*/ + mode = adcp->dmamode; + if (grpp->circular) { + mode |= STM32_DMA_CR_CIRC; + if (adcp->depth > 1) { + /* If circular buffer depth > 1, then the half transfer interrupt + is enabled in order to allow streaming processing.*/ + mode |= STM32_DMA_CR_HTIE; + } + } + dmaStreamSetMemory0(adcp->dmastp, adcp->samples); + dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * + (uint32_t)adcp->depth); + dmaStreamSetMode(adcp->dmastp, mode); + dmaStreamEnable(adcp->dmastp); + + /* ADC setup.*/ + adcp->adc->SR = 0; + adcp->adc->SMPR1 = grpp->smpr1; + adcp->adc->SMPR2 = grpp->smpr2; + adcp->adc->HTR = grpp->htr; + adcp->adc->LTR = grpp->ltr; + adcp->adc->SQR1 = grpp->sqr1 | ADC_SQR1_NUM_CH(grpp->num_channels); + adcp->adc->SQR2 = grpp->sqr2; + adcp->adc->SQR3 = grpp->sqr3; + + /* ADC configuration and start.*/ + adcp->adc->CR1 = grpp->cr1 | ADC_CR1_OVRIE | ADC_CR1_SCAN; + + /* Enforcing the mandatory bits in CR2.*/ + cr2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_ADON; + + /* The start method is different dependign if HW or SW triggered, the + start is performed using the method specified in the CR2 configuration.*/ + if ((cr2 & ADC_CR2_SWSTART) != 0) { + /* Initializing CR2 while keeping ADC_CR2_SWSTART at zero.*/ + adcp->adc->CR2 = (cr2 | ADC_CR2_CONT) & ~ADC_CR2_SWSTART; + + /* Finally enabling ADC_CR2_SWSTART.*/ + adcp->adc->CR2 = (cr2 | ADC_CR2_CONT); + } + else + adcp->adc->CR2 = cr2; +} + +/** + * @brief Stops an ongoing conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop_conversion(ADCDriver *adcp) { + + dmaStreamDisable(adcp->dmastp); + adcp->adc->CR1 = 0; + /* Because ticket #822, preserving injected conversions.*/ + adcp->adc->CR2 &= ~(ADC_CR2_SWSTART); + adcp->adc->CR2 = ADC_CR2_ADON; +} + +/** + * @brief Enables the TSVREFE bit. + * @details The TSVREFE bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + */ +void adcSTM32EnableTSVREFE(void) { + + ADC->CCR |= ADC_CCR_TSVREFE; +} + +/** + * @brief Disables the TSVREFE bit. + * @details The TSVREFE bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + */ +void adcSTM32DisableTSVREFE(void) { + + ADC->CCR &= ~ADC_CCR_TSVREFE; +} + +/** + * @brief Enables the VBATE bit. + * @details The VBATE bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + */ +void adcSTM32EnableVBATE(void) { + + ADC->CCR |= ADC_CCR_VBATE; +} + +/** + * @brief Disables the VBATE bit. + * @details The VBATE bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + */ +void adcSTM32DisableVBATE(void) { + + ADC->CCR &= ~ADC_CCR_VBATE; +} + +#endif /* HAL_USE_ADC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h new file mode 100644 index 0000000..5202f94 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h @@ -0,0 +1,486 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv2/hal_adc_lld.h + * @brief STM32 ADC subsystem low level driver header. + * + * @addtogroup ADC + * @{ + */ + +#ifndef HAL_ADC_LLD_H +#define HAL_ADC_LLD_H + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Absolute Maximum Ratings + * @{ + */ +/** + * @brief Minimum ADC clock frequency. + */ +#define STM32_ADCCLK_MIN 600000 + +/** + * @brief Maximum ADC clock frequency. + */ +#if defined(STM32F4XX) || defined(__DOXYGEN__) +#define STM32_ADCCLK_MAX 36000000 +#else +#define STM32_ADCCLK_MAX 30000000 +#endif +/** @} */ + +/** + * @name Triggers selection + * @{ + */ +#define ADC_CR2_EXTEN_MASK (3U << 28U) +#define ADC_CR2_EXTEN_DISABLED (0U << 28U) +#define ADC_CR2_EXTEN_RISING (1U << 28U) +#define ADC_CR2_EXTEN_FALLING (2U << 28U) +#define ADC_CR2_EXTEN_BOTH (3U << 28U) + +#define ADC_CR2_EXTSEL_MASK (15U << 24U) +#define ADC_CR2_EXTSEL_SRC(n) ((n) << 24U) +/** @} */ + +/** + * @name ADC clock divider settings + * @{ + */ +#define ADC_CCR_ADCPRE_DIV2 0 +#define ADC_CCR_ADCPRE_DIV4 1 +#define ADC_CCR_ADCPRE_DIV6 2 +#define ADC_CCR_ADCPRE_DIV8 3 +/** @} */ + +/** + * @name Available analog channels + * @{ + */ +#define ADC_CHANNEL_IN0 0 /**< @brief External analog input 0. */ +#define ADC_CHANNEL_IN1 1 /**< @brief External analog input 1. */ +#define ADC_CHANNEL_IN2 2 /**< @brief External analog input 2. */ +#define ADC_CHANNEL_IN3 3 /**< @brief External analog input 3. */ +#define ADC_CHANNEL_IN4 4 /**< @brief External analog input 4. */ +#define ADC_CHANNEL_IN5 5 /**< @brief External analog input 5. */ +#define ADC_CHANNEL_IN6 6 /**< @brief External analog input 6. */ +#define ADC_CHANNEL_IN7 7 /**< @brief External analog input 7. */ +#define ADC_CHANNEL_IN8 8 /**< @brief External analog input 8. */ +#define ADC_CHANNEL_IN9 9 /**< @brief External analog input 9. */ +#define ADC_CHANNEL_IN10 10 /**< @brief External analog input 10. */ +#define ADC_CHANNEL_IN11 11 /**< @brief External analog input 11. */ +#define ADC_CHANNEL_IN12 12 /**< @brief External analog input 12. */ +#define ADC_CHANNEL_IN13 13 /**< @brief External analog input 13. */ +#define ADC_CHANNEL_IN14 14 /**< @brief External analog input 14. */ +#define ADC_CHANNEL_IN15 15 /**< @brief External analog input 15. */ +#define ADC_CHANNEL_SENSOR 16 /**< @brief Internal temperature sensor. + @note Available onADC1 only. */ +#define ADC_CHANNEL_VREFINT 17 /**< @brief Internal reference. + @note Available onADC1 only. */ +#define ADC_CHANNEL_VBAT 18 /**< @brief VBAT. + @note Available onADC1 only. */ +/** @} */ + +/** + * @name Sampling rates + * @{ + */ +#define ADC_SAMPLE_3 0 /**< @brief 3 cycles sampling time. */ +#define ADC_SAMPLE_15 1 /**< @brief 15 cycles sampling time. */ +#define ADC_SAMPLE_28 2 /**< @brief 28 cycles sampling time. */ +#define ADC_SAMPLE_56 3 /**< @brief 56 cycles sampling time. */ +#define ADC_SAMPLE_84 4 /**< @brief 84 cycles sampling time. */ +#define ADC_SAMPLE_112 5 /**< @brief 112 cycles sampling time. */ +#define ADC_SAMPLE_144 6 /**< @brief 144 cycles sampling time. */ +#define ADC_SAMPLE_480 7 /**< @brief 480 cycles sampling time. */ +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief ADC common clock divider. + * @note This setting is influenced by the VDDA voltage and other + * external conditions, please refer to the datasheet for more + * info.
+ * See section 5.3.20 "12-bit ADC characteristics". + */ +#if !defined(STM32_ADC_ADCPRE) || defined(__DOXYGEN__) +#define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV2 +#endif + +/** + * @brief ADC1 driver enable switch. + * @details If set to @p TRUE the support for ADC1 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_ADC_USE_ADC1) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC1 FALSE +#endif + +/** + * @brief ADC2 driver enable switch. + * @details If set to @p TRUE the support for ADC2 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_ADC_USE_ADC2) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC2 FALSE +#endif + +/** + * @brief ADC3 driver enable switch. + * @details If set to @p TRUE the support for ADC3 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_ADC_USE_ADC3) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC3 FALSE +#endif + +/** + * @brief DMA stream used for ADC1 operations. + */ +#if !defined(STM32_ADC_ADC1_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) +#endif + +/** + * @brief DMA stream used for ADC2 operations. + */ +#if !defined(STM32_ADC_ADC2_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) +#endif + +/** + * @brief DMA stream used for ADC3 operations. + */ +#if !defined(STM32_ADC_ADC3_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1) +#endif + +/** + * @brief ADC1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC2_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC3 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC interrupt priority level setting. + * @note This setting is shared among ADC1, ADC2 and ADC3 because + * all ADCs share the same vector. + */ +#if !defined(STM32_ADC_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC1 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC2 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC3 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC3_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 5 +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1 +#error "ADC1 not present in the selected device" +#endif + +#if STM32_ADC_USE_ADC2 && !STM32_HAS_ADC2 +#error "ADC2 not present in the selected device" +#endif + +#if STM32_ADC_USE_ADC3 && !STM32_HAS_ADC3 +#error "ADC3 not present in the selected device" +#endif + +#if !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 +#error "ADC driver activated but no ADC peripheral assigned" +#endif + +#if STM32_ADC_USE_ADC1 && \ + !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_MSK) +#error "invalid DMA stream associated to ADC1" +#endif + +#if STM32_ADC_USE_ADC2 && \ + !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC2_DMA_STREAM, STM32_ADC2_DMA_MSK) +#error "invalid DMA stream associated to ADC2" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC3_DMA_STREAM, STM32_ADC3_DMA_MSK) +#error "invalid DMA stream associated to ADC3" +#endif + +/* ADC clock related settings and checks.*/ +#if STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV2 +#define STM32_ADCCLK (STM32_PCLK2 / 2) +#elif STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV4 +#define STM32_ADCCLK (STM32_PCLK2 / 4) +#elif STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV6 +#define STM32_ADCCLK (STM32_PCLK2 / 6) +#elif STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV8 +#define STM32_ADCCLK (STM32_PCLK2 / 8) +#else +#error "invalid STM32_ADC_ADCPRE value specified" +#endif + +#if (STM32_ADCCLK < STM32_ADCCLK_MIN) || (STM32_ADCCLK > STM32_ADCCLK_MAX) +#error "STM32_ADCCLK outside acceptable range (STM32_ADCCLK_MIN...STM32_ADCCLK_MAX)" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief ADC sample data type. + */ +typedef uint16_t adcsample_t; + +/** + * @brief Channels number in a conversion group. + */ +typedef uint16_t adc_channels_num_t; + +/** + * @brief Possible ADC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ + ADC_ERR_OVERFLOW = 1, /**< ADC overflow condition. */ + ADC_ERR_WATCHDOG = 2 /**< ADC watchdog condition. */ +} adcerror_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the ADC driver structure. + */ +#define adc_lld_driver_fields \ + /* Pointer to the ADCx registers block.*/ \ + ADC_TypeDef *adc; \ + /* Pointer to associated DMA channel.*/ \ + const stm32_dma_stream_t *dmastp; \ + /* DMA mode bit mask.*/ \ + uint32_t dmamode + +/** + * @brief Low level fields of the ADC configuration structure. + */ +#define adc_lld_config_fields \ + /* Dummy configuration, it is not needed.*/ \ + uint32_t dummy + +/** + * @brief Low level fields of the ADC configuration structure. + */ +#define adc_lld_configuration_group_fields \ + /* ADC CR1 register initialization data. \ + NOTE: All the required bits must be defined into this field except \ + @p ADC_CR1_SCAN that is enforced inside the driver.*/ \ + uint32_t cr1; \ + /* ADC CR2 register initialization data. \ + NOTE: All the required bits must be defined into this field except \ + @p ADC_CR2_DMA, @p ADC_CR2_CONT and @p ADC_CR2_ADON that are \ + enforced inside the driver.*/ \ + uint32_t cr2; \ + /* ADC SMPR1 register initialization data. \ + NOTE: In this field must be specified the sample times for channels \ + 10...18.*/ \ + uint32_t smpr1; \ + /* ADC SMPR2 register initialization data. \ + NOTE: In this field must be specified the sample times for channels \ + 0...9.*/ \ + uint32_t smpr2; \ + /* ADC watchdog high threshold register. \ + NOTE: This field defines the high threshold of the analog watchdog.*/ \ + uint16_t htr; \ + /* ADC watchdog low threshold register. \ + NOTE: This field defines the low threshold of the analog watchdog.*/ \ + uint16_t ltr; \ + /* ADC SQR1 register initialization data. \ + NOTE: Conversion group sequence 13...16 + sequence length.*/ \ + uint32_t sqr1; \ + /* ADC SQR2 register initialization data. \ + NOTE: Conversion group sequence 7...12.*/ \ + uint32_t sqr2; \ + /* ADC SQR3 register initialization data. \ + NOTE: Conversion group sequence 1...6.*/ \ + uint32_t sqr3 + +/** + * @name Sequences building helper macros + * @{ + */ +/** + * @brief Number of channels in a conversion sequence. + */ +#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20) + +#define ADC_SQR3_SQ1_N(n) ((n) << 0) /**< @brief 1st channel in seq. */ +#define ADC_SQR3_SQ2_N(n) ((n) << 5) /**< @brief 2nd channel in seq. */ +#define ADC_SQR3_SQ3_N(n) ((n) << 10) /**< @brief 3rd channel in seq. */ +#define ADC_SQR3_SQ4_N(n) ((n) << 15) /**< @brief 4th channel in seq. */ +#define ADC_SQR3_SQ5_N(n) ((n) << 20) /**< @brief 5th channel in seq. */ +#define ADC_SQR3_SQ6_N(n) ((n) << 25) /**< @brief 6th channel in seq. */ + +#define ADC_SQR2_SQ7_N(n) ((n) << 0) /**< @brief 7th channel in seq. */ +#define ADC_SQR2_SQ8_N(n) ((n) << 5) /**< @brief 8th channel in seq. */ +#define ADC_SQR2_SQ9_N(n) ((n) << 10) /**< @brief 9th channel in seq. */ +#define ADC_SQR2_SQ10_N(n) ((n) << 15) /**< @brief 10th channel in seq.*/ +#define ADC_SQR2_SQ11_N(n) ((n) << 20) /**< @brief 11th channel in seq.*/ +#define ADC_SQR2_SQ12_N(n) ((n) << 25) /**< @brief 12th channel in seq.*/ + +#define ADC_SQR1_SQ13_N(n) ((n) << 0) /**< @brief 13th channel in seq.*/ +#define ADC_SQR1_SQ14_N(n) ((n) << 5) /**< @brief 14th channel in seq.*/ +#define ADC_SQR1_SQ15_N(n) ((n) << 10) /**< @brief 15th channel in seq.*/ +#define ADC_SQR1_SQ16_N(n) ((n) << 15) /**< @brief 16th channel in seq.*/ +/** @} */ + +/** + * @name Sampling rate settings helper macros + * @{ + */ +#define ADC_SMPR2_SMP_AN0(n) ((n) << 0) /**< @brief AN0 sampling time. */ +#define ADC_SMPR2_SMP_AN1(n) ((n) << 3) /**< @brief AN1 sampling time. */ +#define ADC_SMPR2_SMP_AN2(n) ((n) << 6) /**< @brief AN2 sampling time. */ +#define ADC_SMPR2_SMP_AN3(n) ((n) << 9) /**< @brief AN3 sampling time. */ +#define ADC_SMPR2_SMP_AN4(n) ((n) << 12) /**< @brief AN4 sampling time. */ +#define ADC_SMPR2_SMP_AN5(n) ((n) << 15) /**< @brief AN5 sampling time. */ +#define ADC_SMPR2_SMP_AN6(n) ((n) << 18) /**< @brief AN6 sampling time. */ +#define ADC_SMPR2_SMP_AN7(n) ((n) << 21) /**< @brief AN7 sampling time. */ +#define ADC_SMPR2_SMP_AN8(n) ((n) << 24) /**< @brief AN8 sampling time. */ +#define ADC_SMPR2_SMP_AN9(n) ((n) << 27) /**< @brief AN9 sampling time. */ + +#define ADC_SMPR1_SMP_AN10(n) ((n) << 0) /**< @brief AN10 sampling time. */ +#define ADC_SMPR1_SMP_AN11(n) ((n) << 3) /**< @brief AN11 sampling time. */ +#define ADC_SMPR1_SMP_AN12(n) ((n) << 6) /**< @brief AN12 sampling time. */ +#define ADC_SMPR1_SMP_AN13(n) ((n) << 9) /**< @brief AN13 sampling time. */ +#define ADC_SMPR1_SMP_AN14(n) ((n) << 12) /**< @brief AN14 sampling time. */ +#define ADC_SMPR1_SMP_AN15(n) ((n) << 15) /**< @brief AN15 sampling time. */ +#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18) /**< @brief Temperature Sensor + sampling time. */ +#define ADC_SMPR1_SMP_VREF(n) ((n) << 21) /**< @brief Voltage Reference + sampling time. */ +#define ADC_SMPR1_SMP_VBAT(n) ((n) << 24) /**< @brief VBAT sampling time. */ +/** @} */ + +/** + * @name Threshold settings helper macros + * @{ + */ +/** + * @brief High threshold limitation. + */ +#define ADC_HTR(n) ((n > ADC_HTR_HT) ? ADC_HTR_HT : n) +/** + * @brief Low threshold limitation. + */ +#define ADC_LTR(n) ((n > ADC_LTR_LT) ? ADC_LTR_LT : n) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 && !defined(__DOXYGEN__) +extern ADCDriver ADCD1; +#endif + +#if STM32_ADC_USE_ADC2 && !defined(__DOXYGEN__) +extern ADCDriver ADCD2; +#endif + +#if STM32_ADC_USE_ADC3 && !defined(__DOXYGEN__) +extern ADCDriver ADCD3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void adc_lld_init(void); + void adc_lld_start(ADCDriver *adcp); + void adc_lld_stop(ADCDriver *adcp); + void adc_lld_start_conversion(ADCDriver *adcp); + void adc_lld_stop_conversion(ADCDriver *adcp); + void adcSTM32EnableTSVREFE(void); + void adcSTM32DisableTSVREFE(void); + void adcSTM32EnableVBATE(void); + void adcSTM32DisableVBATE(void); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_ADC */ + +#endif /* HAL_ADC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/notes.txt new file mode 100644 index 0000000..a13d327 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/notes.txt @@ -0,0 +1,13 @@ +STM32 ADCv2 driver. + +Driver capability: + +- Supports the STM32 "advanced" ADC found on F2, F4 and F7 sub-families. + +The file registry must export: + +STM32_HAS_ADCx - ADCx presence flag (1..3). +STM32_ADC_HANDLER - IRQ vector name for ADCs (shared). +STM32_ADC_NUMBER - IRQ vector number for ADCs (shared). +STM32_ADCx_DMA_MSK - Mask of the compatible DMA channels. +STM32_ADCx_DMA_CHN - Mask of the channels mapping. diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/driver.mk new file mode 100644 index 0000000..049021c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv3 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c new file mode 100644 index 0000000..8df21bf --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c @@ -0,0 +1,1009 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv3/hal_adc_lld.c + * @brief STM32 ADC subsystem low level driver source. + * + * @addtogroup ADC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define ADC1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_CHN) + +#define ADC2_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_ADC_ADC2_DMA_STREAM, STM32_ADC2_DMA_CHN) + +#define ADC3_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_ADC_ADC3_DMA_STREAM, STM32_ADC3_DMA_CHN) + +#define ADC4_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_ADC_ADC4_DMA_STREAM, STM32_ADC4_DMA_CHN) + +#if STM32_ADC_DUAL_MODE +#if STM32_ADC_COMPACT_SAMPLES +/* Compact type dual mode.*/ +#define ADC_DMA_SIZE (STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD) +#define ADC_DMA_MDMA ADC_CCR_MDMA_HWORD + +#else /* !STM32_ADC_COMPACT_SAMPLES */ +/* Large type dual mode.*/ +#define ADC_DMA_SIZE (STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD) +#define ADC_DMA_MDMA ADC_CCR_MDMA_WORD +#endif /* !STM32_ADC_COMPACT_SAMPLES */ + +#else /* !STM32_ADC_DUAL_MODE */ +#if STM32_ADC_COMPACT_SAMPLES +/* Compact type single mode.*/ +#define ADC_DMA_SIZE (STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_PSIZE_BYTE) +#define ADC_DMA_MDMA ADC_CCR_MDMA_DISABLED + +#else /* !STM32_ADC_COMPACT_SAMPLES */ +/* Large type single mode.*/ +#define ADC_DMA_SIZE (STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD) +#define ADC_DMA_MDMA ADC_CCR_MDMA_DISABLED +#endif /* !STM32_ADC_COMPACT_SAMPLES */ +#endif /* !STM32_ADC_DUAL_MODE */ + +/* Addressing header differences.*/ +#if !defined(ADC_IER_OVRIE) +#define ADC_IER_OVRIE ADC_IER_OVR +#endif + +#if !defined(ADC_IER_AWD1IE) +#define ADC_IER_AWD1IE ADC_IER_AWD1 +#endif + +#if !defined(ADC_CR_ADVREGEN) +#define ADC_CR_ADVREGEN ADC_CR_ADVREGEN_0 +#endif + +#if !defined(ADC_CR_DEEPPWD) +#define ADC_CR_DEEPPWD ADC_CR_ADVREGEN_1 +#endif + +#if !defined(ADC_ISR_ADRDY) +#define ADC_ISR_ADRDY ADC_ISR_ADRD +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief ADC1 driver identifier.*/ +#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) +ADCDriver ADCD1; +#endif + +/** @brief ADC2 driver identifier.*/ +#if STM32_ADC_USE_ADC2 || defined(__DOXYGEN__) +ADCDriver ADCD2; +#endif + +/** @brief ADC3 driver identifier.*/ +#if STM32_ADC_USE_ADC3 || defined(__DOXYGEN__) +ADCDriver ADCD3; +#endif + +/** @brief ADC4 driver identifier.*/ +#if STM32_ADC_USE_ADC4 || defined(__DOXYGEN__) +ADCDriver ADCD4; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const ADCConfig default_config = { + .difsel = 0 +}; + +static uint32_t clkmask; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Enables the ADC voltage regulator. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_vreg_on(ADCDriver *adcp) { + + adcp->adcm->CR = 0; /* See RM.*/ + adcp->adcm->CR = ADC_CR_ADVREGEN; +#if STM32_ADC_DUAL_MODE + adcp->adcs->CR = ADC_CR_ADVREGEN; +#endif + osalSysPolledDelayX(OSAL_US2RTC(STM32_HCLK, 20)); +} + +/** + * @brief Disables the ADC voltage regulator. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_vreg_off(ADCDriver *adcp) { + + adcp->adcm->CR = 0; /* See RM.*/ + adcp->adcm->CR = ADC_CR_DEEPPWD; +#if STM32_ADC_DUAL_MODE + adcp->adcs->CR = 0; + adcp->adcs->CR = ADC_CR_DEEPPWD; +#endif +} + +/** + * @brief Calibrates and ADC unit. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_calibrate(ADCDriver *adcp) { + + osalDbgAssert(adcp->adcm->CR == ADC_CR_ADVREGEN, "invalid register state"); + + /* Differential calibration for master ADC.*/ + adcp->adcm->CR = ADC_CR_ADVREGEN | ADC_CR_ADCALDIF; + adcp->adcm->CR = ADC_CR_ADVREGEN | ADC_CR_ADCALDIF | ADC_CR_ADCAL; + while ((adcp->adcm->CR & ADC_CR_ADCAL) != 0) + ; + + /* Single-ended calibration for master ADC.*/ + adcp->adcm->CR = ADC_CR_ADVREGEN; + adcp->adcm->CR = ADC_CR_ADVREGEN | ADC_CR_ADCAL; + while ((adcp->adcm->CR & ADC_CR_ADCAL) != 0) + ; + +#if STM32_ADC_DUAL_MODE + osalDbgAssert(adcp->adcs->CR == ADC_CR_ADVREGEN, "invalid register state"); + + /* Differential calibration for slave ADC.*/ + adcp->adcs->CR = ADC_CR_ADVREGEN | ADC_CR_ADCALDIF; + adcp->adcs->CR = ADC_CR_ADVREGEN | ADC_CR_ADCALDIF | ADC_CR_ADCAL; + while ((adcp->adcs->CR & ADC_CR_ADCAL) != 0) + ; + + /* Single-ended calibration for slave ADC.*/ + adcp->adcs->CR = ADC_CR_ADVREGEN; + adcp->adcs->CR = ADC_CR_ADVREGEN | ADC_CR_ADCAL; + while ((adcp->adcs->CR & ADC_CR_ADCAL) != 0) + ; +#endif +} + +/** + * @brief Enables the ADC analog circuit. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_analog_on(ADCDriver *adcp) { + + adcp->adcm->CR |= ADC_CR_ADEN; + while ((adcp->adcm->ISR & ADC_ISR_ADRDY) == 0) + ; +#if STM32_ADC_DUAL_MODE + adcp->adcs->CR |= ADC_CR_ADEN; + while ((adcp->adcs->ISR & ADC_ISR_ADRDY) == 0) + ; +#endif +} + +/** + * @brief Disables the ADC analog circuit. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_analog_off(ADCDriver *adcp) { + + adcp->adcm->CR |= ADC_CR_ADDIS; + while ((adcp->adcm->CR & ADC_CR_ADDIS) != 0) + ; +#if STM32_ADC_DUAL_MODE + adcp->adcs->CR |= ADC_CR_ADDIS; + while ((adcp->adcs->CR & ADC_CR_ADDIS) != 0) + ; +#endif +} + +/** + * @brief Stops an ongoing conversion, if any. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_stop_adc(ADCDriver *adcp) { + + if (adcp->adcm->CR & ADC_CR_ADSTART) { + adcp->adcm->CR |= ADC_CR_ADSTP; + while (adcp->adcm->CR & ADC_CR_ADSTP) + ; + adcp->adcm->IER = 0; + } +} + +/** + * @brief ADC DMA service routine. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void adc_lld_serve_dma_interrupt(ADCDriver *adcp, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + /* DMA, this could help only if the DMA tries to access an unmapped + address space or violates alignment rules.*/ + _adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE); + } + else { + /* It is possible that the conversion group has already be reset by the + ADC error handler, in this case this interrupt is spurious.*/ + if (adcp->grpp != NULL) { + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } + else if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + } + } +} + +/** + * @brief ADC IRQ service routine. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] isr content of the ISR register + */ +static void adc_lld_serve_interrupt(ADCDriver *adcp, uint32_t isr) { + + /* It could be a spurious interrupt caused by overflows after DMA disabling, + just ignore it in this case.*/ + if (adcp->grpp != NULL) { + /* Note, an overflow may occur after the conversion ended before the driver + is able to stop the ADC, this is why the DMA channel is checked too.*/ + if ((isr & ADC_ISR_OVR) && + (dmaStreamGetTransactionSize(adcp->dmastp) > 0)) { + /* ADC overflow condition, this could happen only if the DMA is unable + to read data fast enough.*/ + _adc_isr_error_code(adcp, ADC_ERR_OVERFLOW); + } + if (isr & ADC_ISR_AWD1) { + /* Analog watchdog error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD1); + } + if (isr & ADC_ISR_AWD2) { + /* Analog watchdog error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD2); + } + if (isr & ADC_ISR_AWD3) { + /* Analog watchdog error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD3); + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2 || defined(__DOXYGEN__) +/** + * @brief ADC1/ADC2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_ADC1_HANDLER) { + uint32_t isr; + + OSAL_IRQ_PROLOGUE(); + +#if STM32_ADC_DUAL_MODE + + isr = ADC1->ISR; + isr |= ADC2->ISR; + ADC1->ISR = isr; + ADC2->ISR = isr; +#if defined(STM32_ADC_ADC12_IRQ_HOOK) + STM32_ADC_ADC12_IRQ_HOOK +#endif + adc_lld_serve_interrupt(&ADCD1, isr); + +#else /* !STM32_ADC_DUAL_MODE */ + +#if STM32_ADC_USE_ADC1 + isr = ADC1->ISR; + ADC1->ISR = isr; +#if defined(STM32_ADC_ADC1_IRQ_HOOK) + STM32_ADC_ADC1_IRQ_HOOK +#endif + adc_lld_serve_interrupt(&ADCD1, isr); +#endif + +#if STM32_ADC_USE_ADC2 + isr = ADC2->ISR; + ADC2->ISR = isr; +#if defined(STM32_ADC_ADC2_IRQ_HOOK) + STM32_ADC_ADC2_IRQ_HOOK +#endif + adc_lld_serve_interrupt(&ADCD2, isr); +#endif + +#endif /* !STM32_ADC_DUAL_MODE */ + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_ADC_USE_ADC1 */ + +#if STM32_ADC_USE_ADC3 || defined(__DOXYGEN__) +/** + * @brief ADC3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_ADC3_HANDLER) { + uint32_t isr; + + OSAL_IRQ_PROLOGUE(); + + isr = ADC3->ISR; + ADC3->ISR = isr; +#if defined(STM32_ADC_ADC3_IRQ_HOOK) + STM32_ADC_ADC3_IRQ_HOOK +#endif + adc_lld_serve_interrupt(&ADCD3, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#if STM32_ADC_DUAL_MODE +/** + * @brief ADC4 interrupt handler (as ADC3 slave). + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_ADC4_HANDLER) { + uint32_t isr; + + OSAL_IRQ_PROLOGUE(); + + isr = ADC4->ISR; + ADC4->ISR = isr; + + adc_lld_serve_interrupt(&ADCD3, isr); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_ADC_DUAL_MODE */ +#endif /* STM32_ADC_USE_ADC3 */ + +#if STM32_ADC_USE_ADC4 || defined(__DOXYGEN__) +/** + * @brief ADC4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_ADC4_HANDLER) { + uint32_t isr; + + OSAL_IRQ_PROLOGUE(); + + isr = ADC4->ISR; + ADC4->ISR = isr; + + adc_lld_serve_interrupt(&ADCD4, isr); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_ADC_USE_ADC4 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ADC driver initialization. + * + * @notapi + */ +void adc_lld_init(void) { + + clkmask = 0; + +#if STM32_ADC_USE_ADC1 + /* Driver initialization.*/ + adcObjectInit(&ADCD1); +#if defined(ADC1_2_COMMON) + ADCD1.adcc = ADC1_2_COMMON; +#elif defined(ADC12_COMMON) + ADCD1.adcc = ADC12_COMMON; +#elif defined(ADC123_COMMON) + ADCD1.adcc = ADC123_COMMON; +#else + ADCD1.adcc = ADC1_COMMON; +#endif + ADCD1.adcm = ADC1; +#if STM32_ADC_DUAL_MODE + ADCD1.adcs = ADC2; +#endif + ADCD1.dmastp = NULL; + ADCD1.dmamode = ADC_DMA_SIZE | + STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; +#endif /* STM32_ADC_USE_ADC1 */ + +#if STM32_ADC_USE_ADC2 + /* Driver initialization.*/ + adcObjectInit(&ADCD2); +#if defined(ADC1_2_COMMON) + ADCD2.adcc = ADC1_2_COMMON; +#elif defined(ADC12_COMMON) + ADCD2.adcc = ADC12_COMMON; +#elif defined(ADC123_COMMON) + ADCD2.adcc = ADC123_COMMON; +#endif + ADCD2.adcm = ADC2; + ADCD2.dmastp = NULL; + ADCD2.dmamode = ADC_DMA_SIZE | + STM32_DMA_CR_PL(STM32_ADC_ADC2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; +#endif /* STM32_ADC_USE_ADC2 */ + +#if STM32_ADC_USE_ADC3 + /* Driver initialization.*/ + adcObjectInit(&ADCD3); +#if defined(ADC3_4_COMMON) + ADCD3.adcc = ADC3_4_COMMON; +#elif defined(ADC345_COMMON) + ADCD3.adcc = ADC345_COMMON; +#elif defined(ADC123_COMMON) + ADCD3.adcc = ADC123_COMMON; +#else + ADCD3.adcc = ADC3_COMMON; +#endif + ADCD3.adcm = ADC3; +#if STM32_ADC_DUAL_MODE + ADCD3.adcs = ADC4; +#endif + ADCD3.dmastp = NULL; + ADCD3.dmamode = ADC_DMA_SIZE | + STM32_DMA_CR_PL(STM32_ADC_ADC3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; +#endif /* STM32_ADC_USE_ADC3 */ + +#if STM32_ADC_USE_ADC4 + /* Driver initialization.*/ + adcObjectInit(&ADCD4); +#if defined(ADC3_4_COMMON) + ADCD4.adcc = ADC3_4_COMMON; +#elif defined(ADC345_COMMON) + ADCD4.adcc = ADC345_COMMON; +#endif + ADCD4.adcm = ADC4; + ADCD4.dmastp = NULL; + ADCD4.dmamode = ADC_DMA_SIZE | + STM32_DMA_CR_PL(STM32_ADC_ADC4_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; +#endif /* STM32_ADC_USE_ADC4 */ + + /* IRQs setup.*/ +#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2 + nvicEnableVector(STM32_ADC1_NUMBER, STM32_ADC_ADC12_IRQ_PRIORITY); +#endif +#if STM32_ADC_USE_ADC3 + nvicEnableVector(STM32_ADC3_NUMBER, STM32_ADC_ADC3_IRQ_PRIORITY); +#if STM32_ADC_DUAL_MODE + nvicEnableVector(STM32_ADC4_NUMBER, STM32_ADC_ADC3_IRQ_PRIORITY); +#endif +#endif +#if STM32_ADC_USE_ADC4 + nvicEnableVector(STM32_ADC4_NUMBER, STM32_ADC_ADC4_IRQ_PRIORITY); +#endif + + /* ADC units pre-initializations.*/ +#if defined(STM32F3XX) +#if STM32_HAS_ADC1 && STM32_HAS_ADC2 +#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2 + rccEnableADC12(true); + rccResetADC12(); + ADC1_2_COMMON->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_MDMA; + rccDisableADC12(); +#endif +#else +#if STM32_ADC_USE_ADC1 + rccEnableADC12(true); + rccResetADC12(); + ADC1_COMMON->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_MDMA; + rccDisableADC12(); +#endif +#endif +#if STM32_ADC_USE_ADC3 || STM32_ADC_USE_ADC4 + rccEnableADC34(true); + rccResetADC34(); + ADC3_4_COMMON->CCR = STM32_ADC_ADC34_CLOCK_MODE | ADC_DMA_MDMA; + rccDisableADC34(); +#endif +#endif + +#if defined(STM32L4XX) || defined(STM32L4XXP) + rccEnableADC123(true); + rccResetADC123(); +#if defined(ADC1_2_COMMON) + ADC1_2_COMMON->CCR = STM32_ADC_ADC123_PRESC | STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA; +#elif defined(ADC123_COMMON) + ADC123_COMMON->CCR = STM32_ADC_ADC123_PRESC | STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA; +#else + ADC1_COMMON->CCR = STM32_ADC_ADC123_PRESC | STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA; +#endif + + rccDisableADC123(); +#endif + +#if defined(STM32G4XX) +#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2 + rccEnableADC12(true); + rccResetADC12(); + ADC12_COMMON->CCR = STM32_ADC_ADC12_PRESC | STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_MDMA; + rccDisableADC12(); +#endif +#if STM32_ADC_USE_ADC3 || STM32_ADC_USE_ADC4 + rccEnableADC345(true); + rccResetADC345(); + ADC345_COMMON->CCR = STM32_ADC_ADC345_PRESC | STM32_ADC_ADC345_CLOCK_MODE | ADC_DMA_MDMA; + rccDisableADC345(); +#endif +#endif +} + +/** + * @brief Configures and activates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start(ADCDriver *adcp) { + + /* Handling the default configuration.*/ + if (adcp->config == NULL) { + adcp->config = &default_config; + } + + /* If in stopped state then enables the ADC and DMA clocks.*/ + if (adcp->state == ADC_STOP) { +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) { + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC1_DMA_STREAM, + STM32_ADC_ADC1_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); + + clkmask |= (1 << 0); +#if defined(STM32F3XX) || defined(STM32G4XX) + rccEnableADC12(true); +#endif +#if defined(STM32L4XX) || defined(STM32L4XXP) + rccEnableADC123(true); +#endif +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC1); +#endif + } +#endif /* STM32_ADC_USE_ADC1 */ + +#if STM32_ADC_USE_ADC2 + if (&ADCD2 == adcp) { + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC2_DMA_STREAM, + STM32_ADC_ADC2_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); + + clkmask |= (1 << 1); +#if defined(STM32F3XX) || defined(STM32G4XX) + rccEnableADC12(true); +#endif +#if defined(STM32L4XX) || defined(STM32L4XXP) + rccEnableADC123(true); +#endif +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC2); +#endif + } +#endif /* STM32_ADC_USE_ADC2 */ + +#if STM32_ADC_USE_ADC3 + if (&ADCD3 == adcp) { + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC3_DMA_STREAM, + STM32_ADC_ADC3_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); + + clkmask |= (1 << 2); +#if defined(STM32F3XX) + rccEnableADC34(true); +#endif +#if defined(STM32L4XX) || defined(STM32L4XXP) + rccEnableADC123(true); +#endif +#if defined(STM32G4XX) + rccEnableADC345(true); +#endif +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC3); +#endif + } +#endif /* STM32_ADC_USE_ADC3 */ + +#if STM32_ADC_USE_ADC4 + if (&ADCD4 == adcp) { + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC4_DMA_STREAM, + STM32_ADC_ADC4_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); + + clkmask |= (1 << 3); +#if defined(STM32F3XX) + rccEnableADC34(true); +#endif +#if defined(STM32L4XX) || defined(STM32L4XXP) + rccEnableADC123(true); +#endif +#if defined(STM32G4XX) + rccEnableADC345(true); +#endif +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC4); +#endif + } +#endif /* STM32_ADC_USE_ADC4 */ + + /* Setting DMA peripheral-side pointer.*/ +#if STM32_ADC_DUAL_MODE + dmaStreamSetPeripheral(adcp->dmastp, &adcp->adcc->CDR); +#else + dmaStreamSetPeripheral(adcp->dmastp, &adcp->adcm->DR); +#endif + + /* Differential channels setting.*/ +#if STM32_ADC_DUAL_MODE + adcp->adcm->DIFSEL = adcp->config->difsel; + adcp->adcs->DIFSEL = adcp->config->difsel; +#else + adcp->adcm->DIFSEL = adcp->config->difsel; +#endif + + /* Master ADC calibration.*/ + adc_lld_vreg_on(adcp); + adc_lld_calibrate(adcp); + + /* Master ADC enabled here in order to reduce conversions latencies.*/ + adc_lld_analog_on(adcp); + } +} + +/** + * @brief Deactivates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop(ADCDriver *adcp) { + + /* If in ready state then disables the ADC clock and analog part.*/ + if (adcp->state == ADC_READY) { + + /* Releasing the associated DMA channel.*/ + dmaStreamFreeI(adcp->dmastp); + adcp->dmastp = NULL; + + /* Stopping the ongoing conversion, if any.*/ + adc_lld_stop_adc(adcp); + + /* Disabling ADC analog circuit and regulator.*/ + adc_lld_analog_off(adcp); + adc_lld_vreg_off(adcp); + +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) { + /* Resetting CCR options except default ones.*/ + clkmask &= ~(1 << 0); + } +#endif + +#if STM32_ADC_USE_ADC2 + if (&ADCD2 == adcp) { + clkmask &= ~(1 << 1); + } +#endif + +#if STM32_ADC_USE_ADC3 + if (&ADCD3 == adcp) { + clkmask &= ~(1 << 2); + } +#endif + +#if STM32_ADC_USE_ADC4 + if (&ADCD4 == adcp) { + clkmask &= ~(1 << 3); + } +#endif + +#if defined(STM32F3XX) +#if STM32_HAS_ADC1 || STM32_HAS_ADC2 + if ((clkmask & 0x3) == 0) { + rccDisableADC12(); + } +#endif + +#if STM32_HAS_ADC3 || STM32_HAS_ADC4 + if ((clkmask & 0xC) == 0) { + rccDisableADC34(); + } +#endif +#endif + +#if defined(STM32L4XX) || defined(STM32L4XXP) + if ((clkmask & 0x7) == 0) { + rccDisableADC123(); + } +#endif + +#if defined(STM32G4XX) +#if STM32_HAS_ADC1 || STM32_HAS_ADC2 + if ((clkmask & 0x3) == 0) { + rccDisableADC12(); + } +#endif + +#if STM32_HAS_ADC3 || STM32_HAS_ADC4 + if ((clkmask & 0xC) == 0) { + rccDisableADC345(); + } +#endif +#endif + } +} + +/** + * @brief Starts an ADC conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start_conversion(ADCDriver *adcp) { + uint32_t dmamode, cfgr; + const ADCConversionGroup *grpp = adcp->grpp; +#if STM32_ADC_DUAL_MODE + uint32_t ccr = grpp->ccr & ~(ADC_CCR_CKMODE_MASK | ADC_CCR_MDMA_MASK); +#endif + + osalDbgAssert(!STM32_ADC_DUAL_MODE || ((grpp->num_channels & 1) == 0), + "odd number of channels in dual mode"); + + /* Calculating control registers values.*/ + dmamode = adcp->dmamode; + cfgr = grpp->cfgr | ADC_CFGR_DMAEN; + if (grpp->circular) { + dmamode |= STM32_DMA_CR_CIRC; +#if STM32_ADC_DUAL_MODE + ccr |= ADC_CCR_DMACFG_CIRCULAR; +#else + cfgr |= ADC_CFGR_DMACFG_CIRCULAR; +#endif + if (adcp->depth > 1) { + /* If circular buffer depth > 1, then the half transfer interrupt + is enabled in order to allow streaming processing.*/ + dmamode |= STM32_DMA_CR_HTIE; + } + } + + /* DMA setup.*/ + dmaStreamSetMemory0(adcp->dmastp, adcp->samples); +#if STM32_ADC_DUAL_MODE + dmaStreamSetTransactionSize(adcp->dmastp, ((uint32_t)grpp->num_channels/2) * + (uint32_t)adcp->depth); +#else + dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * + (uint32_t)adcp->depth); +#endif + dmaStreamSetMode(adcp->dmastp, dmamode); + dmaStreamEnable(adcp->dmastp); + + /* ADC setup, if it is defined a callback for the analog watch dog then it + is enabled.*/ + adcp->adcm->ISR = adcp->adcm->ISR; + if (grpp->error_cb != NULL) { + adcp->adcm->IER = ADC_IER_OVRIE | ADC_IER_AWD1IE + | ADC_IER_AWD2IE + | ADC_IER_AWD3IE; + adcp->adcm->TR1 = grpp->tr1; + adcp->adcm->TR2 = grpp->tr2; + adcp->adcm->TR3 = grpp->tr3; + adcp->adcm->AWD2CR = grpp->awd2cr; + adcp->adcm->AWD3CR = grpp->awd3cr; + } + +#if STM32_ADC_DUAL_MODE + + /* Configuring the CCR register with the user-specified settings + in the conversion group configuration structure, static settings are + preserved.*/ + adcp->adcc->CCR = (adcp->adcc->CCR & + (ADC_CCR_CKMODE_MASK | ADC_CCR_MDMA_MASK)) | ccr; + + adcp->adcm->SMPR1 = grpp->smpr[0]; + adcp->adcm->SMPR2 = grpp->smpr[1]; + adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2); + adcp->adcm->SQR2 = grpp->sqr[1]; + adcp->adcm->SQR3 = grpp->sqr[2]; + adcp->adcm->SQR4 = grpp->sqr[3]; + adcp->adcs->SMPR1 = grpp->ssmpr[0]; + adcp->adcs->SMPR2 = grpp->ssmpr[1]; + adcp->adcs->SQR1 = grpp->ssqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2); + adcp->adcs->SQR2 = grpp->ssqr[1]; + adcp->adcs->SQR3 = grpp->ssqr[2]; + adcp->adcs->SQR4 = grpp->ssqr[3]; + +#else /* !STM32_ADC_DUAL_MODE */ + adcp->adcm->SMPR1 = grpp->smpr[0]; + adcp->adcm->SMPR2 = grpp->smpr[1]; + adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels); + adcp->adcm->SQR2 = grpp->sqr[1]; + adcp->adcm->SQR3 = grpp->sqr[2]; + adcp->adcm->SQR4 = grpp->sqr[3]; +#endif /* !STM32_ADC_DUAL_MODE */ + + /* ADC configuration.*/ + adcp->adcm->CFGR = cfgr; +#if (STM32_ADCV3_OVERSAMPLING == TRUE) || defined(__DOXYGEN__) + adcp->adcm->CFGR2 = grpp->cfgr2; +#endif + + /* Starting conversion.*/ + adcp->adcm->CR |= ADC_CR_ADSTART; +} + +/** + * @brief Stops an ongoing conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop_conversion(ADCDriver *adcp) { + + dmaStreamDisable(adcp->dmastp); + adc_lld_stop_adc(adcp); +} + +/** + * @brief Enables the VREFEN bit. + * @details The VREFEN bit is required in order to sample the VREF channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableVREF(ADCDriver *adcp) { + + adcp->adcc->CCR |= ADC_CCR_VREFEN; +} + +/** + * @brief Disables the VREFEN bit. + * @details The VREFEN bit is required in order to sample the VREF channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableVREF(ADCDriver *adcp) { + + adcp->adcc->CCR &= ~ADC_CCR_VREFEN; +} + +/** + * @brief Enables the TSEN bit. + * @details The TSEN bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableTS(ADCDriver *adcp) { + + adcp->adcc->CCR |= ADC_CCR_TSEN; +} + +/** + * @brief Disables the TSEN bit. + * @details The TSEN bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableTS(ADCDriver *adcp) { + + adcp->adcc->CCR &= ~ADC_CCR_TSEN; +} + +/** + * @brief Enables the VBATEN bit. + * @details The VBATEN bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableVBAT(ADCDriver *adcp) { + + adcp->adcc->CCR |= ADC_CCR_VBATEN; +} + +/** + * @brief Disables the VBATEN bit. + * @details The VBATEN bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableVBAT(ADCDriver *adcp) { + + adcp->adcc->CCR &= ~ADC_CCR_VBATEN; +} + +#endif /* HAL_USE_ADC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.h new file mode 100644 index 0000000..8d6c615 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.h @@ -0,0 +1,1026 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv3/hal_adc_lld.h + * @brief STM32 ADC subsystem low level driver header. + * + * @addtogroup ADC + * @{ + */ + +#ifndef HAL_ADC_LLD_H +#define HAL_ADC_LLD_H + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Available analog channels + * @{ + */ +#define ADC_CHANNEL_IN0 0 /**< @brief External analog input 0. */ +#define ADC_CHANNEL_IN1 1 /**< @brief External analog input 1. */ +#define ADC_CHANNEL_IN2 2 /**< @brief External analog input 2. */ +#define ADC_CHANNEL_IN3 3 /**< @brief External analog input 3. */ +#define ADC_CHANNEL_IN4 4 /**< @brief External analog input 4. */ +#define ADC_CHANNEL_IN5 5 /**< @brief External analog input 5. */ +#define ADC_CHANNEL_IN6 6 /**< @brief External analog input 6. */ +#define ADC_CHANNEL_IN7 7 /**< @brief External analog input 7. */ +#define ADC_CHANNEL_IN8 8 /**< @brief External analog input 8. */ +#define ADC_CHANNEL_IN9 9 /**< @brief External analog input 9. */ +#define ADC_CHANNEL_IN10 10 /**< @brief External analog input 10. */ +#define ADC_CHANNEL_IN11 11 /**< @brief External analog input 11. */ +#define ADC_CHANNEL_IN12 12 /**< @brief External analog input 12. */ +#define ADC_CHANNEL_IN13 13 /**< @brief External analog input 13. */ +#define ADC_CHANNEL_IN14 14 /**< @brief External analog input 14. */ +#define ADC_CHANNEL_IN15 15 /**< @brief External analog input 15. */ +#define ADC_CHANNEL_IN16 16 /**< @brief External analog input 16. */ +#define ADC_CHANNEL_IN17 17 /**< @brief External analog input 17. */ +#define ADC_CHANNEL_IN18 18 /**< @brief External analog input 18. */ +/** @} */ + +/** + * @name Sampling rates + * @{ + */ +#if defined(STM32F3XX) || defined(__DOXYGEN__) +#define ADC_SMPR_SMP_1P5 0 /**< @brief 14 cycles conversion time */ +#define ADC_SMPR_SMP_2P5 1 /**< @brief 15 cycles conversion time. */ +#define ADC_SMPR_SMP_4P5 2 /**< @brief 17 cycles conversion time. */ +#define ADC_SMPR_SMP_7P5 3 /**< @brief 20 cycles conversion time. */ +#define ADC_SMPR_SMP_19P5 4 /**< @brief 32 cycles conversion time. */ +#define ADC_SMPR_SMP_61P5 5 /**< @brief 74 cycles conversion time. */ +#define ADC_SMPR_SMP_181P5 6 /**< @brief 194 cycles conversion time. */ +#define ADC_SMPR_SMP_601P5 7 /**< @brief 614 cycles conversion time. */ +#endif +#if defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ADC_SMPR_SMP_2P5 0 /**< @brief 15 cycles conversion time */ +#define ADC_SMPR_SMP_6P5 1 /**< @brief 19 cycles conversion time. */ +#define ADC_SMPR_SMP_12P5 2 /**< @brief 25 cycles conversion time. */ +#define ADC_SMPR_SMP_24P5 3 /**< @brief 37 cycles conversion time. */ +#define ADC_SMPR_SMP_47P5 4 /**< @brief 60 cycles conversion time. */ +#define ADC_SMPR_SMP_92P5 5 /**< @brief 105 cycles conversion time. */ +#define ADC_SMPR_SMP_247P5 6 /**< @brief 260 cycles conversion time. */ +#define ADC_SMPR_SMP_640P5 7 /**< @brief 653 cycles conversion time. */ +#endif +/** @} */ + +/** + * @name CFGR register configuration helpers + * @{ + */ +#define ADC_CFGR_DMACFG_MASK (1 << 1) +#define ADC_CFGR_DMACFG_ONESHOT (0 << 1) +#define ADC_CFGR_DMACFG_CIRCULAR (1 << 1) + +#define ADC_CFGR_RES_MASK (3 << 3) +#define ADC_CFGR_RES_12BITS (0 << 3) +#define ADC_CFGR_RES_10BITS (1 << 3) +#define ADC_CFGR_RES_8BITS (2 << 3) +#define ADC_CFGR_RES_6BITS (3 << 3) + +#if defined(STM32F3XX) || defined(STM32L4XX) || defined(STM32L4XXP) || \ + defined(__DOXYGEN__) +#define ADC_CFGR_ALIGN_MASK (1 << 5) +#define ADC_CFGR_ALIGN_RIGHT (0 << 5) +#define ADC_CFGR_ALIGN_LEFT (1 << 5) + +#define ADC_CFGR_EXTSEL_MASK (15 << 6) +#define ADC_CFGR_EXTSEL_SRC(n) ((n) << 6) +#endif +#if defined(STM32G4XX) +#define ADC_CFGR_ALIGN_MASK (1 << 15) +#define ADC_CFGR_ALIGN_RIGHT (0 << 15) +#define ADC_CFGR_ALIGN_LEFT (1 << 15) + +#define ADC_CFGR_EXTSEL_MASK (31 << 5) +#define ADC_CFGR_EXTSEL_SRC(n) ((n) << 5) +#endif + +#define ADC_CFGR_EXTEN_MASK (3 << 10) +#define ADC_CFGR_EXTEN_DISABLED (0 << 10) +#define ADC_CFGR_EXTEN_RISING (1 << 10) +#define ADC_CFGR_EXTEN_FALLING (2 << 10) +#define ADC_CFGR_EXTEN_BOTH (3 << 10) + +#define ADC_CFGR_DISCEN_MASK (1 << 16) +#define ADC_CFGR_DISCEN_DISABLED (0 << 16) +#define ADC_CFGR_DISCEN_ENABLED (1 << 16) + +#define ADC_CFGR_DISCNUM_MASK (7 << 17) +#define ADC_CFGR_DISCNUM_VAL(n) ((n) << 17) + +#define ADC_CFGR_AWD1_DISABLED 0 +#define ADC_CFGR_AWD1_ALL (1 << 23) +#define ADC_CFGR_AWD1_SINGLE(n) (((n) << 26) | (1 << 23) | (1 << 22)) +/** @} */ + +/** + * @name CCR register configuration helpers + * @{ + */ +#define ADC_CCR_DUAL_MASK (31 << 0) +#define ADC_CCR_DUAL_FIELD(n) ((n) << 0) + +#define ADC_CCR_DELAY_MASK (15 << 8) +#define ADC_CCR_DELAY_FIELD(n) ((n) << 8) + +#define ADC_CCR_DMACFG_MASK (1 << 13) +#define ADC_CCR_DMACFG_ONESHOT (0 << 13) +#define ADC_CCR_DMACFG_CIRCULAR (1 << 13) + +#define ADC_CCR_MDMA_MASK (3 << 14) +#define ADC_CCR_MDMA_DISABLED (0 << 14) +#define ADC_CCR_MDMA_WORD (2 << 14) +#define ADC_CCR_MDMA_HWORD (3 << 14) + +#define ADC_CCR_CKMODE_MASK (3 << 16) +#define ADC_CCR_CKMODE_ADCCK (0 << 16) +#define ADC_CCR_CKMODE_AHB_DIV1 (1 << 16) +#define ADC_CCR_CKMODE_AHB_DIV2 (2 << 16) +#define ADC_CCR_CKMODE_AHB_DIV4 (3 << 16) + +#if !defined(STM32F3XX) +#define ADC_CCR_PRESC_MASK (15 << 18) +#define ADC_CCR_PRESC_NOCLOCK (0 << 18) +#define ADC_CCR_PRESC_DIV2 (1 << 18) +#define ADC_CCR_PRESC_DIV4 (2 << 18) +#define ADC_CCR_PRESC_DIV6 (3 << 18) +#define ADC_CCR_PRESC_DIV8 (4 << 18) +#define ADC_CCR_PRESC_DIV10 (5 << 18) +#define ADC_CCR_PRESC_DIV12 (6 << 18) +#define ADC_CCR_PRESC_DIV16 (7 << 18) +#define ADC_CCR_PRESC_DIV32 (8 << 18) +#define ADC_CCR_PRESC_DIV64 (9 << 18) +#define ADC_CCR_PRESC_DIV128 (10 << 18) +#define ADC_CCR_PRESC_DIV256 (11 << 18) +#endif /* !defined(STM32F3XX) */ + +/* F3 headers do not define the following macros, L4 headers do.*/ +#if !defined(ADC_CCR_VREFEN) || defined(__DOXYGEN__) +#define ADC_CCR_VREFEN (1 << 22) +#endif + +#if !defined(ADC_CCR_TSEN) || defined(__DOXYGEN__) +#define ADC_CCR_TSEN (1 << 23) +#endif + +#if !defined(ADC_CCR_VBATEN) || defined(__DOXYGEN__) +#define ADC_CCR_VBATEN (1 << 24) +#endif +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief Enables the ADC master/slave mode. + * @note In dual mode only ADCD1 and ADCD3 are available. + */ +#if !defined(STM32_ADC_DUAL_MODE) || defined(__DOXYGEN__) +#define STM32_ADC_DUAL_MODE FALSE +#endif + +/** + * @brief Makes the ADC samples type an 8bits one. + * @note 10 and 12 bits sampling mode must not be used when this option + * is enabled. + */ +#if !defined(STM32_ADC_COMPACT_SAMPLES) || defined(__DOXYGEN__) +#define STM32_ADC_COMPACT_SAMPLES FALSE +#endif + +/** + * @brief ADC1 driver enable switch. + * @details If set to @p TRUE the support for ADC1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC1) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC1 FALSE +#endif + +/** + * @brief ADC2 driver enable switch. + * @details If set to @p TRUE the support for ADC2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC2) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC2 FALSE +#endif + +/** + * @brief ADC3 driver enable switch. + * @details If set to @p TRUE the support for ADC3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC3) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC3 FALSE +#endif +/** + * @brief ADC4 driver enable switch. + * @details If set to @p TRUE the support for ADC4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC4) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC4 FALSE +#endif + +/** + * @brief ADC1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC2_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC3 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC4 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC4_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC1/ADC2 interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC12_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC3 interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC4 interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC4_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC1 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC2 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC3 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC3_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC4 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC4_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC4_DMA_IRQ_PRIORITY 5 +#endif + +#if defined(STM32F3XX) || defined(__DOXYGEN__) +/** + * @brief ADC1/ADC2 clock source and mode. + */ +#if !defined(STM32_ADC_ADC12_CLOCK_MODE) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV1 +#endif + +/** + * @brief ADC3/ADC4 clock source and mode. + */ +#if !defined(STM32_ADC_ADC34_CLOCK_MODE) || defined(__DOXYGEN__) +#define STM32_ADC_ADC34_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV1 +#endif +#endif /* defined(STM32F3XX) */ + +#if defined(STM32L4XX) || defined(STM32L4XXP) || defined(__DOXYGEN__) +/** + * @brief ADC1/ADC2/ADC3 clock source and mode. + */ +#if !defined(STM32_ADC_ADC123_CLOCK_MODE) || defined(__DOXYGEN__) +#define STM32_ADC_ADC123_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV1 +#endif + +/** + * @brief ADC1/ADC2/ADC3 clock prescaler. + */ +#if !defined(STM32_ADC_ADC123_PRESC) || defined(__DOXYGEN__) +#define STM32_ADC_ADC123_PRESC ADC_CCR_PRESC_DIV2 +#endif +#endif /* defined(STM32L4XX) || defined(STM32L4XXP) */ + +#if defined(STM32G4XX) || defined(__DOXYGEN__) +/** + * @brief ADC1/ADC2 clock source and mode. + */ +#if !defined(STM32_ADC_ADC12_CLOCK_MODE) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4 +#endif + +/** + * @brief ADC3/ADC4/ADC5 clock source and mode. + */ +#if !defined(STM32_ADC_ADC345_CLOCK_MODE) || defined(__DOXYGEN__) +#define STM32_ADC_ADC345_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4 +#endif + +/** + * @brief ADC1/ADC2 clock prescaler. + */ +#if !defined(STM32_ADC_ADC12_PRESC) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_PRESC ADC_CCR_PRESC_DIV2 +#endif + +/** + * @brief ADC3/ADC4/ADC5 clock prescaler. + */ +#if !defined(STM32_ADC_ADC345_PRESC) || defined(__DOXYGEN__) +#define STM32_ADC_ADC345_PRESC ADC_CCR_PRESC_DIV2 +#endif +#endif /* defined(STM32G4XX) */ + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Supported devices checks.*/ +#if !defined(STM32F3XX) && !defined(STM32L4XX) && !defined(STM32L4XXP) && \ + !defined(STM32G4XX) +#error "ADCv3 only supports F3, L4, L4+ and G4 STM32 devices" +#endif + +#if defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) || \ + defined(__DOXYGEN__) +#define STM32_ADCV3_OVERSAMPLING TRUE +#else +#define STM32_ADCV3_OVERSAMPLING FALSE +#endif + +/* Registry checks.*/ +#if !defined(STM32_HAS_ADC1) || !defined(STM32_HAS_ADC2) || \ + !defined(STM32_HAS_ADC3) || !defined(STM32_HAS_ADC4) +#error "STM32_HAS_ADCx not defined in registry" +#endif + +#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_HANDLER)) || \ + (STM32_ADC_USE_ADC2 && !defined(STM32_ADC2_HANDLER)) || \ + (STM32_ADC_USE_ADC3 && !defined(STM32_ADC3_HANDLER)) || \ + (STM32_ADC_USE_ADC4 && !defined(STM32_ADC4_HANDLER)) +#error "STM32_ADCx_HANDLER not defined in registry" +#endif + +#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_NUMBER)) || \ + (STM32_ADC_USE_ADC2 && !defined(STM32_ADC2_NUMBER)) || \ + (STM32_ADC_USE_ADC3 && !defined(STM32_ADC3_NUMBER)) || \ + (STM32_ADC_USE_ADC4 && !defined(STM32_ADC4_NUMBER)) +#error "STM32_ADCx_NUMBER not defined in registry" +#endif + +#if !STM32_DMA_SUPPORTS_DMAMUX +#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_DMA_MSK)) || \ + (STM32_ADC_USE_ADC2 && !defined(STM32_ADC2_DMA_MSK)) || \ + (STM32_ADC_USE_ADC3 && !defined(STM32_ADC3_DMA_MSK)) || \ + (STM32_ADC_USE_ADC4 && !defined(STM32_ADC4_DMA_MSK)) +#error "STM32_ADCx_DMA_MSK not defined in registry" +#endif + +#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_DMA_CHN)) || \ + (STM32_ADC_USE_ADC2 && !defined(STM32_ADC2_DMA_CHN)) || \ + (STM32_ADC_USE_ADC3 && !defined(STM32_ADC3_DMA_CHN)) || \ + (STM32_ADC_USE_ADC4 && !defined(STM32_ADC4_DMA_CHN)) +#error "STM32_ADCx_DMA_CHN not defined in registry" +#endif +#endif /* !STM32_DMA_SUPPORTS_DMAMUX */ + +/* Units checks.*/ +#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1 +#error "ADC1 not present in the selected device" +#endif + +#if STM32_ADC_USE_ADC2 && !STM32_HAS_ADC2 +#error "ADC2 not present in the selected device" +#endif + +#if STM32_ADC_USE_ADC3 && !STM32_HAS_ADC3 +#error "ADC3 not present in the selected device" +#endif + +#if STM32_ADC_USE_ADC4 && !STM32_HAS_ADC4 +#error "ADC4 not present in the selected device" +#endif + +/* Units checks related to dual mode.*/ +#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC1 && !STM32_HAS_ADC2 +#error "ADC2 not present in the selected device, required for dual mode" +#endif + +#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC3 && !STM32_HAS_ADC4 +#error "ADC4 not present in the selected device, required for dual mode" +#endif + +#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC2 +#error "ADC2 cannot be used in dual mode" +#endif + +#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC4 +#error "ADC4 cannot be used in dual mode" +#endif + +/* At least one ADC must be assigned.*/ +#if !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && \ + !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4 +#error "ADC driver activated but no ADC peripheral assigned" +#endif + +/* ISR arrangements checks.*/ +#if STM32_HAS_ADC1 && STM32_HAS_ADC2 +#if STM32_ADC1_NUMBER != STM32_ADC2_NUMBER +#error "ADCv3 driver expects STM32_ADC1_NUMBER == STM32_ADC2_NUMBER from registry" +#endif +#endif + +/* ADC IRQ priority tests.*/ +#if STM32_ADC_USE_ADC1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC12_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC1" +#endif + +#if STM32_ADC_USE_ADC2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC12_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC2" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC3" +#endif + +#if STM32_ADC_USE_ADC4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC4" +#endif + +/* DMA IRQ priority tests.*/ +#if STM32_ADC_USE_ADC1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC1_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC1 DMA" +#endif + +#if STM32_ADC_USE_ADC2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC2_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC2 DMA" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC3_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC3 DMA" +#endif + +#if STM32_ADC_USE_ADC4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC4_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC4 DMA" +#endif + +/* DMA priority tests.*/ +#if STM32_ADC_USE_ADC1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC1" +#endif + +#if STM32_ADC_USE_ADC2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC2" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC3" +#endif + +#if STM32_ADC_USE_ADC4 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC4" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_ADC_USE_ADC1 && !defined(STM32_ADC_ADC1_DMA_STREAM) +#error "ADC1 DMA stream not defined" +#endif + +#if STM32_ADC_USE_ADC2 && !defined(STM32_ADC_ADC2_DMA_STREAM) +#error "ADC2 DMA stream not defined" +#endif + +#if STM32_ADC_USE_ADC3 && !defined(STM32_ADC_ADC3_DMA_STREAM) +#error "ADC3 DMA stream not defined" +#endif + +#if STM32_ADC_USE_ADC4 && !defined(STM32_ADC_ADC4_DMA_STREAM) +#error "ADC4 DMA stream not defined" +#endif + +#if STM32_DMA_SUPPORTS_DMAMUX + +#else /* !STM32_DMA_SUPPORTS_DMAMUX */ + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_ADC_USE_ADC1 && \ + !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_MSK) +#error "invalid DMA stream associated to ADC1" +#endif + +#if STM32_ADC_USE_ADC2 && \ + !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC2_DMA_STREAM, STM32_ADC2_DMA_MSK) +#error "invalid DMA stream associated to ADC2" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC3_DMA_STREAM, STM32_ADC3_DMA_MSK) +#error "invalid DMA stream associated to ADC3" +#endif + +#if STM32_ADC_USE_ADC4 && \ + !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC4_DMA_STREAM, STM32_ADC4_DMA_MSK) +#error "invalid DMA stream associated to ADC4" +#endif + +#endif /* !STM32_DMA_SUPPORTS_DMAMUX */ + +/* ADC clock prescaler checks.*/ +#if defined(STM32F3XX) +#endif /* defined(STM32F3XX) */ + +#if defined(STM32L4XX) || defined(STM32L4XXP) +#if STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV2 +#define ADC123_PRESC_VALUE 2 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV4 +#define ADC123_PRESC_VALUE 4 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV6 +#define ADC123_PRESC_VALUE 6 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV8 +#define ADC123_PRESC_VALUE 8 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV10 +#define ADC123_PRESC_VALUE 10 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV12 +#define ADC123_PRESC_VALUE 12 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV16 +#define ADC123_PRESC_VALUE 16 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV32 +#define ADC123_PRESC_VALUE 32 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV64 +#define ADC123_PRESC_VALUE 64 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV128 +#define ADC123_PRESC_VALUE 128 +#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV256 +#define ADC123_PRESC_VALUE 256 +#error "invalid clock divider selected for STM32_ADC_ADC12_PRESC" +#endif +#endif /* defined(STM32L4XX) || defined(STM32L4XXP) */ + +#if defined(STM32G4XX) +#if STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV2 +#define ADC12_PRESC_VALUE 2 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV4 +#define ADC12_PRESC_VALUE 4 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV6 +#define ADC12_PRESC_VALUE 6 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV8 +#define ADC12_PRESC_VALUE 8 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV10 +#define ADC12_PRESC_VALUE 10 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV12 +#define ADC12_PRESC_VALUE 12 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV16 +#define ADC12_PRESC_VALUE 16 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV32 +#define ADC12_PRESC_VALUE 32 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV64 +#define ADC12_PRESC_VALUE 64 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV128 +#define ADC12_PRESC_VALUE 128 +#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV256 +#define ADC12_PRESC_VALUE 256 +#error "invalid clock divider selected for STM32_ADC_ADC12_PRESC" +#endif + +#if STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV2 +#define ADC345_PRESC_VALUE 2 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV4 +#define ADC345_PRESC_VALUE 4 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV6 +#define ADC345_PRESC_VALUE 6 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV8 +#define ADC345_PRESC_VALUE 8 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV10 +#define ADC345_PRESC_VALUE 10 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV12 +#define ADC345_PRESC_VALUE 12 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV16 +#define ADC345_PRESC_VALUE 16 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV32 +#define ADC345_PRESC_VALUE 32 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV64 +#define ADC345_PRESC_VALUE 64 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV128 +#define ADC345_PRESC_VALUE 128 +#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV256 +#define ADC345_PRESC_VALUE 256 +#error "invalid clock divider selected for STM32_ADC_ADC345_PRESC" +#endif +#endif /* defined(STM32G4XX) */ + +/* ADC clock source checks.*/ +#if defined(STM32F3XX) +#if STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK +#define STM32_ADC12_CLOCK STM32_ADC12CLK +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1 +#define STM32_ADC12_CLOCK (STM32_HCLK / 1) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2 +#define STM32_ADC12_CLOCK (STM32_HCLK / 2) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC12_CLOCK (STM32_HCLK / 4) +#else +#error "invalid clock mode selected for STM32_ADC_ADC12_CLOCK_MODE" +#endif + +#if STM32_ADC_ADC34_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK +#define STM32_ADC34_CLOCK STM32_ADC34CLK +#elif STM32_ADC_ADC34_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1 +#define STM32_ADC34_CLOCK (STM32_HCLK / 1) +#elif STM32_ADC_ADC34_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2 +#define STM32_ADC34_CLOCK (STM32_HCLK / 2) +#elif STM32_ADC_ADC34_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC34_CLOCK (STM32_HCLK / 4) +#else +#error "invalid clock mode selected for STM32_ADC_ADC34_CLOCK_MODE" +#endif + +#if STM32_ADC12_CLOCK > STM32_ADCCLK_MAX +#error "STM32_ADC12_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)" +#endif + +#if STM32_ADC34_CLOCK > STM32_ADCCLK_MAX +#error "STM32_ADC34_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)" +#endif +#endif /* defined(STM32F3XX) */ + +#if defined(STM32L4XX) || defined(STM32L4XXP) +#if STM32_ADC_ADC123_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK +#define STM32_ADC123_CLOCK (STM32_ADCCLK / ADC123_PRESC_VALUE) +#elif STM32_ADC_ADC123_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1 +#define STM32_ADC123_CLOCK (STM32_ADCCLK / 1) +#elif STM32_ADC_ADC123_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2 +#define STM32_ADC123_CLOCK (STM32_ADCCLK / 2) +#elif STM32_ADC_ADC123_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC123_CLOCK (STM32_ADCCLK / 4) +#else +#error "invalid clock mode selected for STM32_ADC_ADC123_CLOCK_MODE" +#endif + +#if STM32_ADC123_CLOCK > STM32_ADCCLK_MAX +#error "STM32_ADC123_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)" +#endif +#endif /* defined(STM32L4XX) || defined(STM32L4XXP) */ + +#if defined(STM32G4XX) +#if STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK +#define STM32_ADC12_CLOCK (STM32_ADC12CLK / ADC12_PRESC_VALUE) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1 +#define STM32_ADC12_CLOCK (STM32_HCLK / 1) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2 +#define STM32_ADC12_CLOCK (STM32_HCLK / 2) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC12_CLOCK (STM32_HCLK / 4) +#else +#error "invalid clock mode selected for STM32_ADC_ADC12_CLOCK_MODE" +#endif + +#if STM32_ADC_ADC345_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK +#define STM32_ADC345_CLOCK (STM32_ADC345CLK / ADC345_PRESC_VALUE) +#elif STM32_ADC_ADC345_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1 +#define STM32_ADC345_CLOCK (STM32_HCLK / 1) +#elif STM32_ADC_ADC345_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2 +#define STM32_ADC345_CLOCK (STM32_HCLK / 2) +#elif STM32_ADC_ADC345_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC345_CLOCK (STM32_HCLK / 4) +#else +#error "invalid clock mode selected for STM32_ADC_ADC345_CLOCK_MODE" +#endif + +#if STM32_ADC12_CLOCK > STM32_ADCCLK_MAX +#error "STM32_ADC12_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)" +#endif + +#if STM32_ADC345_CLOCK > STM32_ADCCLK_MAX +#error "STM32_ADC345_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)" +#endif +#endif /* defined(STM32G4XX) */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief ADC sample data type. + */ +#if !STM32_ADC_COMPACT_SAMPLES || defined(__DOXYGEN__) +typedef uint16_t adcsample_t; +#else +typedef uint8_t adcsample_t; +#endif + +/** + * @brief Channels number in a conversion group. + */ +typedef uint16_t adc_channels_num_t; + +/** + * @brief Possible ADC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ + ADC_ERR_OVERFLOW = 1, /**< ADC overflow condition. */ + ADC_ERR_AWD1 = 2, /**< Watchdog 1 triggered. */ + ADC_ERR_AWD2 = 3, /**< Watchdog 2 triggered. */ + ADC_ERR_AWD3 = 4 /**< Watchdog 3 triggered. */ +} adcerror_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the ADC driver structure. + */ +#if (STM32_ADC_DUAL_MODE == TRUE) || defined(__DOXYGEN__) +#define adc_lld_driver_fields \ + /* Pointer to the master ADCx registers block.*/ \ + ADC_TypeDef *adcm; \ + /* Pointer to the slave ADCx registers block.*/ \ + ADC_TypeDef *adcs; \ + /* Pointer to the common ADCx_y registers block.*/ \ + ADC_Common_TypeDef *adcc; \ + /* Pointer to associated DMA channel.*/ \ + const stm32_dma_stream_t *dmastp; \ + /* DMA mode bit mask.*/ \ + uint32_t dmamode +#else +#define adc_lld_driver_fields \ + /* Pointer to the master ADCx registers block.*/ \ + ADC_TypeDef *adcm; \ + /* Pointer to the slave ADCx registers block.*/ \ + ADC_Common_TypeDef *adcc; \ + /* Pointer to associated DMA channel.*/ \ + const stm32_dma_stream_t *dmastp; \ + /* DMA mode bit mask.*/ \ + uint32_t dmamode +#endif + +/** + * @brief Low level fields of the ADC configuration structure. + */ +#define adc_lld_config_fields \ + /* ADC DIFSEL register initialization data.*/ \ + uint32_t difsel + +/** + * @brief Low level fields of the ADC group configuration structure. + */ +#if (STM32_ADCV3_OVERSAMPLING == TRUE) || defined(__DOXYGEN__) +#if (STM32_ADC_DUAL_MODE == TRUE) || defined(__DOXYGEN__) +#define adc_lld_configuration_group_fields \ + /* ADC CFGR register initialization data. \ + NOTE: The bits DMAEN and DMACFG are enforced internally \ + to the driver, keep them to zero. \ + NOTE: The bits @p ADC_CFGR_CONT or @p ADC_CFGR_DISCEN must be \ + specified in continuous mode or if the buffer depth is \ + greater than one.*/ \ + uint32_t cfgr; \ + /* ADC CFGR2 register initialization data.*/ \ + uint32_t cfgr2; \ + /* ADC TR1 register initialization data.*/ \ + uint32_t tr1; \ + /* ADC TR2 register initialization data.*/ \ + uint32_t tr2; \ + /* ADC TR3 register initialization data.*/ \ + uint32_t tr3; \ + /* ADC AWD2CR register initialization data.*/ \ + uint32_t awd2cr; \ + /* ADC AWD3CR register initialization data.*/ \ + uint32_t awd3cr; \ + /* ADC CCR register initialization data. \ + NOTE: Put this field to zero if not using oversampling.*/ \ + uint32_t ccr; \ + /* ADC SMPRx registers initialization data.*/ \ + uint32_t smpr[2]; \ + /* ADC SQRx register initialization data.*/ \ + uint32_t sqr[4]; \ + /* Slave ADC SMPRx registers initialization data. \ + NOTE: This field is only present in dual mode.*/ \ + uint32_t ssmpr[2]; \ + /* Slave ADC SQRx register initialization data. \ + NOTE: This field is only present in dual mode.*/ \ + uint32_t ssqr[4] +#else /* STM32_ADC_DUAL_MODE == FALSE */ +#define adc_lld_configuration_group_fields \ + uint32_t cfgr; \ + uint32_t cfgr2; \ + uint32_t tr1; \ + uint32_t tr2; \ + uint32_t tr3; \ + uint32_t awd2cr; \ + uint32_t awd3cr; \ + uint32_t smpr[2]; \ + uint32_t sqr[4] +#endif /* STM32_ADC_DUAL_MODE == FALSE */ + +#else /* STM32_ADCV3_OVERSAMPLING == FALSE */ +#if (STM32_ADC_DUAL_MODE == TRUE) || defined(__DOXYGEN__) +#define adc_lld_configuration_group_fields \ + uint32_t cfgr; \ + uint32_t tr1; \ + uint32_t tr2; \ + uint32_t tr3; \ + uint32_t awd2cr; \ + uint32_t awd3cr; \ + uint32_t ccr; \ + uint32_t smpr[2]; \ + uint32_t sqr[4]; \ + uint32_t ssmpr[2]; \ + uint32_t ssqr[4] +#else /* STM32_ADC_DUAL_MODE == FALSE */ +#define adc_lld_configuration_group_fields \ + uint32_t cfgr; \ + uint32_t tr1; \ + uint32_t tr2; \ + uint32_t tr3; \ + uint32_t awd2cr; \ + uint32_t awd3cr; \ + uint32_t smpr[2]; \ + uint32_t sqr[4] +#endif /* STM32_ADC_DUAL_MODE == FALSE */ +#endif /* STM32_ADCV3_OVERSAMPLING == FALSE */ + +/** + * @name Threshold registers initializers + * @{ + */ +#define ADC_TR(low, high) (((uint32_t)(high) << 16) | (uint32_t)(low)) +#define ADC_TR_DISABLED ADC_TR(0U, 0x0FFFU) +#define ADC_AWDCR_ENABLE(n) (1U << (n)) +/** @} */ + +/** + * @name Sequences building helper macros + * @{ + */ +/** + * @brief Number of channels in a conversion sequence. + */ +#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 0) + +#define ADC_SQR1_SQ1_N(n) ((n) << 6) /**< @brief 1st channel in seq. */ +#define ADC_SQR1_SQ2_N(n) ((n) << 12) /**< @brief 2nd channel in seq. */ +#define ADC_SQR1_SQ3_N(n) ((n) << 18) /**< @brief 3rd channel in seq. */ +#define ADC_SQR1_SQ4_N(n) ((n) << 24) /**< @brief 4th channel in seq. */ + +#define ADC_SQR2_SQ5_N(n) ((n) << 0) /**< @brief 5th channel in seq. */ +#define ADC_SQR2_SQ6_N(n) ((n) << 6) /**< @brief 6th channel in seq. */ +#define ADC_SQR2_SQ7_N(n) ((n) << 12) /**< @brief 7th channel in seq. */ +#define ADC_SQR2_SQ8_N(n) ((n) << 18) /**< @brief 8th channel in seq. */ +#define ADC_SQR2_SQ9_N(n) ((n) << 24) /**< @brief 9th channel in seq. */ + +#define ADC_SQR3_SQ10_N(n) ((n) << 0) /**< @brief 10th channel in seq.*/ +#define ADC_SQR3_SQ11_N(n) ((n) << 6) /**< @brief 11th channel in seq.*/ +#define ADC_SQR3_SQ12_N(n) ((n) << 12) /**< @brief 12th channel in seq.*/ +#define ADC_SQR3_SQ13_N(n) ((n) << 18) /**< @brief 13th channel in seq.*/ +#define ADC_SQR3_SQ14_N(n) ((n) << 24) /**< @brief 14th channel in seq.*/ + +#define ADC_SQR4_SQ15_N(n) ((n) << 0) /**< @brief 15th channel in seq.*/ +#define ADC_SQR4_SQ16_N(n) ((n) << 6) /**< @brief 16th channel in seq.*/ +/** @} */ + +/** + * @name Sampling rate settings helper macros + * @{ + */ +#define ADC_SMPR1_SMP_AN0(n) ((n) << 0) /**< @brief AN0 sampling time. */ +#define ADC_SMPR1_SMP_AN1(n) ((n) << 3) /**< @brief AN1 sampling time. */ +#define ADC_SMPR1_SMP_AN2(n) ((n) << 6) /**< @brief AN2 sampling time. */ +#define ADC_SMPR1_SMP_AN3(n) ((n) << 9) /**< @brief AN3 sampling time. */ +#define ADC_SMPR1_SMP_AN4(n) ((n) << 12) /**< @brief AN4 sampling time. */ +#define ADC_SMPR1_SMP_AN5(n) ((n) << 15) /**< @brief AN5 sampling time. */ +#define ADC_SMPR1_SMP_AN6(n) ((n) << 18) /**< @brief AN6 sampling time. */ +#define ADC_SMPR1_SMP_AN7(n) ((n) << 21) /**< @brief AN7 sampling time. */ +#define ADC_SMPR1_SMP_AN8(n) ((n) << 24) /**< @brief AN8 sampling time. */ +#define ADC_SMPR1_SMP_AN9(n) ((n) << 27) /**< @brief AN9 sampling time. */ + +#define ADC_SMPR2_SMP_AN10(n) ((n) << 0) /**< @brief AN10 sampling time. */ +#define ADC_SMPR2_SMP_AN11(n) ((n) << 3) /**< @brief AN11 sampling time. */ +#define ADC_SMPR2_SMP_AN12(n) ((n) << 6) /**< @brief AN12 sampling time. */ +#define ADC_SMPR2_SMP_AN13(n) ((n) << 9) /**< @brief AN13 sampling time. */ +#define ADC_SMPR2_SMP_AN14(n) ((n) << 12) /**< @brief AN14 sampling time. */ +#define ADC_SMPR2_SMP_AN15(n) ((n) << 15) /**< @brief AN15 sampling time. */ +#define ADC_SMPR2_SMP_AN16(n) ((n) << 18) /**< @brief AN16 sampling time. */ +#define ADC_SMPR2_SMP_AN17(n) ((n) << 21) /**< @brief AN17 sampling time. */ +#define ADC_SMPR2_SMP_AN18(n) ((n) << 24) /**< @brief AN18 sampling time. */ +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 && !defined(__DOXYGEN__) +extern ADCDriver ADCD1; +#endif + +#if STM32_ADC_USE_ADC2 && !defined(__DOXYGEN__) +extern ADCDriver ADCD2; +#endif + +#if STM32_ADC_USE_ADC3 && !defined(__DOXYGEN__) +extern ADCDriver ADCD3; +#endif + +#if STM32_ADC_USE_ADC4 && !defined(__DOXYGEN__) +extern ADCDriver ADCD4; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void adc_lld_init(void); + void adc_lld_start(ADCDriver *adcp); + void adc_lld_stop(ADCDriver *adcp); + void adc_lld_start_conversion(ADCDriver *adcp); + void adc_lld_stop_conversion(ADCDriver *adcp); + void adcSTM32EnableVREF(ADCDriver *adcp); + void adcSTM32DisableVREF(ADCDriver *adcp); + void adcSTM32EnableTS(ADCDriver *adcp); + void adcSTM32DisableTS(ADCDriver *adcp); + void adcSTM32EnableVBAT(ADCDriver *adcp); + void adcSTM32DisableVBAT(ADCDriver *adcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_ADC */ + +#endif /* HAL_ADC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/notes.txt new file mode 100644 index 0000000..fbfe6c2 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/notes.txt @@ -0,0 +1,22 @@ +STM32 ADCv3 driver. + +Driver capability: + +- Supports the STM32 "fast" ADC found on F3, L4, L4+ and G4 sub-families. + +The file registry must export: + +STM32_HAS_ADCx - ADCx presence flag (1..4). +STM32_ADC1_HANDLER - IRQ vector name for ADC1. +STM32_ADC1_NUMBER - IRQ vector number for ADC1. +STM32_ADC2_HANDLER - IRQ vector name for ADC2. +STM32_ADC2_NUMBER - IRQ vector number for ADC2. +STM32_ADC3_HANDLER - IRQ vector name for ADC3. +STM32_ADC3_NUMBER - IRQ vector number for ADC3. +STM32_ADC4_HANDLER - IRQ vector name for ADC4. +STM32_ADC4_NUMBER - IRQ vector number for ADC4. + +If there is no DMAMUX then the file registry must export also: + +STM32_ADCx_DMA_MSK - Mask of the compatible DMA channels (1..4). +STM32_ADCx_DMA_CHN - Mask of the channels mapping (1..4). diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/driver.mk new file mode 100644 index 0000000..91bc885 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv4 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c new file mode 100644 index 0000000..2b85dbd --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c @@ -0,0 +1,822 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv4/hal_adc_lld.c + * @brief STM32 ADC subsystem low level driver source. + * + * @addtogroup ADC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if STM32_ADC_DUAL_MODE == TRUE +#if STM32_ADC_COMPACT_SAMPLES == TRUE +/* Compact type dual mode, 2x8-bit.*/ +#define ADC12_DMA_SIZE (STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD) +#define ADC3_BDMA_SIZE (STM32_BDMA_CR_MSIZE_BYTE | STM32_BDMA_CR_PSIZE_BYTE) +#define ADC_DMA_DAMDF ADC_CCR_DAMDF_BYTE + +#else /* STM32_ADC_COMPACT_SAMPLES == FALSE */ +/* Large type dual mode, 2x16bit.*/ +#define ADC12_DMA_SIZE (STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD) +#define ADC3_BDMA_SIZE (STM32_BDMA_CR_MSIZE_HWORD | STM32_BDMA_CR_PSIZE_HWORD) +#define ADC_DMA_DAMDF ADC_CCR_DAMDF_HWORD +#endif /* !STM32_ADC_COMPACT_SAMPLES */ + +#else /* STM32_ADC_DUAL_MODE == FALSE */ +#if STM32_ADC_COMPACT_SAMPLES +/* Compact type single mode, 8-bit.*/ +#define ADC12_DMA_SIZE (STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_PSIZE_BYTE) +#define ADC3_BDMA_SIZE (STM32_BDMA_CR_MSIZE_BYTE | STM32_BDMA_CR_PSIZE_BYTE) +#define ADC_DMA_DAMDF ADC_CCR_DAMDF_DISABLED + +#else /* STM32_ADC_COMPACT_SAMPLES == FALSE */ +/* Large type single mode, 16-bit.*/ +#define ADC12_DMA_SIZE (STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD) +#define ADC3_BDMA_SIZE (STM32_BDMA_CR_MSIZE_HWORD | STM32_BDMA_CR_PSIZE_HWORD) +#define ADC_DMA_DAMDF ADC_CCR_DAMDF_DISABLED +#endif /* STM32_ADC_COMPACT_SAMPLES == FALSE */ +#endif /* STM32_ADC_DUAL_MODE == FALSE */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief ADC1 driver identifier.*/ +#if STM32_ADC_USE_ADC12 || defined(__DOXYGEN__) +ADCDriver ADCD1; +#endif + +/** @brief ADC3 driver identifier.*/ +#if STM32_ADC_USE_ADC3 || defined(__DOXYGEN__) +ADCDriver ADCD3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const ADCConfig default_config = { + .difsel = 0U +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Enables the ADC voltage regulator. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_vreg_on(ADCDriver *adcp) { + + adcp->adcm->CR = ADC_CR_ADVREGEN; +#if STM32_ADC_DUAL_MODE + if (&ADCD1 == adcp) { + adcp->adcs->CR = ADC_CR_ADVREGEN; + } +#endif + osalSysPolledDelayX(OSAL_US2RTC(STM32_SYS_CK, 10U)); +} + +/** + * @brief Disables the ADC voltage regulator. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_vreg_off(ADCDriver *adcp) { + + adcp->adcm->CR = ADC_CR_DEEPPWD; +#if STM32_ADC_DUAL_MODE + if (&ADCD1 == adcp) { + adcp->adcs->CR = ADC_CR_DEEPPWD; + } +#endif +} + +/** + * @brief Enables the ADC analog circuit. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_analog_on(ADCDriver *adcp) { + + adcp->adcm->ISR = ADC_ISR_ADRDY; + adcp->adcm->CR |= ADC_CR_ADEN; + while ((adcp->adcm->ISR & ADC_ISR_ADRDY) == 0U) + ; +#if STM32_ADC_DUAL_MODE + if (&ADCD1 == adcp) { + adcp->adcs->ISR = ADC_ISR_ADRDY; + adcp->adcs->CR |= ADC_CR_ADEN; + while ((adcp->adcs->ISR & ADC_ISR_ADRDY) == 0U) + ; + } +#endif +} + +/** + * @brief Disables the ADC analog circuit. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_analog_off(ADCDriver *adcp) { + + adcp->adcm->CR |= ADC_CR_ADDIS; + while ((adcp->adcm->CR & ADC_CR_ADDIS) != 0U) + ; +#if STM32_ADC_DUAL_MODE + if (&ADCD1 == adcp) { + adcp->adcs->CR |= ADC_CR_ADDIS; + while ((adcp->adcs->CR & ADC_CR_ADDIS) != 0U) + ; + } +#endif +} + +/** + * @brief Calibrates and ADC unit. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_calibrate(ADCDriver *adcp) { + + osalDbgAssert(adcp->adcm->CR == ADC_CR_ADVREGEN, "invalid register state"); + + adcp->adcm->CR &= ~(ADC_CR_ADCALDIF | ADC_CR_ADCALLIN); + adcp->adcm->CR |= adcp->config->calibration & (ADC_CR_ADCALDIF | + ADC_CR_ADCALLIN); + adcp->adcm->CR |= ADC_CR_ADCAL; + while ((adcp->adcm->CR & ADC_CR_ADCAL) != 0U) + ; +#if STM32_ADC_DUAL_MODE + if (&ADCD1 == adcp) { + osalDbgAssert(adcp->adcs->CR == ADC_CR_ADVREGEN, "invalid register state"); + + adcp->adcs->CR &= ~(ADC_CR_ADCALDIF | ADC_CR_ADCALLIN); + adcp->adcs->CR |= adcp->config->calibration & (ADC_CR_ADCALDIF | + ADC_CR_ADCALLIN); + adcp->adcs->CR |= ADC_CR_ADCAL; + while ((adcp->adcs->CR & ADC_CR_ADCAL) != 0U) + ; + } +#endif +} + +/** + * @brief Stops an ongoing conversion, if any. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_lld_stop_adc(ADCDriver *adcp) { + + if (adcp->adcm->CR & ADC_CR_ADSTART) { + adcp->adcm->CR |= ADC_CR_ADSTP; + while (adcp->adcm->CR & ADC_CR_ADSTP) + ; + } +#if !defined(STM32H723xx) || STM32_ADC_USE_ADC3 == FALSE + adcp->adcm->PCSEL = 0U; +#endif +} + +#if (STM32_ADC_USE_ADC12 == TRUE) || defined(__DOXYGEN__) +/** + * @brief ADC DMA service routine. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void adc_lld_serve_dma_interrupt(ADCDriver *adcp, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + /* DMA, this could help only if the DMA tries to access an unmapped + address space or violates alignment rules.*/ + _adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE); + } + else { + /* It is possible that the conversion group has already be reset by the + ADC error handler, in this case this interrupt is spurious.*/ + if (adcp->grpp != NULL) { + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } + else if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + } + } +} +#endif /* STM32_ADC_USE_ADC12 == TRUE */ + +#if (STM32_ADC_USE_ADC3 == TRUE) || defined(__DOXYGEN__) +/** + * @brief ADC BDMA service routine. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void adc_lld_serve_bdma_interrupt(ADCDriver *adcp, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & STM32_BDMA_ISR_TEIF) != 0) { + /* DMA, this could help only if the DMA tries to access an unmapped + address space or violates alignment rules.*/ + _adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE); + } + else { + /* It is possible that the conversion group has already be reset by the + ADC error handler, in this case this interrupt is spurious.*/ + if (adcp->grpp != NULL) { + if ((flags & STM32_BDMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } + else if ((flags & STM32_BDMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + } + } +} +#endif /* STM32_ADC_USE_ADC3 == TRUE */ + +/** + * @brief ADC IRQ service routine. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] isr content of the ISR register + */ +static void adc_lld_serve_interrupt(ADCDriver *adcp, uint32_t isr) { + + /* It could be a spurious interrupt caused by overflows after DMA disabling, + just ignore it in this case.*/ + if (adcp->grpp != NULL) { + /* Note, an overflow may occur after the conversion ended before the driver + is able to stop the ADC, this is why the state is checked too.*/ + if ((isr & ADC_ISR_OVR) && (adcp->state == ADC_ACTIVE)) { + /* ADC overflow condition, this could happen only if the DMA is unable + to read data fast enough.*/ + _adc_isr_error_code(adcp, ADC_ERR_OVERFLOW); + } + if (isr & ADC_ISR_AWD1) { + /* Analog watchdog error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD1); + } + if (isr & ADC_ISR_AWD2) { + /* Analog watchdog error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD2); + } + if (isr & ADC_ISR_AWD3) { + /* Analog watchdog error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD3); + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (STM32_ADC_USE_ADC12 == TRUE) || defined(__DOXYGEN__) +/** + * @brief ADC1/ADC2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_ADC12_HANDLER) { + uint32_t isr; + + OSAL_IRQ_PROLOGUE(); + + isr = ADC1->ISR; +#if STM32_ADC_DUAL_MODE + isr |= ADC2->ISR; +#endif + ADC1->ISR = isr; +#if STM32_ADC_DUAL_MODE + ADC2->ISR = isr; +#endif +#if defined(STM32_ADC_ADC12_IRQ_HOOK) + STM32_ADC_ADC12_IRQ_HOOK +#endif + adc_lld_serve_interrupt(&ADCD1, isr); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_ADC_USE_ADC12 == TRUE */ + +#if (STM32_ADC_USE_ADC3 == TRUE) || defined(__DOXYGEN__) +/** + * @brief ADC3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_ADC3_HANDLER) { + uint32_t isr; + + OSAL_IRQ_PROLOGUE(); + + isr = ADC3->ISR; + ADC3->ISR = isr; +#if defined(STM32_ADC_ADC3_IRQ_HOOK) + STM32_ADC_ADC3_IRQ_HOOK +#endif + adc_lld_serve_interrupt(&ADCD3, isr); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_ADC_USE_ADC3 == TRUE */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ADC driver initialization. + * + * @notapi + */ +void adc_lld_init(void) { + +#if STM32_ADC_USE_ADC12 == TRUE + /* Driver initialization.*/ + adcObjectInit(&ADCD1); + ADCD1.adcc = ADC12_COMMON; + ADCD1.adcm = ADC1; +#if STM32_ADC_DUAL_MODE + ADCD1.adcs = ADC2; +#endif + ADCD1.data.dma = NULL; + ADCD1.dmamode = ADC12_DMA_SIZE | + STM32_DMA_CR_PL(STM32_ADC_ADC12_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + nvicEnableVector(STM32_ADC12_NUMBER, STM32_ADC_ADC12_IRQ_PRIORITY); +#endif /* STM32_ADC_USE_ADC12 == TRUE */ + +#if STM32_ADC_USE_ADC3 == TRUE + /* Driver initialization.*/ + adcObjectInit(&ADCD3); + ADCD3.adcc = ADC3_COMMON; + ADCD3.adcm = ADC3; + ADCD3.data.bdma = NULL; + ADCD3.dmamode = ADC3_BDMA_SIZE | + STM32_BDMA_CR_PL(STM32_ADC_ADC3_DMA_PRIORITY) | + STM32_BDMA_CR_DIR_P2M | + STM32_BDMA_CR_MINC | STM32_BDMA_CR_TCIE | + STM32_BDMA_CR_TEIE; + nvicEnableVector(STM32_ADC3_NUMBER, STM32_ADC_ADC3_IRQ_PRIORITY); +#endif /* STM32_ADC_USE_ADC3 == TRUE */ + + /* ADC units pre-initializations.*/ +#if (STM32_HAS_ADC1 == TRUE) && (STM32_HAS_ADC2 == TRUE) +#if STM32_ADC_USE_ADC12 == TRUE + rccEnableADC12(true); + rccResetADC12(); + ADC12_COMMON->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_DAMDF; + rccDisableADC12(); +#endif +#if STM32_ADC_USE_ADC3 == TRUE + rccEnableADC3(true); + rccResetADC3(); + ADC3_COMMON->CCR = STM32_ADC_ADC3_CLOCK_MODE | STM32_ADC_ADC3_PRESC; + rccDisableADC3(); +#endif +#endif +} + +/** + * @brief Configures and activates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start(ADCDriver *adcp) { + + /* Handling the default configuration.*/ + if (adcp->config == NULL) { + adcp->config = &default_config; + } + + /* If in stopped state then enables the ADC and DMA clocks.*/ + if (adcp->state == ADC_STOP) { +#if STM32_ADC_USE_ADC12 == TRUE + if (&ADCD1 == adcp) { + adcp->data.dma = dmaStreamAllocI(STM32_ADC_ADC12_DMA_STREAM, + STM32_ADC_ADC12_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->data.dma != NULL, "unable to allocate stream"); + rccEnableADC12(true); + dmaSetRequestSource(adcp->data.dma, STM32_DMAMUX1_ADC1); + + /* Setting DMA peripheral-side pointer.*/ +#if STM32_ADC_DUAL_MODE + dmaStreamSetPeripheral(adcp->data.dma, &adcp->adcc->CDR); +#else + dmaStreamSetPeripheral(adcp->data.dma, &adcp->adcm->DR); +#endif + + /* Differential channels setting.*/ +#if STM32_ADC_DUAL_MODE + adcp->adcm->DIFSEL = adcp->config->difsel; + adcp->adcs->DIFSEL = adcp->config->difsel; +#else + adcp->adcm->DIFSEL = adcp->config->difsel; +#endif + } +#endif /* STM32_ADC_USE_ADC12 == TRUE */ + +#if STM32_ADC_USE_ADC3 == TRUE + if (&ADCD3 == adcp) { + adcp->data.bdma = bdmaStreamAllocI(STM32_ADC_ADC3_BDMA_STREAM, + STM32_ADC_ADC3_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_bdma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->data.bdma != NULL, "unable to allocate stream"); + rccEnableADC3(true); + bdmaSetRequestSource(adcp->data.bdma, STM32_DMAMUX2_ADC3_REQ); + + /* Setting DMA peripheral-side pointer.*/ + bdmaStreamSetPeripheral(adcp->data.bdma, &adcp->adcm->DR); + + /* Differential channels setting.*/ + adcp->adcm->DIFSEL = adcp->config->difsel; + } +#endif /* STM32_ADC_USE_ADC3 == TRUE */ + + /* Master ADC calibration.*/ + adc_lld_vreg_on(adcp); + adc_lld_calibrate(adcp); + + /* Configure the ADC boost. */ +#if STM32_ADC_USE_ADC12 == TRUE + if (&ADCD1 == adcp) { + adcp->adcm->CR |= STM32_ADC12_BOOST; +#if STM32_ADC_DUAL_MODE + adcp->adcs->CR |= STM32_ADC12_BOOST; +#endif + } +#endif + +#if STM32_ADC_USE_ADC3 == TRUE + if (&ADCD3 == adcp) { + adcp->adcm->CR |= STM32_ADC3_BOOST; + } +#endif + + /* Master ADC enabled here in order to reduce conversions latencies.*/ + adc_lld_analog_on(adcp); + } +} + +/** + * @brief Deactivates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop(ADCDriver *adcp) { + + /* If in ready state then disables the ADC clock and analog part.*/ + if (adcp->state == ADC_READY) { + + /* Stopping the ongoing conversion, if any.*/ + adc_lld_stop_adc(adcp); + + /* Disabling ADC analog circuit and regulator.*/ + adc_lld_analog_off(adcp); + adc_lld_vreg_off(adcp); + +#if STM32_ADC_USE_ADC12 == TRUE + if (&ADCD1 == adcp) { + + /* Releasing the associated DMA channel.*/ + dmaStreamFreeI(adcp->data.dma); + adcp->data.dma = NULL; + + /* Resetting CCR options except default ones.*/ + adcp->adcc->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_DAMDF; + rccDisableADC12(); + } +#endif + +#if STM32_ADC_USE_ADC3 == TRUE + if (&ADCD3 == adcp) { + + /* Releasing the associated BDMA channel.*/ + bdmaStreamFreeI(adcp->data.bdma); + adcp->data.bdma = NULL; + + /* Resetting CCR options except default ones.*/ + adcp->adcc->CCR = STM32_ADC_ADC3_CLOCK_MODE | STM32_ADC_ADC3_PRESC; + rccDisableADC3(); + } +#endif + } +} + +/** + * @brief Starts an ADC conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start_conversion(ADCDriver *adcp) { + uint32_t dmamode, cfgr; + const ADCConversionGroup *grpp = adcp->grpp; + +#if STM32_ADC_USE_ADC12 == TRUE +#if STM32_ADC_DUAL_MODE + uint32_t ccr; +#endif + if (&ADCD1 == adcp) { +#if STM32_ADC_DUAL_MODE + ccr = grpp->ccr & ~(ADC_CCR_CKMODE_MASK | ADC_CCR_DAMDF_MASK); + osalDbgAssert(!STM32_ADC_DUAL_MODE || ((grpp->num_channels & 1) == 0), + "odd number of channels in dual mode"); +#endif + + /* Calculating control registers values.*/ + dmamode = adcp->dmamode; + if (grpp->circular) { + dmamode |= STM32_DMA_CR_CIRC; + cfgr = grpp->cfgr | ADC_CFGR_DMNGT_CIRCULAR; + if (adcp->depth > 1) { + /* If circular buffer depth > 1, then the half transfer interrupt + is enabled in order to allow streaming processing.*/ + dmamode |= STM32_DMA_CR_HTIE; + } + } + else { + cfgr = grpp->cfgr | ADC_CFGR_DMNGT_ONESHOT; + } + + /* DMA setup.*/ + dmaStreamSetMemory0(adcp->data.dma, adcp->samples); +#if STM32_ADC_DUAL_MODE + dmaStreamSetTransactionSize(adcp->data.dma, ((uint32_t)grpp->num_channels / 2U) * + (uint32_t)adcp->depth); +#else + dmaStreamSetTransactionSize(adcp->data.dma, (uint32_t)grpp->num_channels * + (uint32_t)adcp->depth); +#endif + dmaStreamSetMode(adcp->data.dma, dmamode); + dmaStreamEnable(adcp->data.dma); + } +#endif /* STM32_ADC_USE_ADC12 == TRUE */ + +#if STM32_ADC_USE_ADC3 == TRUE + if (&ADCD3 == adcp) { + /* Calculating control registers values.*/ + dmamode = adcp->dmamode; + if (grpp->circular) { + dmamode |= STM32_BDMA_CR_CIRC; + cfgr = grpp->cfgr | ADC_CFGR_DMNGT_CIRCULAR; + if (adcp->depth > 1) { + /* If circular buffer depth > 1, then the half transfer interrupt + is enabled in order to allow streaming processing.*/ + dmamode |= STM32_BDMA_CR_HTIE; + } + } + else { + cfgr = grpp->cfgr | ADC_CFGR_DMNGT_ONESHOT; + } + + /* DMA setup.*/ + bdmaStreamSetMemory(adcp->data.bdma, adcp->samples); + bdmaStreamSetTransactionSize(adcp->data.bdma, (uint32_t)grpp->num_channels * + (uint32_t)adcp->depth); + bdmaStreamSetMode(adcp->data.bdma, dmamode); + bdmaStreamEnable(adcp->data.bdma); + } +#endif /* STM32_ADC_USE_ADC3 == TRUE */ + + /* ADC setup, if it is defined a callback for the analog watch dog then it + is enabled.*/ + adcp->adcm->ISR = adcp->adcm->ISR; + adcp->adcm->IER = ADC_IER_OVRIE | ADC_IER_AWD1IE; +#if STM32_ADC_DUAL_MODE == TRUE && STM32_ADC_USE_ADC12 == TRUE + /* Configuration for dual mode ADC12 */ + if (&ADCD1 == adcp) { + /* Configuring the CCR register with the user-specified settings + in the conversion group configuration structure, static settings are + preserved.*/ + adcp->adcc->CCR = (adcp->adcc->CCR & + (ADC_CCR_CKMODE_MASK | ADC_CCR_DAMDF_MASK)) | ccr; + + adcp->adcm->CFGR2 = grpp->cfgr2; + adcp->adcm->PCSEL = grpp->pcsel; + adcp->adcm->LTR1 = grpp->ltr1; + adcp->adcm->HTR1 = grpp->htr1; + adcp->adcm->LTR2 = grpp->ltr2; + adcp->adcm->HTR2 = grpp->htr2; + adcp->adcm->LTR3 = grpp->ltr3; + adcp->adcm->HTR3 = grpp->htr3; + adcp->adcm->SMPR1 = grpp->smpr[0]; + adcp->adcm->SMPR2 = grpp->smpr[1]; + adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2); + adcp->adcm->SQR2 = grpp->sqr[1]; + adcp->adcm->SQR3 = grpp->sqr[2]; + adcp->adcm->SQR4 = grpp->sqr[3]; + adcp->adcs->CFGR2 = grpp->cfgr2; + adcp->adcs->PCSEL = grpp->pcsel; + adcp->adcs->LTR1 = grpp->ltr1; + adcp->adcs->HTR1 = grpp->htr1; + adcp->adcs->LTR2 = grpp->ltr2; + adcp->adcs->HTR2 = grpp->htr2; + adcp->adcs->LTR3 = grpp->ltr3; + adcp->adcs->HTR3 = grpp->htr3; + adcp->adcs->SMPR1 = grpp->ssmpr[0]; + adcp->adcs->SMPR2 = grpp->ssmpr[1]; + adcp->adcs->SQR1 = grpp->ssqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2); + adcp->adcs->SQR2 = grpp->ssqr[1]; + adcp->adcs->SQR3 = grpp->ssqr[2]; + adcp->adcs->SQR4 = grpp->ssqr[3]; + + /* ADC configuration.*/ + adcp->adcm->CFGR = cfgr; + adcp->adcs->CFGR = cfgr; + } + +#endif /* STM32_ADC_DUAL_MODE == TRUE && STM32_ADC_USE_ADC12 == TRUE */ + +#if STM32_ADC_DUAL_MODE == FALSE || STM32_ADC_USE_ADC3 == TRUE + /* Configuration for ADC3 and single mode ADC1 */ +#if STM32_ADC_DUAL_MODE == TRUE && STM32_ADC_USE_ADC3 == TRUE + if (&ADCD3 == adcp) +#endif + { + adcp->adcm->CFGR2 = grpp->cfgr2; +#if !defined(STM32H723xx) || STM32_ADC_USE_ADC3 == FALSE + adcp->adcm->PCSEL = grpp->pcsel; +#endif + adcp->adcm->LTR1 = grpp->ltr1; + adcp->adcm->HTR1 = grpp->htr1; + adcp->adcm->LTR2 = grpp->ltr2; + adcp->adcm->HTR2 = grpp->htr2; + adcp->adcm->LTR3 = grpp->ltr3; + adcp->adcm->HTR3 = grpp->htr3; + adcp->adcm->SMPR1 = grpp->smpr[0]; + adcp->adcm->SMPR2 = grpp->smpr[1]; + adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels); + adcp->adcm->SQR2 = grpp->sqr[1]; + adcp->adcm->SQR3 = grpp->sqr[2]; + adcp->adcm->SQR4 = grpp->sqr[3]; + + /* ADC configuration.*/ + adcp->adcm->CFGR = cfgr; + } +#endif + + /* Starting conversion.*/ + adcp->adcm->CR |= ADC_CR_ADSTART; +} + +/** + * @brief Stops an ongoing conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop_conversion(ADCDriver *adcp) { + +#if STM32_ADC_USE_ADC12 == TRUE + if (&ADCD1 == adcp) { + dmaStreamDisable(adcp->data.dma); + } +#endif /* STM32_ADC_USE_ADC12 == TRUE */ + +#if STM32_ADC_USE_ADC3 == TRUE + if (&ADCD3 == adcp) { + bdmaStreamDisable(adcp->data.bdma); + } +#endif /* STM32_ADC_USE_ADC12 == TRUE */ + + adc_lld_stop_adc(adcp); +} + +/** + * @brief Enables the VREFEN bit. + * @details The VREFEN bit is required in order to sample the VREF channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableVREF(ADCDriver *adcp) { + + adcp->adcc->CCR |= ADC_CCR_VREFEN; +} + +/** + * @brief Disables the VREFEN bit. + * @details The VREFEN bit is required in order to sample the VREF channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableVREF(ADCDriver *adcp) { + + adcp->adcc->CCR &= ~ADC_CCR_VREFEN; +} + +/** + * @brief Enables the TSEN bit. + * @details The TSEN bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableTS(ADCDriver *adcp) { + + adcp->adcc->CCR |= ADC_CCR_TSEN; +} + +/** + * @brief Disables the TSEN bit. + * @details The TSEN bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableTS(ADCDriver *adcp) { + + adcp->adcc->CCR &= ~ADC_CCR_TSEN; +} + +/** + * @brief Enables the VBATEN bit. + * @details The VBATEN bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableVBAT(ADCDriver *adcp) { + + adcp->adcc->CCR |= ADC_CCR_VBATEN; +} + +/** + * @brief Disables the VBATEN bit. + * @details The VBATEN bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableVBAT(ADCDriver *adcp) { + + adcp->adcc->CCR &= ~ADC_CCR_VBATEN; +} + +#endif /* HAL_USE_ADC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h new file mode 100644 index 0000000..5f3cf46 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h @@ -0,0 +1,737 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv4/hal_adc_lld.h + * @brief STM32 ADC subsystem low level driver header. + * + * @addtogroup ADC + * @{ + */ + +#ifndef HAL_ADC_LLD_H +#define HAL_ADC_LLD_H + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Available analog channels + * @{ + */ +#define ADC_CHANNEL_IN0 0U /**< @brief External analog input 0. */ +#define ADC_CHANNEL_IN1 1U /**< @brief External analog input 1. */ +#define ADC_CHANNEL_IN2 2U /**< @brief External analog input 2. */ +#define ADC_CHANNEL_IN3 3U /**< @brief External analog input 3. */ +#define ADC_CHANNEL_IN4 4U /**< @brief External analog input 4. */ +#define ADC_CHANNEL_IN5 5U /**< @brief External analog input 5. */ +#define ADC_CHANNEL_IN6 6U /**< @brief External analog input 6. */ +#define ADC_CHANNEL_IN7 7U /**< @brief External analog input 7. */ +#define ADC_CHANNEL_IN8 8U /**< @brief External analog input 8. */ +#define ADC_CHANNEL_IN9 9U /**< @brief External analog input 9. */ +#define ADC_CHANNEL_IN10 10U /**< @brief External analog input 10. */ +#define ADC_CHANNEL_IN11 11U /**< @brief External analog input 11. */ +#define ADC_CHANNEL_IN12 12U /**< @brief External analog input 12. */ +#define ADC_CHANNEL_IN13 13U /**< @brief External analog input 13. */ +#define ADC_CHANNEL_IN14 14U /**< @brief External analog input 14. */ +#define ADC_CHANNEL_IN15 15U /**< @brief External analog input 15. */ +#define ADC_CHANNEL_IN16 16U /**< @brief External analog input 16. */ +#define ADC_CHANNEL_IN17 17U /**< @brief External analog input 17. */ +#define ADC_CHANNEL_IN18 18U /**< @brief External analog input 18. */ +#define ADC_CHANNEL_IN19 19U /**< @brief External analog input 19. */ +/** @} */ + +/** + * @name ADC channels selection masks + * @{ + */ +#define ADC_SELMASK_IN0 (1U << ADC_CHANNEL_IN0) +#define ADC_SELMASK_IN1 (1U << ADC_CHANNEL_IN1) +#define ADC_SELMASK_IN2 (1U << ADC_CHANNEL_IN2) +#define ADC_SELMASK_IN3 (1U << ADC_CHANNEL_IN3) +#define ADC_SELMASK_IN4 (1U << ADC_CHANNEL_IN4) +#define ADC_SELMASK_IN5 (1U << ADC_CHANNEL_IN5) +#define ADC_SELMASK_IN6 (1U << ADC_CHANNEL_IN6) +#define ADC_SELMASK_IN7 (1U << ADC_CHANNEL_IN7) +#define ADC_SELMASK_IN8 (1U << ADC_CHANNEL_IN8) +#define ADC_SELMASK_IN9 (1U << ADC_CHANNEL_IN9) +#define ADC_SELMASK_IN10 (1U << ADC_CHANNEL_IN10) +#define ADC_SELMASK_IN11 (1U << ADC_CHANNEL_IN11) +#define ADC_SELMASK_IN12 (1U << ADC_CHANNEL_IN12) +#define ADC_SELMASK_IN13 (1U << ADC_CHANNEL_IN13) +#define ADC_SELMASK_IN14 (1U << ADC_CHANNEL_IN14) +#define ADC_SELMASK_IN15 (1U << ADC_CHANNEL_IN15) +#define ADC_SELMASK_IN16 (1U << ADC_CHANNEL_IN16) +#define ADC_SELMASK_IN17 (1U << ADC_CHANNEL_IN17) +#define ADC_SELMASK_IN18 (1U << ADC_CHANNEL_IN18) +#define ADC_SELMASK_IN19 (1U << ADC_CHANNEL_IN19) +/** @} */ + +/** + * @name Sampling rates + * @{ + */ +#if defined(STM32H7XX) +#if !defined(STM32H723xx) || STM32_ADC_USE_ADC3 == FALSE +#define ADC_SMPR_SMP_1P5 0U /**< @brief 9 cycles conversion time */ +#define ADC_SMPR_SMP_2P5 1U /**< @brief 10 cycles conversion time. */ +#define ADC_SMPR_SMP_8P5 2U /**< @brief 16 cycles conversion time. */ +#define ADC_SMPR_SMP_16P5 3U /**< @brief 24 cycles conversion time. */ +#define ADC_SMPR_SMP_32P5 4U /**< @brief 40 cycles conversion time. */ +#define ADC_SMPR_SMP_64P5 5U /**< @brief 72 cycles conversion time. */ +#define ADC_SMPR_SMP_384P5 6U /**< @brief 392 cycles conversion time. */ +#define ADC_SMPR_SMP_810P5 7U /**< @brief 818 cycles conversion time. */ +#else +#define ADC_SMPR_SMP_2P5 0U /**< @brief cycles conversion time */ +#define ADC_SMPR_SMP_6P5 1U /**< @brief cycles conversion time. */ +#define ADC_SMPR_SMP_12P5 2U /**< @brief cycles conversion time. */ +#define ADC_SMPR_SMP_24P5 3U /**< @brief cycles conversion time. */ +#define ADC_SMPR_SMP_47P5 4U /**< @brief cycles conversion time. */ +#define ADC_SMPR_SMP_92P5 5U /**< @brief cycles conversion time. */ +#define ADC_SMPR_SMP_247P5 6U /**< @brief cycles conversion time. */ +#define ADC_SMPR_SMP_640P5 7U /**< @brief cycles conversion time. */ +#endif +#endif +/** @} */ + +/** + * @name CFGR register configuration helpers + * @{ + */ +#define ADC_CFGR_DMNGT_MASK (3U << 0U) +#define ADC_CFGR_DMNGT_NODMA (0U << 0U) +#define ADC_CFGR_DMNGT_ONESHOT (1U << 0U) +#define ADC_CFGR_DMNGT_DFSDM (2U << 0U) +#define ADC_CFGR_DMNGT_CIRCULAR (3U << 0U) + +#define ADC_CFGR_RES_MASK (7U << 2U) +#define ADC_CFGR_RES_16BITS (0U << 2U) +#define ADC_CFGR_RES_10BITS (3U << 2U) +#if !defined(STM32_ENFORCE_H7_REV_XY) +#define ADC_CFGR_RES_14BITS (5U << 2U) +#define ADC_CFGR_RES_12BITS (6U << 2U) +#define ADC_CFGR_RES_8BITS (7U << 2U) +#else +#define ADC_CFGR_RES_14BITS (1U << 2U) +#define ADC_CFGR_RES_12BITS (2U << 2U) +#define ADC_CFGR_RES_8BITS (4U << 2U) +#endif + +#define ADC_CFGR_EXTSEL_MASK (15U << 5U) +#define ADC_CFGR_EXTSEL_SRC(n) ((n) << 5U) + +#define ADC_CFGR_EXTEN_MASK (3U << 10U) +#define ADC_CFGR_EXTEN_DISABLED (0U << 10U) +#define ADC_CFGR_EXTEN_RISING (1U << 10U) +#define ADC_CFGR_EXTEN_FALLING (2U << 10U) +#define ADC_CFGR_EXTEN_BOTH (3U << 10U) + +#define ADC_CFGR_DISCEN_MASK (1U << 16U) +#define ADC_CFGR_DISCEN_DISABLED (0U << 16U) +#define ADC_CFGR_DISCEN_ENABLED (1U << 16U) + +#define ADC_CFGR_DISCNUM_MASK (7U << 17U) +#define ADC_CFGR_DISCNUM_VAL(n) ((n) << 17U) +/** @} */ + +/** + * @name CCR register configuration helpers + * @{ + */ +#define ADC_CCR_DUAL_MASK (31U << 0U) +#define ADC_CCR_DUAL_FIELD(n) ((n) << 0U) +#define ADC_CCR_DUAL_INDEPENDENT (0U << 0U) /**< @brief Independent, dual mode disabled. */ +#define ADC_CCR_DUAL_REG_SIMULT (6U << 0U) /**< @brief Regular simultaneous. */ +#define ADC_CCR_DUAL_REG_INTERL (7U << 0U) /**< @brief Regular interleaved. */ +#define ADC_CCR_DUAL_INJ_SIMULT (5U << 0U) /**< @brief Injected simultaneous. */ +#define ADC_CCR_DUAL_INJ_ALTERNATE (9U << 0U) /**< @brief Injected alternate trigger. */ +#define ADC_CCR_DUAL_REG_SIM_INJ_SIM (1U << 0U) /**< @brief Combined regular simultaneous + injected simultaneous. */ +#define ADC_CCR_DUAL_REG_SIM_INJ_ALT (2U << 0U) /**< @brief Combined regular simultaneous + injected alternate trigger. */ +#define ADC_CCR_DUAL_REG_INT_INJ_SIM (3U << 0U) /**< @brief Combined regular interleaved + injected simultaneous. */ +#define ADC_CCR_DELAY_MASK (15U << 8U) +#define ADC_CCR_DELAY_FIELD(n) ((n) << 8U) +#define ADC_CCR_DAMDF_MASK (3U << 14U) +#define ADC_CCR_DAMDF_DISABLED (0U << 14U) +#define ADC_CCR_DAMDF_HWORD (2U << 14U) +#define ADC_CCR_DAMDF_BYTE (3U << 14U) +#define ADC_CCR_CKMODE_MASK (3U << 16U) +#define ADC_CCR_CKMODE_ADCCK (0U << 16U) +#define ADC_CCR_CKMODE_AHB_DIV1 (1U << 16U) +#define ADC_CCR_CKMODE_AHB_DIV2 (2U << 16U) +#define ADC_CCR_CKMODE_AHB_DIV4 (3U << 16U) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief Enables the ADC1 and ADC2 master/slave mode. + */ +#if !defined(STM32_ADC_DUAL_MODE) || defined(__DOXYGEN__) +#define STM32_ADC_DUAL_MODE FALSE +#endif + +/** + * @brief Makes the ADC samples type an 8bits one. + * @note 10, 12, 14 and 16 bits sampling mode must not be used when this + * option is enabled. + */ +#if !defined(STM32_ADC_COMPACT_SAMPLES) || defined(__DOXYGEN__) +#define STM32_ADC_COMPACT_SAMPLES FALSE +#endif + +/** + * @brief ADC1/ADC2 driver enable switch. + * @details If set to @p TRUE the support for ADC1/ADC2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC12) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC12 FALSE +#endif + +/** + * @brief ADC3 driver enable switch. + * @details If set to @p TRUE the support for ADC3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC3) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC3 FALSE +#endif + +/** + * @brief ADC1/ADC2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC12_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC3 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC1/ADC2 interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC12_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC3 interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_IRQ_PRIORITY 5 +#endif + +/** + * @brief ADC1/ADC2 clock source and mode. + */ +#if !defined(STM32_ADC_ADC12_CLOCK_MODE) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4 +#endif + +/** + * @brief ADC3 clock source and mode. + */ +#if !defined(STM32_ADC_ADC3_CLOCK_MODE) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Supported devices checks.*/ +#if !defined(STM32H7XX) +#error "ADCv4 only supports H7 STM32 devices" +#endif + +/* Registry checks.*/ +#if !defined(STM32_HAS_ADC1) || !defined(STM32_HAS_ADC2) || \ + !defined(STM32_HAS_ADC3) +#error "STM32_HAS_ADCx not defined in registry" +#endif + +/* Units checks.*/ +#if STM32_ADC_USE_ADC12 && !STM32_HAS_ADC1 +#error "ADC1 not present in the selected device" +#endif + +#if STM32_ADC_DUAL_MODE && !STM32_HAS_ADC2 +#error "ADC2 not present in the selected device" +#endif + +#if STM32_ADC_USE_ADC3 && !STM32_HAS_ADC3 +#error "ADC3 not present in the selected device" +#endif + +/* IRQ handlers checks.*/ +#if STM32_HAS_ADC1 && !defined(STM32_ADC12_HANDLER) +#error "STM32_ADC12_HANDLER not defined in registry" +#endif + +#if STM32_HAS_ADC2 && !defined(STM32_ADC12_HANDLER) +#error "STM32_ADC12_HANDLER not defined in registry" +#endif + +#if STM32_HAS_ADC3 && !defined(STM32_ADC3_HANDLER) +#error "STM32_ADC3_HANDLER not defined in registry" +#endif + +/* IRQ vector numbers checks.*/ +#if STM32_HAS_ADC1 && !defined(STM32_ADC12_NUMBER) +#error "STM32_ADC12_NUMBER not defined in registry" +#endif + +#if STM32_HAS_ADC2 && !defined(STM32_ADC12_NUMBER) +#error "STM32_ADC12_NUMBER not defined in registry" +#endif + +#if STM32_HAS_ADC3 && !defined(STM32_ADC3_NUMBER) +#error "STM32_ADC3_NUMBER not defined in registry" +#endif + +/* At least one ADC must be assigned.*/ +#if !STM32_ADC_USE_ADC12 && !STM32_ADC_USE_ADC3 +#error "ADC driver activated but no ADC peripheral assigned" +#endif + +/* Dual mode is only supported with ADC12.*/ +#if !STM32_ADC_USE_ADC12 && STM32_ADC_DUAL_MODE +#error "STM32_ADC_DUAL_MODE only supported with ADC12" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_ADC_USE_ADC12 && !defined(STM32_ADC_ADC12_DMA_STREAM) +#error "STM32_ADC_ADC12_DMA_STREAM not defined" +#endif + +#if STM32_ADC_USE_ADC3 && !defined(STM32_ADC_ADC3_BDMA_STREAM) +#error "STM32_ADC_ADC3_BDMA_STREAM not defined" +#endif + +/* DMA channel range tests.*/ +#if STM32_ADC_USE_ADC12 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_ADC_ADC12_DMA_STREAM) +#error "Invalid DMA channel assigned to ADC12" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !STM32_BDMA_IS_VALID_STREAM(STM32_ADC_ADC3_BDMA_STREAM) +#error "Invalid DMA channel assigned to ADC3" +#endif + +/* DMA priority tests.*/ +#if STM32_ADC_USE_ADC12 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC12_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC1" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC3" +#endif + +/* ADC IRQ priority tests.*/ +#if STM32_ADC_USE_ADC12 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC12_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC1" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC3" +#endif + +#if !defined(STM32_ENFORCE_H7_REV_XY) +/* ADC clock source checks.*/ +#if (STM32_D1HPRE == STM32_D1HPRE_DIV1) +#define STM32_ADC_SCLK STM32_HCLK +#else +#define STM32_ADC_SCLK (STM32_HCLK / 2) +#endif + +#if STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK +/* CHTODO: also check ADC_CCR_PRESC.*/ +#define STM32_ADC12_CLOCK (STM32_ADCCLK / 2) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1 +#define STM32_ADC12_CLOCK (STM32_ADC_SCLK / 1 / 2) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2 +#define STM32_ADC12_CLOCK (STM32_ADC_SCLK / 2 / 2) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC12_CLOCK (STM32_ADC_SCLK / 4 / 2) +#else +#error "invalid clock mode selected for STM32_ADC_ADC12_CLOCK_MODE" +#endif + +#if STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK +/* CHTODO: also check ADC_CCR_PRESC.*/ +#define STM32_ADC3_CLOCK (STM32_ADCCLK / 2) +#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1 +#define STM32_ADC3_CLOCK (STM32_ADC_SCLK / 1 / 2) +#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2 +#define STM32_ADC3_CLOCK (STM32_ADC_SCLK / 2 / 2) +#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC3_CLOCK (STM32_ADC_SCLK / 4 / 2) +#else +#error "invalid clock mode selected for STM32_ADC_ADC3_CLOCK_MODE" +#endif + +#else /* defined(STM32_ENFORCE_H7_REV_XY) */ + +#if STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK +#define STM32_ADC12_CLOCK STM32_ADCCLK +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1 +#define STM32_ADC12_CLOCK (STM32_HCLK / 1) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2 +#define STM32_ADC12_CLOCK (STM32_HCLK / 2) +#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC12_CLOCK (STM32_HCLK / 4) +#else +#error "invalid clock mode selected for STM32_ADC_ADC12_CLOCK_MODE" +#endif + +#if STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK +#define STM32_ADC3_CLOCK STM32_ADCCLK +#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1 +#define STM32_ADC3_CLOCK (STM32_HCLK / 1) +#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2 +#define STM32_ADC3_CLOCK (STM32_HCLK / 2) +#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC3_CLOCK (STM32_HCLK / 4) +#else +#error "invalid clock mode selected for STM32_ADC_ADC3_CLOCK_MODE" +#endif + +#endif /* defined(STM32_ENFORCE_H7_REV_XY) */ + +#if STM32_ADC12_CLOCK > STM32_ADCCLK_MAX +#error "STM32_ADC12_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)" +#endif + +#if STM32_ADC3_CLOCK > STM32_ADCCLK_MAX +#error "STM32_ADC3_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)" +#endif + +#if !defined(STM32_ENFORCE_H7_REV_XY) +/* ADC boost checks.*/ +#if STM32_ADC12_CLOCK > 6250000 +#define STM32_ADC12_BOOST (1U << 8U) +#elif STM32_ADC12_CLOCK > 12500000 +#define STM32_ADC12_BOOST (2U << 8U) +#elif STM32_ADC12_CLOCK > 25000000 +#define STM32_ADC12_BOOST (3U << 8U) +#else +#define STM32_ADC12_BOOST (0U << 8U) +#endif + +#if STM32_ADC3_CLOCK > 6250000 +#define STM32_ADC3_BOOST (1U << 8U) +#elif STM32_ADC3_CLOCK > 12500000 +#define STM32_ADC3_BOOST (2U << 8U) +#elif STM32_ADC3_CLOCK > 25000000 +#define STM32_ADC3_BOOST (3U << 8U) +#else +#define STM32_ADC3_BOOST (0U << 8U) +#endif + +#else /* defined(STM32_ENFORCE_H7_REV_XY) */ + +#if STM32_ADC12_CLOCK > 20000000 +#define STM32_ADC12_BOOST (1U << 8U) +#else +#define STM32_ADC12_BOOST (0U << 8U) +#endif + +#if STM32_ADC3_CLOCK > 20000000 +#define STM32_ADC3_BOOST (1U << 8U) +#else +#define STM32_ADC3_BOOST (0U << 8U) +#endif + +#endif /* defined(STM32_ENFORCE_H7_REV_XY) */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +#if STM32_ADC_USE_ADC12 +#define STM32_ADC_DMA_REQUIRED +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif +#endif + +#if STM32_ADC_USE_ADC3 +#define STM32_ADC_BDMA_REQUIRED +#if !defined(STM32_BDMA_REQUIRED) +#define STM32_BDMA_REQUIRED +#endif +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief ADC sample data type. + */ +#if !STM32_ADC_COMPACT_SAMPLES || defined(__DOXYGEN__) +typedef uint16_t adcsample_t; +#else +typedef uint8_t adcsample_t; +#endif + +/** + * @brief Channels number in a conversion group. + */ +typedef uint32_t adc_channels_num_t; + +/** + * @brief Possible ADC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ + ADC_ERR_OVERFLOW = 1, /**< ADC overflow condition. */ + ADC_ERR_AWD1 = 2, /**< Watchdog 1 triggered. */ + ADC_ERR_AWD2 = 3, /**< Watchdog 2 triggered. */ + ADC_ERR_AWD3 = 4 /**< Watchdog 3 triggered. */ +} adcerror_t; + +/** + * @brief Type of a DMA channel pointer choice. + */ +typedef union { +#if defined(STM32_ADC_DMA_REQUIRED) || defined(__DOXYGEN__) + /** + * @brief DMA stream. + */ + const stm32_dma_stream_t *dma; +#endif +#if defined(STM32_ADC_BDMA_REQUIRED) || defined(__DOXYGEN__) + /** + * @brief BDMA stream. + */ + const stm32_bdma_stream_t *bdma; +#endif +} adc_ldd_dma_reference_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC12 == TRUE +typedef ADC12_TypeDef ADC_TypeDef; +#else +typedef ADC3_TypeDef ADC_TypeDef; +#endif + +/** + * @brief Low level fields of the ADC driver structure. + */ +#if (STM32_ADC_DUAL_MODE == TRUE) || defined(__DOXYGEN__) +#define adc_lld_driver_fields \ + /* Pointer to the master ADCx registers block.*/ \ + ADC_TypeDef *adcm; \ + /* Pointer to the slave ADCx registers block.*/ \ + ADC_TypeDef *adcs; \ + /* Pointer to the common ADCx_y registers block.*/ \ + ADC_Common_TypeDef *adcc; \ + /* Pointer to associated DMA channel.*/ \ + adc_ldd_dma_reference_t data; \ + /* DMA mode bit mask.*/ \ + uint32_t dmamode +#else +#define adc_lld_driver_fields \ + /* Pointer to the master ADCx registers block.*/ \ + ADC_TypeDef *adcm; \ + /* Pointer to the slave ADCx registers block.*/ \ + ADC_Common_TypeDef *adcc; \ + /* Pointer to associated DMA channel.*/ \ + adc_ldd_dma_reference_t data; \ + /* DMA mode bit mask.*/ \ + uint32_t dmamode +#endif + +/** + * @brief Low level fields of the ADC configuration structure. + */ +#define adc_lld_config_fields \ + /* ADC DIFSEL register initialization data.*/ \ + uint32_t difsel; \ + /* Calibration mode, specify ADCCALIN and/or ADCCALDIF bits in here.*/ \ + uint32_t calibration + +#if (STM32_ADC_DUAL_MODE == TRUE) || defined(__DOXYGEN__) +#define adc_lld_configuration_group_fields \ + /* ADC CFGR register initialization data. \ + NOTE: The bits DMAEN and DMACFG are enforced internally \ + to the driver, keep them to zero. \ + NOTE: The bits @p ADC_CFGR_CONT or @p ADC_CFGR_DISCEN must be \ + specified in continuous mode or if the buffer depth is \ + greater than one.*/ \ + uint32_t cfgr; \ + /* ADC CFGR2 register initialization data. \ + NOTE: Put this field to zero if not using oversampling.*/ \ + uint32_t cfgr2; \ + /* ADC CCR register initialization data*/ \ + uint32_t ccr; \ + /* ADC PCSEL register initialization data.*/ \ + uint32_t pcsel; \ + /* ADC LTR1 register initialization data.*/ \ + uint32_t ltr1; \ + /* ADC HTR1 register initialization data.*/ \ + uint32_t htr1; \ + /* ADC LTR2 register initialization data.*/ \ + uint32_t ltr2; \ + /* ADC HTR2 register initialization data.*/ \ + uint32_t htr2; \ + /* ADC LTR3 register initialization data.*/ \ + uint32_t ltr3; \ + /* ADC HTR3 register initialization data.*/ \ + uint32_t htr3; \ + /* ADC SMPRx registers initialization data.*/ \ + uint32_t smpr[2]; \ + /* ADC SQRx register initialization data.*/ \ + uint32_t sqr[4]; \ + /* Slave ADC SMPRx registers initialization data. \ + NOTE: This field is only present in dual mode.*/ \ + uint32_t ssmpr[2]; \ + /* Slave ADC SQRx register initialization data. \ + NOTE: This field is only present in dual mode.*/ \ + uint32_t ssqr[4] +#else /* STM32_ADC_DUAL_MODE == FALSE */ +#define adc_lld_configuration_group_fields \ + uint32_t cfgr; \ + uint32_t cfgr2; \ + uint32_t ccr; \ + uint32_t pcsel; \ + uint32_t ltr1; \ + uint32_t htr1; \ + uint32_t ltr2; \ + uint32_t htr2; \ + uint32_t ltr3; \ + uint32_t htr3; \ + uint32_t smpr[2]; \ + uint32_t sqr[4] +#endif /* STM32_ADC_DUAL_MODE == FALSE */ + +/** + * @name Sequences building helper macros + * @{ + */ +/** + * @brief Number of channels in a conversion sequence. + */ +#define ADC_SQR1_NUM_CH(n) (((n) - 1U) << 0U) + +#define ADC_SQR1_SQ1_N(n) ((n) << 6U) /**< @brief 1st channel in seq. */ +#define ADC_SQR1_SQ2_N(n) ((n) << 12U)/**< @brief 2nd channel in seq. */ +#define ADC_SQR1_SQ3_N(n) ((n) << 18U)/**< @brief 3rd channel in seq. */ +#define ADC_SQR1_SQ4_N(n) ((n) << 24U)/**< @brief 4th channel in seq. */ + +#define ADC_SQR2_SQ5_N(n) ((n) << 0U) /**< @brief 5th channel in seq. */ +#define ADC_SQR2_SQ6_N(n) ((n) << 6U) /**< @brief 6th channel in seq. */ +#define ADC_SQR2_SQ7_N(n) ((n) << 12U)/**< @brief 7th channel in seq. */ +#define ADC_SQR2_SQ8_N(n) ((n) << 18U)/**< @brief 8th channel in seq. */ +#define ADC_SQR2_SQ9_N(n) ((n) << 24U)/**< @brief 9th channel in seq. */ + +#define ADC_SQR3_SQ10_N(n) ((n) << 0U) /**< @brief 10th channel in seq.*/ +#define ADC_SQR3_SQ11_N(n) ((n) << 6U) /**< @brief 11th channel in seq.*/ +#define ADC_SQR3_SQ12_N(n) ((n) << 12U)/**< @brief 12th channel in seq.*/ +#define ADC_SQR3_SQ13_N(n) ((n) << 18U)/**< @brief 13th channel in seq.*/ +#define ADC_SQR3_SQ14_N(n) ((n) << 24U)/**< @brief 14th channel in seq.*/ + +#define ADC_SQR4_SQ15_N(n) ((n) << 0U) /**< @brief 15th channel in seq.*/ +#define ADC_SQR4_SQ16_N(n) ((n) << 6U) /**< @brief 16th channel in seq.*/ +/** @} */ + +/** + * @name Sampling rate settings helper macros + * @{ + */ +#define ADC_SMPR1_SMP_AN0(n) ((n) << 0U) /**< @brief AN0 sampling time. */ +#define ADC_SMPR1_SMP_AN1(n) ((n) << 3U) /**< @brief AN1 sampling time. */ +#define ADC_SMPR1_SMP_AN2(n) ((n) << 6U) /**< @brief AN2 sampling time. */ +#define ADC_SMPR1_SMP_AN3(n) ((n) << 9U) /**< @brief AN3 sampling time. */ +#define ADC_SMPR1_SMP_AN4(n) ((n) << 12U)/**< @brief AN4 sampling time. */ +#define ADC_SMPR1_SMP_AN5(n) ((n) << 15U)/**< @brief AN5 sampling time. */ +#define ADC_SMPR1_SMP_AN6(n) ((n) << 18U)/**< @brief AN6 sampling time. */ +#define ADC_SMPR1_SMP_AN7(n) ((n) << 21U)/**< @brief AN7 sampling time. */ +#define ADC_SMPR1_SMP_AN8(n) ((n) << 24U)/**< @brief AN8 sampling time. */ +#define ADC_SMPR1_SMP_AN9(n) ((n) << 27U)/**< @brief AN9 sampling time. */ + +#define ADC_SMPR2_SMP_AN10(n) ((n) << 0U) /**< @brief AN10 sampling time. */ +#define ADC_SMPR2_SMP_AN11(n) ((n) << 3U) /**< @brief AN11 sampling time. */ +#define ADC_SMPR2_SMP_AN12(n) ((n) << 6U) /**< @brief AN12 sampling time. */ +#define ADC_SMPR2_SMP_AN13(n) ((n) << 9U) /**< @brief AN13 sampling time. */ +#define ADC_SMPR2_SMP_AN14(n) ((n) << 12U)/**< @brief AN14 sampling time. */ +#define ADC_SMPR2_SMP_AN15(n) ((n) << 15U)/**< @brief AN15 sampling time. */ +#define ADC_SMPR2_SMP_AN16(n) ((n) << 18U)/**< @brief AN16 sampling time. */ +#define ADC_SMPR2_SMP_AN17(n) ((n) << 21U)/**< @brief AN17 sampling time. */ +#define ADC_SMPR2_SMP_AN18(n) ((n) << 24U)/**< @brief AN18 sampling time. */ +#define ADC_SMPR2_SMP_AN19(n) ((n) << 27U)/**< @brief AN19 sampling time. */ +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC12 && !defined(__DOXYGEN__) +extern ADCDriver ADCD1; +#endif + +#if STM32_ADC_USE_ADC3 && !defined(__DOXYGEN__) +extern ADCDriver ADCD3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void adc_lld_init(void); + void adc_lld_start(ADCDriver *adcp); + void adc_lld_stop(ADCDriver *adcp); + void adc_lld_start_conversion(ADCDriver *adcp); + void adc_lld_stop_conversion(ADCDriver *adcp); + void adcSTM32EnableVREF(ADCDriver *adcp); + void adcSTM32DisableVREF(ADCDriver *adcp); + void adcSTM32EnableTS(ADCDriver *adcp); + void adcSTM32DisableTS(ADCDriver *adcp); + void adcSTM32EnableVBAT(ADCDriver *adcp); + void adcSTM32DisableVBAT(ADCDriver *adcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_ADC */ + +#endif /* HAL_ADC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/notes.txt new file mode 100644 index 0000000..d0b59b7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/notes.txt @@ -0,0 +1,13 @@ +STM32 ADCv4 driver. + +Driver capability: + +- Supports the STM32 "fast" ADC found on H7 sub-family. + +The file registry must export: + +STM32_HAS_ADCx - ADCx presence flag (1..4). +STM32_ADC12_HANDLER - IRQ vector name for ADC1 and ADC2. +STM32_ADC12_NUMBER - IRQ vector number for ADC1 and ADC2. +STM32_ADC34_HANDLER - IRQ vector name for ADC3 and ADC4. +STM32_ADC34_NUMBER - IRQ vector number for ADC3 and ADC4. diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/driver.mk new file mode 100644 index 0000000..1774fca --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv5 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c new file mode 100644 index 0000000..d4d52a0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c @@ -0,0 +1,476 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv1/hal_adc_lld.c + * @brief STM32 ADC subsystem low level driver source. + * + * @addtogroup ADC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define ADC1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief ADC1 driver identifier.*/ +#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) +ADCDriver ADCD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief ADC voltage regulator enable. + * + * @param[in] adc pointer to the ADC registers block + */ +NOINLINE static void adc_lld_vreg_on(ADC_TypeDef *adc) { + + osalDbgAssert(adc->CR == 0, "invalid register state"); + +#if defined(ADC_CR_ADVREGEN) + adc->CR = ADC_CR_ADVREGEN; + volatile uint32_t loop = (STM32_HCLK >> 20) << 4; + do { + loop--; + } while (loop > 0); +#else +#endif +} + +/** + * @brief Stops an ongoing conversion, if any. + * + * @param[in] adc pointer to the ADC registers block + */ +static void adc_lld_stop_adc(ADC_TypeDef *adc) { + + if (adc->CR & ADC_CR_ADSTART) { + adc->CR |= ADC_CR_ADSTP; + while (adc->CR & ADC_CR_ADSTP) + ; + adc->IER = 0; + } +} + +/** + * @brief ADC DMA service routine. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + /* DMA, this could help only if the DMA tries to access an unmapped + address space or violates alignment rules.*/ + _adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE); + } + else { + /* It is possible that the conversion group has already be reset by the + ADC error handler, in this case this interrupt is spurious.*/ + if (adcp->grpp != NULL) { + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } + else if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) +#if !defined(STM32_ADC1_HANDLER) +#error "STM32_ADC1_HANDLER not defined" +#endif +/** + * @brief ADC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_ADC1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + adc_lld_serve_interrupt(&ADCD1); + +#if defined(STM32_ADC_ADC1_IRQ_HOOK) + STM32_ADC_ADC1_IRQ_HOOK +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ADC driver initialization. + * + * @notapi + */ +void adc_lld_init(void) { + +#if STM32_ADC_USE_ADC1 + /* Driver initialization.*/ + adcObjectInit(&ADCD1); + ADCD1.adc = ADC1; + ADCD1.dmastp = NULL; + ADCD1.dmamode = STM32_DMA_CR_CHSEL(ADC1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + + /* The vector is initialized on driver initialization and never + disabled.*/ + nvicEnableVector(12, STM32_ADC_ADC1_IRQ_PRIORITY); +#endif + + /* Calibration procedure.*/ + rccEnableADC1(true); + + /* CCR setup.*/ + ADC->CCR = STM32_ADC_PRESC << 18; + + /* Regulator enabled and stabilized before calibration.*/ + adc_lld_vreg_on(ADC1); + + ADC1->CR |= ADC_CR_ADCAL; + while (ADC1->CR & ADC_CR_ADCAL) + ; + ADC1->CR = 0; + rccDisableADC1(); +} + +/** + * @brief Configures and activates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start(ADCDriver *adcp) { + + /* If in stopped state then enables the ADC and DMA clocks.*/ + if (adcp->state == ADC_STOP) { +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) { + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC1_DMA_STREAM, + STM32_ADC_ADC1_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_rx_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); + rccEnableADC1(true); + + /* DMA setup.*/ + dmaStreamSetPeripheral(adcp->dmastp, &ADC1->DR); + dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC1); + + /* Clock settings.*/ + adcp->adc->CFGR2 = STM32_ADC_ADC1_CKMODE; + } +#endif /* STM32_ADC_USE_ADC1 */ + + /* Regulator enabled and stabilized before calibration.*/ + adc_lld_vreg_on(ADC1); + + /* ADC initial setup, starting the analog part here in order to reduce + the latency when starting a conversion.*/ + adcp->adc->CR = ADC_CR_ADEN; + while (!(adcp->adc->ISR & ADC_ISR_ADRDY)) + ; + } +} + +/** + * @brief Deactivates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop(ADCDriver *adcp) { + + /* If in ready state then disables the ADC clock and analog part.*/ + if (adcp->state == ADC_READY) { + + dmaStreamFreeI(adcp->dmastp); + adcp->dmastp = NULL; + + /* Restoring CCR default.*/ + ADC->CCR = STM32_ADC_PRESC << 18; + + /* Disabling ADC.*/ + if (adcp->adc->CR & ADC_CR_ADEN) { + adc_lld_stop_adc(adcp->adc); + adcp->adc->CR |= ADC_CR_ADDIS; + while (adcp->adc->CR & ADC_CR_ADDIS) + ; + } + + /* Regulator and anything else off.*/ + adcp->adc->CR = 0; + +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) + rccDisableADC1(); +#endif + } +} + +/** + * @brief Starts an ADC conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start_conversion(ADCDriver *adcp) { + uint32_t mode, cfgr1, cfgr2; + const ADCConversionGroup *grpp = adcp->grpp; + + /* DMA setup.*/ + mode = adcp->dmamode; + cfgr1 = grpp->cfgr1 | ADC_CFGR1_DMAEN; + cfgr2 = adcp->adc->CFGR2 & STM32_ADC_CKMODE_MASK; + if (grpp->circular) { + mode |= STM32_DMA_CR_CIRC; + cfgr1 |= ADC_CFGR1_DMACFG; + if (adcp->depth > 1) { + /* If circular buffer depth > 1, then the half transfer interrupt + is enabled in order to allow streaming processing.*/ + mode |= STM32_DMA_CR_HTIE; + } + } + dmaStreamSetMemory0(adcp->dmastp, adcp->samples); + dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * + (uint32_t)adcp->depth); + dmaStreamSetMode(adcp->dmastp, mode); + dmaStreamEnable(adcp->dmastp); + + /* ADC setup, if it is defined a callback for the analog watch dog then it + is enabled.*/ + adcp->adc->ISR = adcp->adc->ISR; + if (grpp->error_cb != NULL) { + adcp->adc->IER = ADC_IER_OVRIE | ADC_IER_AWD1IE + | ADC_IER_AWD2IE + | ADC_IER_AWD3IE; + adcp->adc->TR1 = grpp->tr1; + adcp->adc->TR2 = grpp->tr2; + adcp->adc->TR3 = grpp->tr3; + adcp->adc->AWD2CR = grpp->awd2cr; + adcp->adc->AWD3CR = grpp->awd3cr; + } + adcp->adc->SMPR = grpp->smpr; + adcp->adc->CHSELR = grpp->chselr; + + /* ADC configuration and start.*/ + adcp->adc->CFGR1 = cfgr1; + adcp->adc->CFGR2 = cfgr2 | grpp->cfgr2; + + /* ADC conversion start.*/ + adcp->adc->CR |= ADC_CR_ADSTART; +} + +/** + * @brief Stops an ongoing conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop_conversion(ADCDriver *adcp) { + + dmaStreamDisable(adcp->dmastp); + adc_lld_stop_adc(adcp->adc); +} + +/** + * @brief ISR code. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_serve_interrupt(ADCDriver *adcp) { + uint32_t isr; + + isr = adcp->adc->ISR; + adcp->adc->ISR = isr; + + /* It could be a spurious interrupt caused by overflows after DMA disabling, + just ignore it in this case.*/ + if (adcp->grpp != NULL) { + /* Note, an overflow may occur after the conversion ended before the driver + is able to stop the ADC, this is why the DMA channel is checked too.*/ + if ((isr & ADC_ISR_OVR) && + (dmaStreamGetTransactionSize(adcp->dmastp) > 0)) { + /* ADC overflow condition, this could happen only if the DMA is unable + to read data fast enough.*/ + _adc_isr_error_code(adcp, ADC_ERR_OVERFLOW); + } + if (isr & ADC_ISR_AWD1) { + /* Analog watchdog 1 error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD1); + } + if (isr & ADC_ISR_AWD2) { + /* Analog watchdog 2 error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD2); + } + if (isr & ADC_ISR_AWD3) { + /* Analog watchdog 3 error.*/ + _adc_isr_error_code(adcp, ADC_ERR_AWD3); + } + } +} + +/** + * @brief Enables the VREFEN bit. + * @details The VREFEN bit is required in order to sample the VREF channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableVREF(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR |= ADC_CCR_VREFEN; +} + +/** + * @brief Disables the VREFEN bit. + * @details The VREFEN bit is required in order to sample the VREF channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableVREF(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR &= ~ADC_CCR_VREFEN; +} + +/** + * @brief Enables the TSEN bit. + * @details The TSEN bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableTS(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR |= ADC_CCR_TSEN; +} + +/** + * @brief Disables the TSEN bit. + * @details The TSEN bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableTS(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR &= ~ADC_CCR_TSEN; +} + +#if defined(ADC_CCR_VBATEN) || defined(__DOXYGEN__) +/** + * @brief Enables the VBATEN bit. + * @details The VBATEN bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32EnableVBAT(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR |= ADC_CCR_VBATEN; +} + +/** + * @brief Disables the VBATEN bit. + * @details The VBATEN bit is required in order to sample the VBAT channel. + * @note This is an STM32-only functionality. + * @note This function is meant to be called after @p adcStart(). + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adcSTM32DisableVBAT(ADCDriver *adcp) { + + (void)adcp; + + ADC->CCR &= ~ADC_CCR_VBATEN; +} +#endif /* defined(ADC_CCR_VBATEN) */ + +#endif /* HAL_USE_ADC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.h new file mode 100644 index 0000000..45ea1e0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.h @@ -0,0 +1,401 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file ADCv1/hal_adc_lld.h + * @brief STM32 ADC subsystem low level driver header. + * + * @addtogroup ADC + * @{ + */ + +#ifndef HAL_ADC_LLD_H +#define HAL_ADC_LLD_H + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Sampling rates + * @{ + */ +#define ADC_SMPR_SMP_1P5 0U /**< @brief 14 cycles conversion time */ +#define ADC_SMPR_SMP_3P5 1U /**< @brief 16 cycles conversion time. */ +#define ADC_SMPR_SMP_7P5 2U /**< @brief 20 cycles conversion time. */ +#define ADC_SMPR_SMP_12P5 3U /**< @brief 25 cycles conversion time. */ +#define ADC_SMPR_SMP_19P5 4U /**< @brief 31 cycles conversion time. */ +#define ADC_SMPR_SMP_39P5 5U /**< @brief 52 cycles conversion time. */ +#define ADC_SMPR_SMP_79P5 6U /**< @brief 92 cycles conversion time. */ +#define ADC_SMPR_SMP_160P5 7U /**< @brief 173 cycles conversion time. */ +/** @} */ + +/** + * @name CFGR1 register configuration helpers + * @{ + */ +#define ADC_CFGR1_RES_12BIT (0U << 3U) +#define ADC_CFGR1_RES_10BIT (1U << 3U) +#define ADC_CFGR1_RES_8BIT (2U << 3U) +#define ADC_CFGR1_RES_6BIT (3U << 3U) + +#define ADC_CFGR1_EXTSEL_MASK (15U << 6U) +#define ADC_CFGR1_EXTSEL_SRC(n) ((n) << 6U) + +#define ADC_CFGR1_EXTEN_MASK (3U << 10U) +#define ADC_CFGR1_EXTEN_DISABLED (0U << 10U) +#define ADC_CFGR1_EXTEN_RISING (1U << 10U) +#define ADC_CFGR1_EXTEN_FALLING (2U << 10U) +#define ADC_CFGR1_EXTEN_BOTH (3U << 10U) +/** @} */ + +/** + * @name CFGR2 register configuration helpers + * @{ + */ +#define STM32_ADC_CKMODE_MASK (3U << 30U) +#define STM32_ADC_CKMODE_ADCCLK (0U << 30U) +#define STM32_ADC_CKMODE_PCLK_DIV2 (1U << 30U) +#define STM32_ADC_CKMODE_PCLK_DIV4 (2U << 30U) +#define STM32_ADC_CKMODE_PCLK (3U << 30U) + +#define ADC_CFGR2_OVSR_MASK (7U << 2U) +#define ADC_CFGR2_OVSR_2X (0U << 2U) +#define ADC_CFGR2_OVSR_4X (1U << 2U) +#define ADC_CFGR2_OVSR_8X (2U << 2U) +#define ADC_CFGR2_OVSR_16X (3U << 2U) +#define ADC_CFGR2_OVSR_32X (4U << 2U) +#define ADC_CFGR2_OVSR_64X (5U << 2U) +#define ADC_CFGR2_OVSR_128X (6U << 2U) +#define ADC_CFGR2_OVSR_256X (7U << 2U) + +#define ADC_CFGR2_OVSS_MASK (15 << 5U) +#define ADC_CFGR2_OVSS_SHIFT(n) ((n) << 5U) +/** @} */ + +/** + * @name CHSELR register initializers for CHSELRMOD=0 + * @{ + */ +#define ADC_CHSELR_CHSEL_N(n) (1U << (n)) +/** @} */ + +/** + * @name CHSELR register initializers for CHSELRMOD=1 + * @{ + */ +#define ADC_CHSELR_SQ1_N(n) ((uint32_t)(n) << 0U) +#define ADC_CHSELR_SQ2_N(n) ((uint32_t)(n) << 4U) +#define ADC_CHSELR_SQ3_N(n) ((uint32_t)(n) << 8U) +#define ADC_CHSELR_SQ4_N(n) ((uint32_t)(n) << 12U) +#define ADC_CHSELR_SQ5_N(n) ((uint32_t)(n) << 16U) +#define ADC_CHSELR_SQ6_N(n) ((uint32_t)(n) << 20U) +#define ADC_CHSELR_SQ7_N(n) ((uint32_t)(n) << 24U) +#define ADC_CHSELR_SQ8_N(n) ((uint32_t)(n) << 28U) + +#define ADC_CHSELR_SQ1_END (15U << 0U) +#define ADC_CHSELR_SQ2_END (15U << 4U) +#define ADC_CHSELR_SQ3_END (15U << 8U) +#define ADC_CHSELR_SQ4_END (15U << 12U) +#define ADC_CHSELR_SQ5_END (15U << 16U) +#define ADC_CHSELR_SQ6_END (15U << 20U) +#define ADC_CHSELR_SQ7_END (15U << 24U) +#define ADC_CHSELR_SQ8_END (15U << 28U) +/** @} */ + +/** + * @name Threshold registers initializers + * @{ + */ +#define ADC_TR(low, high) (((uint32_t)(high) << 16U) | \ + (uint32_t)(low)) +#define ADC_TR_DISABLED ADC_TR(0U, 0x0FFFU) +#define ADC_AWDCR_ENABLE(n) (1U << (n)) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief ADC1 driver enable switch. + * @details If set to @p TRUE the support for ADC1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC1) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC1 FALSE +#endif + +/** + * @brief ADC1 clock source selection. + */ +#if !defined(STM32_ADC_ADC1_CKMODE) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_CKMODE STM32_ADC_CKMODE_ADCCLK +#endif + +/** + * @brief ADC1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_IRQ_PRIORITY 2 +#endif + +/** + * @brief ADC1 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 2 +#endif + +/* + * @brief ADC prescaler setting. + * @note This setting has effect only in asynchronous clock mode (the + * default, @p STM32_ADC_CKMODE_ADCCLK). + */ +#if !defined(STM32_ADC_PRESCALER_VALUE) || defined(__DOXYGEN__) +#define STM32_ADC_PRESCALER_VALUE 2 +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Supported devices checks.*/ +#if !defined(STM32G0XX) +#error "ADCv5 only supports G0 STM32 devices" +#endif + +/* Registry checks.*/ +#if !defined(STM32_HAS_ADC1) +#error "STM32_HAS_ADC1 not defined in registry" +#endif + +#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_HANDLER)) +#error "STM32_ADC1_HANDLER not defined in registry" +#endif + +#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_NUMBER)) +#error "STM32_ADC1_NUMBER not defined in registry" +#endif + +#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1 +#error "ADC1 not present in the selected device" +#endif + +/* Units checks.*/ +#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1 +#error "ADC1 not present in the selected device" +#endif + +/* At least one ADC must be assigned.*/ +#if !STM32_ADC_USE_ADC1 +#error "ADC driver activated but no ADC peripheral assigned" +#endif + +/* ADC IRQ priority tests.*/ +#if STM32_ADC_USE_ADC1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC1" +#endif + +/* DMA IRQ priority tests.*/ +#if STM32_ADC_USE_ADC1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC1_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC1 DMA" +#endif + +/* DMA priority tests.*/ +#if STM32_ADC_USE_ADC1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC1" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_ADC_USE_ADC1 && !defined(STM32_ADC_ADC1_DMA_STREAM) +#error "ADC DMA stream not defined" +#endif + + +/* ADC clock source checks.*/ +#if STM32_ADC_PRESCALER_VALUE == 2 +#define STM32_ADC_PRESC 1U +#elif STM32_ADC_PRESCALER_VALUE == 4 +#define STM32_ADC_PRESC 2U +#elif STM32_ADC_PRESCALER_VALUE == 6 +#define STM32_ADC_PRESC 3U +#elif STM32_ADC_PRESCALER_VALUE == 8 +#define STM32_ADC_PRESC 4U +#elif STM32_ADC_PRESCALER_VALUE == 10 +#define STM32_ADC_PRESC 5U +#elif STM32_ADC_PRESCALER_VALUE == 12 +#define STM32_ADC_PRESC 6U +#elif STM32_ADC_PRESCALER_VALUE == 16 +#define STM32_ADC_PRESC 7U +#elif STM32_ADC_PRESCALER_VALUE == 32 +#define STM32_ADC_PRESC 8U +#elif STM32_ADC_PRESCALER_VALUE == 64 +#define STM32_ADC_PRESC 9U +#elif STM32_ADC_PRESCALER_VALUE == 128 +#define STM32_ADC_PRESC 10U +#elif STM32_ADC_PRESCALER_VALUE == 256 +#define STM32_ADC_PRESC 11U +#else +#error "Invalid value assigned to STM32_ADC_PRESCALER_VALUE" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief ADC sample data type. + */ +typedef uint16_t adcsample_t; + +/** + * @brief Channels number in a conversion group. + */ +typedef uint16_t adc_channels_num_t; + +/** + * @brief Possible ADC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ + ADC_ERR_OVERFLOW = 1, /**< ADC overflow condition. */ + ADC_ERR_AWD1 = 2, /**< Analog watchdog 1. */ + ADC_ERR_AWD2 = 3, /**< Analog watchdog 2. */ + ADC_ERR_AWD3 = 4 /**< Analog watchdog 3. */ +} adcerror_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the ADC driver structure. + */ +#define adc_lld_driver_fields \ + /* Pointer to the ADCx registers block.*/ \ + ADC_TypeDef *adc; \ + /* Pointer to associated DMA channel.*/ \ + const stm32_dma_stream_t *dmastp; \ + /* DMA mode bit mask.*/ \ + uint32_t dmamode + +/** + * @brief Low level fields of the ADC configuration structure. + */ +#define adc_lld_config_fields \ + /* Dummy configuration, it is not needed.*/ \ + uint32_t dummy + +/** + * @brief Low level fields of the ADC configuration structure. + */ +#define adc_lld_configuration_group_fields \ + /* ADC CFGR1 register initialization data. \ + NOTE: The bits DMAEN and DMACFG are enforced internally \ + to the driver, keep them to zero. \ + NOTE: The bits @p ADC_CFGR1_CONT or @p ADC_CFGR1_DISCEN must be \ + specified in continuous more or if the buffer depth is \ + greater than one.*/ \ + uint32_t cfgr1; \ + /* ADC CFGR2 register initialization data. \ + NOTE: CKMODE bits must not be specified in this field and left to \ + zero.*/ \ + uint32_t cfgr2; \ + /* ADC TR1 register initialization data.*/ \ + uint32_t tr1; \ + /* ADC TR2 register initialization data.*/ \ + uint32_t tr2; \ + /* ADC TR3 register initialization data.*/ \ + uint32_t tr3; \ + /* ADC AWD2CR register initialization data.*/ \ + uint32_t awd2cr; \ + /* ADC AWD3CR register initialization data.*/ \ + uint32_t awd3cr; \ + /* ADC SMPR register initialization data.*/ \ + uint32_t smpr; \ + /* ADC CHSELR register initialization data. \ + NOTE: The number of bits at logic level one in this register must \ + be equal to the number in the @p num_channels field.*/ \ + uint32_t chselr + +/** + * @brief Changes the value of the ADC CCR register. + * @details Use this function in order to enable or disable the internal + * analog sources. See the documentation in the STM32 Reference + * Manual. + * @note PRESC bits must not be specified and left to zero. + */ +#define adcSTM32SetCCR(ccr) (ADC->CCR = (ccr)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 && !defined(__DOXYGEN__) +extern ADCDriver ADCD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void adc_lld_init(void); + void adc_lld_start(ADCDriver *adcp); + void adc_lld_stop(ADCDriver *adcp); + void adc_lld_start_conversion(ADCDriver *adcp); + void adc_lld_stop_conversion(ADCDriver *adcp); + void adc_lld_serve_interrupt(ADCDriver *adcp); + void adcSTM32EnableVREF(ADCDriver *adcp); + void adcSTM32DisableVREF(ADCDriver *adcp); + void adcSTM32EnableTS(ADCDriver *adcp); + void adcSTM32DisableTS(ADCDriver *adcp); +#if defined(ADC_CCR_VBATEN) + void adcSTM32EnableVBAT(ADCDriver *adcp); + void adcSTM32DisableVBAT(ADCDriver *adcp); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_ADC */ + +#endif /* HAL_ADC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/notes.txt new file mode 100644 index 0000000..283e5c3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/notes.txt @@ -0,0 +1,16 @@ +STM32 ADCv1 driver. + +Driver capability: + +- Supports the STM32 "simple" ADC, the one found on small devices (G0). + +The file registry must export: + +STM32_HAS_ADC1 - ADC1 presence flag. +STM32_ADC_SUPPORTS_PRESCALER - Support of CCR PRESC field. +STM32_ADC_SUPPORTS_OVERSAMPLING - Support of oversampling-related fields. +STM32_ADC1_IRQ_SHARED_WITH_EXTI - TRUE if the IRQ is shared with EXTI. +STM32_ADC1_HANDLER - IRQ vector name. +STM32_ADC1_NUMBER - IRQ vector number. +STM32_ADC1_DMA_MSK - Mask of the compatible DMA channels. +STM32_ADC1_DMA_CHN - Mask of the channels mapping. diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/driver.mk new file mode 100644 index 0000000..1146b41 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/BDMAv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/notes.txt new file mode 100644 index 0000000..e7fe3ad --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/notes.txt @@ -0,0 +1,11 @@ +STM32 BDMAv1 driver. + +Driver capability: + +- The driver supports the "basic" DMA controller. + +The file registry must export: + +STM32_BDMAn_CHx_HANDLER - Vector name for IRQ "x" (1..7). If the macro + is not exported then the ISR is not declared. +STM32_BDMAn_CHx_NUMBER - Vector number for IRQ "x" (1..7). diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c new file mode 100644 index 0000000..4ca2e41 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c @@ -0,0 +1,455 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file BDMAv1/stm32_bdma.c + * @brief BDMA helper driver code. + * + * @addtogroup STM32_BDMA + * @details BDMA sharing helper driver. In the STM32 the BDMA streams are a + * shared resource, this driver allows to allocate and free BDMA + * streams at runtime in order to allow all the other device + * drivers to coordinate the access to the resource. + * @note The BDMA ISR handlers are all declared into this module because + * sharing, the various device drivers can associate a callback to + * ISRs when allocating streams. + * @{ + */ + +#include "hal.h" + +/* The following macro is only defined if some driver requiring BDMA services + has been enabled.*/ +#if defined(STM32_BDMA_REQUIRED) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/** + * @brief Mask of the BDMA streams in @p bdma_allocated_mask. + */ +#define STM32_BDMA_STREAMS_MASK 0x000000FFU + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief BDMA streams descriptors. + * @details This table keeps the association between an unique stream + * identifier and the involved physical registers. + * @note Don't use this array directly, use the appropriate wrapper macros + * instead: @p STM32_BDMA1_STREAM1, @p STM32_BDMA1_STREAM2 etc. + */ +const stm32_bdma_stream_t _stm32_bdma_streams[STM32_BDMA_STREAMS] = { + {BDMA, BDMA_Channel0, 0, DMAMUX2_Channel0, 0, STM32_BDMA1_CH0_NUMBER}, + {BDMA, BDMA_Channel1, 4, DMAMUX2_Channel1, 1, STM32_BDMA1_CH1_NUMBER}, + {BDMA, BDMA_Channel2, 8, DMAMUX2_Channel2, 2, STM32_BDMA1_CH2_NUMBER}, + {BDMA, BDMA_Channel3, 12, DMAMUX2_Channel3, 3, STM32_BDMA1_CH3_NUMBER}, + {BDMA, BDMA_Channel4, 16, DMAMUX2_Channel4, 4, STM32_BDMA1_CH4_NUMBER}, + {BDMA, BDMA_Channel5, 20, DMAMUX2_Channel5, 5, STM32_BDMA1_CH5_NUMBER}, + {BDMA, BDMA_Channel6, 24, DMAMUX2_Channel6, 6, STM32_BDMA1_CH6_NUMBER}, + {BDMA, BDMA_Channel7, 28, DMAMUX2_Channel7, 7, STM32_BDMA1_CH7_NUMBER} +}; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief BDMA ISR redirector type. + */ +typedef struct { + stm32_bdmaisr_t func; /**< @brief BDMA callback function. */ + void *param; /**< @brief BDMA callback parameter.*/ +} bdma_isr_redir_t; + +/** + * @brief BDMA driver base structure. + */ +static struct { + /** + * @brief Mask of the allocated streams. + */ + uint32_t allocated_mask; + /** + * @brief DMA IRQ redirectors. + */ + struct { + /** + * @brief DMA callback function. + */ + stm32_bdmaisr_t func; + /** + * @brief DMA callback parameter. + */ + void *param; + } streams[STM32_BDMA_STREAMS]; +} bdma; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief BDMA1 stream 0 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_BDMA1_CH0_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (BDMA->ISR >> 0U) & STM32_BDMA_ISR_MASK; + BDMA->IFCR = flags << 0U; + if (bdma.streams[0].func) + bdma.streams[0].func(bdma.streams[0].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief BDMA1 stream 1 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_BDMA1_CH1_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (BDMA->ISR >> 4U) & STM32_BDMA_ISR_MASK; + BDMA->IFCR = flags << 4U; + if (bdma.streams[1].func) + bdma.streams[1].func(bdma.streams[1].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief BDMA1 stream 2 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_BDMA1_CH2_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (BDMA->ISR >> 8U) & STM32_BDMA_ISR_MASK; + BDMA->IFCR = flags << 8U; + if (bdma.streams[2].func) + bdma.streams[2].func(bdma.streams[2].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief BDMA1 stream 3 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_BDMA1_CH3_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (BDMA->ISR >> 12U) & STM32_BDMA_ISR_MASK; + BDMA->IFCR = flags << 12U; + if (bdma.streams[3].func) + bdma.streams[3].func(bdma.streams[3].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief BDMA1 stream 4 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_BDMA1_CH4_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (BDMA->ISR >> 16U) & STM32_BDMA_ISR_MASK; + BDMA->IFCR = flags << 16U; + if (bdma.streams[4].func) + bdma.streams[4].func(bdma.streams[4].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief BDMA1 stream 5 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_BDMA1_CH5_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (BDMA->ISR >> 20U) & STM32_BDMA_ISR_MASK; + BDMA->IFCR = flags << 20U; + if (bdma.streams[5].func) + bdma.streams[5].func(bdma.streams[5].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief BDMA1 stream 6 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_BDMA1_CH6_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (BDMA->ISR >> 24U) & STM32_BDMA_ISR_MASK; + BDMA->IFCR = flags << 24U; + if (bdma.streams[6].func) + bdma.streams[6].func(bdma.streams[6].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief BDMA1 stream 7 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_BDMA1_CH7_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (BDMA->ISR >> 28U) & STM32_BDMA_ISR_MASK; + BDMA->IFCR = flags << 28U; + if (bdma.streams[7].func) + bdma.streams[7].func(bdma.streams[7].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief STM32 BDMA helper initialization. + * + * @init + */ +void bdmaInit(void) { + unsigned i; + + bdma.allocated_mask = 0U; + for (i = 0; i < STM32_BDMA_STREAMS; i++) { + _stm32_bdma_streams[i].channel->CCR = 0U; + bdma.streams[i].func = NULL; + bdma.streams[i].param = NULL; + } + BDMA->IFCR = 0xFFFFFFFFU; +} + +/** + * @brief Allocates a BDMA stream. + * @details The stream is allocated and, if required, the BDMA clock enabled. + * The function also enables the IRQ vector associated to the stream + * and initializes its priority. + * + * @param[in] id numeric identifiers of a specific stream or: + * - @p STM32_BDMA_STREAM_ID_ANY for any stream. + * . + * @param[in] priority IRQ priority for the BDMA stream + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return Pointer to the allocated @p stm32_bdma_stream_t + * structure. + * @retval NULL if a/the stream is not available. + * + * @iclass + */ +const stm32_bdma_stream_t *bdmaStreamAllocI(uint32_t id, + uint32_t priority, + stm32_bdmaisr_t func, + void *param) { + uint32_t i, startid, endid; + + osalDbgCheckClassI(); + + if (id < STM32_BDMA_STREAMS) { + startid = id; + endid = id; + } + else if (id == STM32_BDMA_STREAM_ID_ANY) { + startid = 0U; + endid = STM32_BDMA_STREAMS - 1U; + } + else { + osalDbgCheck(false); + return NULL; + } + + for (i = startid; i <= endid; i++) { + uint32_t mask = (1U << i); + if ((bdma.allocated_mask & mask) == 0U) { + const stm32_bdma_stream_t *stp = STM32_BDMA_STREAM(i); + + /* Installs the DMA handler.*/ + bdma.streams[i].func = func; + bdma.streams[i].param = param; + bdma.allocated_mask |= mask; + + /* Enabling DMA clocks required by the current streams set.*/ + if ((STM32_BDMA_STREAMS_MASK & mask) != 0U) { + rccEnableBDMA1(true); + } + +#if defined(rccEnableDMAMUX) + /* Enabling DMAMUX if present.*/ + if (bdma.allocated_mask != 0U) { + rccEnableDMAMUX(true); + } +#endif + + /* Enables the associated IRQ vector if not already enabled and if a + callback is defined.*/ + if (func != NULL) { + nvicEnableVector(stp->vector, priority); + } + + /* Putting the stream in a known state.*/ + bdmaStreamDisable(stp); + stp->channel->CCR = STM32_BDMA_CR_RESET_VALUE; + + return stp; + } + } + + return NULL; +} + +/** + * @brief Allocates a BDMA stream. + * @details The stream is allocated and, if required, the BDMA clock enabled. + * The function also enables the IRQ vector associated to the stream + * and initializes its priority. + * + * @param[in] id numeric identifiers of a specific stream or: + * - @p STM32_BDMA_STREAM_ID_ANY for any stream. + * . + * @param[in] priority IRQ priority for the BDMA stream + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return Pointer to the allocated @p stm32_bdma_stream_t + * structure. + * @retval NULL if a/the stream is not available. + * + * @api + */ +const stm32_bdma_stream_t *bdmaStreamAlloc(uint32_t id, + uint32_t priority, + stm32_bdmaisr_t func, + void *param) { + const stm32_bdma_stream_t *stp; + + osalSysLock(); + stp = bdmaStreamAllocI(id, priority, func, param); + osalSysUnlock(); + + return stp; +} + +/** + * @brief Releases a BDMA stream. + * @details The stream is freed and, if required, the BDMA clock disabled. + * Trying to release a unallocated stream is an illegal operation + * and is trapped if assertions are enabled. + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * + * @iclass + */ +void bdmaStreamFreeI(const stm32_bdma_stream_t *stp) { + + osalDbgCheck(stp != NULL); + + /* Check if the streams is not taken.*/ + osalDbgAssert((bdma.allocated_mask & (1U << stp->selfindex)) != 0U, + "not allocated"); + + /* Disables the associated IRQ vector.*/ + nvicDisableVector(stp->vector); + + /* Marks the stream as not allocated.*/ + bdma.allocated_mask &= ~(1U << stp->selfindex); + + /* Clearing associated handler and parameter.*/ + bdma.streams->func = NULL; + bdma.streams->param = NULL; + + /* Shutting down clocks that are no more required, if any.*/ + if ((bdma.allocated_mask & STM32_BDMA_STREAMS_MASK) == 0U) { + rccDisableBDMA1(); + } +} + +/** + * @brief Releases a BDMA stream. + * @details The stream is freed and, if required, the BDMA clock disabled. + * Trying to release a unallocated stream is an illegal operation + * and is trapped if assertions are enabled. + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * + * @api + */ +void bdmaStreamFree(const stm32_bdma_stream_t *stp) { + + osalSysLock(); + bdmaStreamFreeI(stp); + osalSysUnlock(); +} + +/** + * @brief Associates a peripheral request to a BDMA stream. + * @note This function can be invoked in both ISR or thread context. + * + * @param[in] stp pointer to a @p stm32_bdma_stream_t structure + * @param[in] per peripheral identifier + * + * @special + */ +void bdmaSetRequestSource(const stm32_bdma_stream_t *stp, uint32_t per) { + + osalDbgCheck(per < 256U); + + stp->mux->CCR = per; +} + +#endif /* STM32_BDMA_REQUIRED */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.h new file mode 100644 index 0000000..6ed63f1 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.h @@ -0,0 +1,441 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file BDMAv1/stm32_bdma.h + * @brief BDMA helper driver header. + * @note This driver uses the new naming convention used for the STM32F2xx + * so the "BDMA channels" are referred as "BDMA streams". + * + * @addtogroup STM32_BDMA + * @{ + */ + +#ifndef STM32_BDMA_H +#define STM32_BDMA_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Total number of BDMA streams. + * @details This is the total number of streams among all the BDMA units. + */ +#define STM32_BDMA_STREAMS 8U + +/** + * @brief Mask of the ISR bits passed to the BDMA callback functions. + */ +#define STM32_BDMA_ISR_MASK 0x0EU + +/** + * @brief Checks if a BDMA priority is within the valid range. + * + * @param[in] prio BDMA priority + * @retval The check result. + * @retval false invalid BDMA priority. + * @retval true correct BDMA priority. + */ +#define STM32_BDMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U)) + +/** + * @brief Checks if a BDMA stream id is within the valid range. + * + * @param[in] id BDMA stream id + * @retval The check result. + * @retval false invalid DMA stream. + * @retval true correct DMA stream. + */ +#define STM32_BDMA_IS_VALID_STREAM(id) (((id) >= 0U) && \ + ((id) <= STM32_BDMA_STREAMS)) + +/** + * @name Special stream identifiers + * @{ + */ +#define STM32_BDMA_STREAM_ID_ANY STM32_BDMA_STREAMS +/** @} */ + +/** + * @name BDMA streams identifiers + * @{ + */ +/** + * @brief Returns a pointer to a stm32_dma_stream_t structure. + * + * @param[in] id the stream numeric identifier + * @return A pointer to the stm32_bdma_stream_t constant structure + * associated to the BDMA stream. + */ +#define STM32_BDMA_STREAM(id) (&_stm32_bdma_streams[id]) + +#define STM32_BDMA1_STREAM0 STM32_BDMA_STREAM(0) +#define STM32_BDMA1_STREAM1 STM32_BDMA_STREAM(1) +#define STM32_BDMA1_STREAM2 STM32_BDMA_STREAM(2) +#define STM32_BDMA1_STREAM3 STM32_BDMA_STREAM(3) +#define STM32_BDMA1_STREAM4 STM32_BDMA_STREAM(4) +#define STM32_BDMA1_STREAM5 STM32_BDMA_STREAM(5) +#define STM32_BDMA1_STREAM6 STM32_BDMA_STREAM(6) +#define STM32_BDMA1_STREAM7 STM32_BDMA_STREAM(7) +/** @} */ + +/** + * @name CR register constants + * @{ + */ +#define STM32_BDMA_CR_RESET_VALUE 0x00000000U +#define STM32_BDMA_CR_EN BDMA_CCR_EN_Msk +#define STM32_BDMA_CR_TCIE BDMA_CCR_TCIE +#define STM32_BDMA_CR_HTIE BDMA_CCR_HTIE +#define STM32_BDMA_CR_TEIE BDMA_CCR_TEIE +#define STM32_BDMA_CR_DIR_MASK (BDMA_CCR_DIR | BDMA_CCR_MEM2MEM) +#define STM32_BDMA_CR_DIR_P2M 0U +#define STM32_BDMA_CR_DIR_M2P BDMA_CCR_DIR +#define STM32_BDMA_CR_DIR_M2M BDMA_CCR_MEM2MEM +#define STM32_BDMA_CR_CIRC BDMA_CCR_CIRC +#define STM32_BDMA_CR_PINC BDMA_CCR_PINC +#define STM32_BDMA_CR_MINC BDMA_CCR_MINC +#define STM32_BDMA_CR_PSIZE_MASK BDMA_CCR_PSIZE_Msk +#define STM32_BDMA_CR_PSIZE_BYTE 0U +#define STM32_BDMA_CR_PSIZE_HWORD BDMA_CCR_PSIZE_0 +#define STM32_BDMA_CR_PSIZE_WORD BDMA_CCR_PSIZE_1 +#define STM32_BDMA_CR_MSIZE_MASK BDMA_CCR_MSIZE_Msk +#define STM32_BDMA_CR_MSIZE_BYTE 0U +#define STM32_BDMA_CR_MSIZE_HWORD BDMA_CCR_MSIZE_0 +#define STM32_BDMA_CR_MSIZE_WORD BDMA_CCR_MSIZE_1 +#define STM32_BDMA_CR_SIZE_MASK (STM32_BDMA_CR_PSIZE_MASK | \ + STM32_BDMA_CR_MSIZE_MASK) +#define STM32_BDMA_CR_PL_MASK BDMA_CCR_PL_Msk +#define STM32_BDMA_CR_PL(n) ((n) << 12U) +#if !defined(STM32_ENFORCE_H7_REV_XY) +#define STM32_BDMA_CR_DBM BDMA_CCR_DBM +#define STM32_BDMA_CR_CM BDMA_CCR_CT +#endif +/** @} */ + +/** + * @name Status flags passed to the ISR callbacks + * @{ + */ +#define STM32_BDMA_ISR_TEIF BDMA_ISR_TEIF0 +#define STM32_BDMA_ISR_HTIF BDMA_ISR_HTIF0 +#define STM32_BDMA_ISR_TCIF BDMA_ISR_TCIF0 +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_BDMA1) +#error "STM32_HAS_BDMA1 missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH0_HANDLER) +#error "STM32_BDMA1_CH0_HANDLER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH1_HANDLER) +#error "STM32_BDMA1_CH1_HANDLER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH2_HANDLER) +#error "STM32_BDMA1_CH2_HANDLER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH3_HANDLER) +#error "STM32_BDMA1_CH3_HANDLER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH4_HANDLER) +#error "STM32_BDMA1_CH4_HANDLER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH5_HANDLER) +#error "STM32_BDMA1_CH5_HANDLER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH6_HANDLER) +#error "STM32_BDMA1_CH6_HANDLER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH7_HANDLER) +#error "STM32_BDMA1_CH7_HANDLER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH0_NUMBER) +#error "STM32_BDMA1_CH0_NUMBER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH1_NUMBER) +#error "STM32_BDMA1_CH1_NUMBER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH2_NUMBER) +#error "STM32_BDMA1_CH2_NUMBER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH3_NUMBER) +#error "STM32_BDMA1_CH3_NUMBER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH4_NUMBER) +#error "STM32_BDMA1_CH4_NUMBER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH5_NUMBER) +#error "STM32_BDMA1_CH5_NUMBER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH6_NUMBER) +#error "STM32_BDMA1_CH6_NUMBER missing in registry" +#endif + +#if !defined(STM32_BDMA1_CH7_NUMBER) +#error "STM32_BDMA1_CH7_NUMBER missing in registry" +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief STM32 BDMA ISR function type. + * + * @param[in] p parameter for the registered function + * @param[in] flags pre-shifted content of the ISR register, the bits + * are aligned to bit zero + */ +typedef void (*stm32_bdmaisr_t)(void *p, uint32_t flags); + +/** + * @brief STM32 BDMA stream descriptor structure. + */ +typedef struct { + BDMA_TypeDef *bdma; /**< @brief Associated BDMA. */ + BDMA_Channel_TypeDef *channel; /**< @brief Associated BDMA channel.*/ + uint8_t shift; /**< @brief Bit offset in ISR and + IFCR registers. */ + DMAMUX_Channel_TypeDef *mux; /**< @brief Associated BDMA stream. */ + uint8_t selfindex; /**< @brief Index to self in array. */ + uint8_t vector; /**< @brief Associated IRQ vector. */ +} stm32_bdma_stream_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Associates a peripheral data register to a BDMA stream. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * @param[in] addr value to be written in the CPAR register + * + * @special + */ +#define bdmaStreamSetPeripheral(stp, addr) { \ + (stp)->channel->CPAR = (uint32_t)(addr); \ +} + +/** + * @brief Associates a memory destination to a BDMA stream. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * @param[in] addr value to be written in the CMAR register + * + * @special + */ +#define bdmaStreamSetMemory(stp, addr) { \ + (stp)->channel->CM0AR = (uint32_t)(addr); \ +} + +/** + * @brief Sets the number of transfers to be performed. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * @param[in] size value to be written in the CNDTR register + * + * @special + */ +#define bdmaStreamSetTransactionSize(stp, size) { \ + (stp)->channel->CNDTR = (uint32_t)(size); \ +} + +/** + * @brief Returns the number of transfers to be performed. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * @return The number of transfers to be performed. + * + * @special + */ +#define bdmaStreamGetTransactionSize(stp) ((size_t)((stp)->channel->CNDTR)) + +/** + * @brief Programs the stream mode settings. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * @param[in] mode value to be written in the CCR register + * + * @special + */ +#define bdmaStreamSetMode(stp, mode) { \ + (stp)->channel->CCR = (uint32_t)(mode); \ +} + +/** + * @brief BDMA stream enable. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * + * @special + */ +#define bdmaStreamEnable(stp) { \ + (stp)->channel->CCR |= STM32_BDMA_CR_EN; \ +} + +/** + * @brief BDMA stream disable. + * @details The function disables the specified stream and then clears any + * pending interrupt. + * @note This function can be invoked in both ISR or thread context. + * @note Interrupts enabling flags are set to zero after this call, see + * bug 3607518. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * + * @special + */ +#define bdmaStreamDisable(stp) { \ + (stp)->channel->CCR &= ~(STM32_BDMA_CR_TCIE | STM32_BDMA_CR_HTIE | \ + STM32_BDMA_CR_TEIE | STM32_BDMA_CR_EN); \ + bdmaStreamClearInterrupt(stp); \ +} + +/** + * @brief BDMA stream interrupt sources clear. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * + * @special + */ +#define bdmaStreamClearInterrupt(stp) { \ + (stp)->bdma->IFCR = STM32_BDMA_ISR_MASK << (stp)->shift; \ +} + +/** + * @brief Starts a memory to memory operation using the specified stream. + * @note The default transfer data mode is "byte to byte" but it can be + * changed by specifying extra options in the @p mode parameter. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + * @param[in] mode value to be written in the CCR register, this value + * is implicitly ORed with: + * - @p STM32_BDMA_CR_MINC + * - @p STM32_BDMA_CR_PINC + * - @p STM32_BDMA_CR_DIR_M2M + * - @p STM32_BDMA_CR_EN + * . + * @param[in] src source address + * @param[in] dst destination address + * @param[in] n number of data units to copy + */ +#define bdmaStartMemCopy(stp, mode, src, dst, n) { \ + bdmaStreamSetPeripheral(stp, src); \ + bdmaStreamSetMemory0(stp, dst); \ + bdmaStreamSetTransactionSize(stp, n); \ + bdmaStreamSetMode(stp, (mode) | \ + STM32_BDMA_CR_MINC | STM32_BDMA_CR_PINC | \ + STM32_BDMA_CR_DIR_M2M | STM32_BDMA_CR_EN); \ +} + +/** + * @brief Polled wait for BDMA transfer end. + * @pre The stream must have been allocated using @p bdmaStreamAllocate(). + * @post After use the stream can be released using @p bdmaStreamRelease(). + * + * @param[in] stp pointer to an @p stm32_bdma_stream_t structure + */ +#define bdmaWaitCompletion(stp) { \ + while ((stp)->channel->CNDTR > 0U) \ + ; \ + bdmaStreamDisable(stp); \ +} +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern const stm32_bdma_stream_t _stm32_bdma_streams[STM32_BDMA_STREAMS]; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void bdmaInit(void); + const stm32_bdma_stream_t *bdmaStreamAllocI(uint32_t id, + uint32_t priority, + stm32_bdmaisr_t func, + void *param); + const stm32_bdma_stream_t *bdmaStreamAlloc(uint32_t id, + uint32_t priority, + stm32_bdmaisr_t func, + void *param); + void bdmaStreamFreeI(const stm32_bdma_stream_t *stp); + void bdmaStreamFree(const stm32_bdma_stream_t *stp); + void bdmaSetRequestSource(const stm32_bdma_stream_t *stp, uint32_t per); +#ifdef __cplusplus +} +#endif + +#endif /* STM32_BDMA_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/driver.mk new file mode 100644 index 0000000..608a927 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c new file mode 100644 index 0000000..4d4e76a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c @@ -0,0 +1,1032 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file CANv1/hal_can_lld.c + * @brief STM32 CAN subsystem low level driver source. + * + * @addtogroup CAN + * @{ + */ + +#include "hal.h" + +#if HAL_USE_CAN || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* + * Addressing differences in the headers, they seem unable to agree on names. + */ +#if STM32_CAN_USE_CAN1 +#if !defined(CAN1) +#define CAN1 CAN +#endif +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief CAN1 driver identifier.*/ +#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__) +CANDriver CAND1; +#endif + +/** @brief CAN2 driver identifier.*/ +#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__) +CANDriver CAND2; +#endif + +/** @brief CAN3 driver identifier.*/ +#if STM32_CAN_USE_CAN3 || defined(__DOXYGEN__) +CANDriver CAND3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +/** + * @brief Programs the filters of CAN 1 and CAN 2. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] can2sb number of the first filter assigned to CAN2 + * @param[in] num number of entries in the filters array, if zero then + * a default filter is programmed + * @param[in] cfp pointer to the filters array, can be @p NULL if + * (num == 0) + * + * @notapi + */ +static void can_lld_set_filters(CANDriver* canp, + uint32_t can2sb, + uint32_t num, + const CANFilter *cfp) { + +#if STM32_CAN_USE_CAN2 + if (canp == &CAND2) { + /* Set handle to CAN1, because CAN1 manages the filters of CAN2.*/ + canp = &CAND1; + } +#endif + + /* Temporarily enabling CAN clock.*/ +#if STM32_CAN_USE_CAN1 + if (canp == &CAND1) { + rccEnableCAN1(true); + /* Filters initialization.*/ + canp->can->FMR = (canp->can->FMR & 0xFFFF0000) | CAN_FMR_FINIT; + canp->can->FMR = (canp->can->FMR & 0xFFFF0000) | (can2sb << 8) | CAN_FMR_FINIT; + } +#endif + +#if STM32_CAN_USE_CAN3 + if (canp == &CAND3) { + rccEnableCAN3(true); + /* Filters initialization.*/ + canp->can->FMR = (canp->can->FMR & 0xFFFF0000) | CAN_FMR_FINIT; + } +#endif + + if (num > 0) { + uint32_t i, fmask; + + /* All filters cleared.*/ + canp->can->FA1R = 0; + canp->can->FM1R = 0; + canp->can->FS1R = 0; + canp->can->FFA1R = 0; + +#if STM32_CAN_USE_CAN1 + if (canp == &CAND1) { + for (i = 0; i < STM32_CAN_MAX_FILTERS; i++) { + canp->can->sFilterRegister[i].FR1 = 0; + canp->can->sFilterRegister[i].FR2 = 0; + } + } +#endif + +#if STM32_CAN_USE_CAN3 + if (canp == &CAND3) { + for (i = 0; i < STM32_CAN3_MAX_FILTERS; i++) { + canp->can->sFilterRegister[i].FR1 = 0; + canp->can->sFilterRegister[i].FR2 = 0; + } + } +#endif + + /* Scanning the filters array.*/ + for (i = 0; i < num; i++) { + fmask = 1 << cfp->filter; + if (cfp->mode) + canp->can->FM1R |= fmask; + if (cfp->scale) + canp->can->FS1R |= fmask; + if (cfp->assignment) + canp->can->FFA1R |= fmask; + canp->can->sFilterRegister[cfp->filter].FR1 = cfp->register1; + canp->can->sFilterRegister[cfp->filter].FR2 = cfp->register2; + canp->can->FA1R |= fmask; + cfp++; + } + } + else { + /* Setting up a single default filter that enables everything for both + CANs.*/ + canp->can->sFilterRegister[0].FR1 = 0; + canp->can->sFilterRegister[0].FR2 = 0; +#if STM32_CAN_USE_CAN2 + if (canp == &CAND1) { + canp->can->sFilterRegister[can2sb].FR1 = 0; + canp->can->sFilterRegister[can2sb].FR2 = 0; + } +#endif + canp->can->FM1R = 0; + canp->can->FFA1R = 0; + canp->can->FS1R = 1; + canp->can->FA1R = 1; +#if STM32_CAN_USE_CAN2 + if (canp == &CAND1) { + canp->can->FS1R |= 1 << can2sb; + canp->can->FA1R |= 1 << can2sb; + } +#endif + } + canp->can->FMR &= ~CAN_FMR_FINIT; + + /* Clock disabled, it will be enabled again in can_lld_start().*/ + /* Temporarily enabling CAN clock.*/ +#if STM32_CAN_USE_CAN1 + if (canp == &CAND1) { + rccDisableCAN1(); + } +#endif +#if STM32_CAN_USE_CAN3 + if (canp == &CAND3) { + rccDisableCAN3(); + } +#endif +} + +/** + * @brief Common TX ISR handler. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +static void can_lld_tx_handler(CANDriver *canp) { + uint32_t tsr; + eventflags_t flags; + + /* Clearing IRQ sources.*/ + tsr = canp->can->TSR; + canp->can->TSR = tsr; + + /* Flags to be signaled through the TX event source.*/ + flags = 0U; + + /* Checking mailbox 0.*/ + if ((tsr & CAN_TSR_RQCP0) != 0U) { + if ((tsr & (CAN_TSR_ALST0 | CAN_TSR_TERR0)) != 0U) { + flags |= CAN_MAILBOX_TO_MASK(1U) << 16U; + } + else { + flags |= CAN_MAILBOX_TO_MASK(1U); + } + } + + /* Checking mailbox 1.*/ + if ((tsr & CAN_TSR_RQCP1) != 0U) { + if ((tsr & (CAN_TSR_ALST1 | CAN_TSR_TERR1)) != 0U) { + flags |= CAN_MAILBOX_TO_MASK(2U) << 16U; + } + else { + flags |= CAN_MAILBOX_TO_MASK(2U); + } + } + + /* Checking mailbox 2.*/ + if ((tsr & CAN_TSR_RQCP2) != 0U) { + if ((tsr & (CAN_TSR_ALST2 | CAN_TSR_TERR2)) != 0U) { + flags |= CAN_MAILBOX_TO_MASK(3U) << 16U; + } + else { + flags |= CAN_MAILBOX_TO_MASK(3U); + } + } + + /* Signaling flags and waking up threads waiting for a transmission slot.*/ + _can_tx_empty_isr(canp, flags); +} + +/** + * @brief Common RX0 ISR handler. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +static void can_lld_rx0_handler(CANDriver *canp) { + uint32_t rf0r; + + rf0r = canp->can->RF0R; + if ((rf0r & CAN_RF0R_FMP0) > 0) { + /* No more receive events until the queue 0 has been emptied.*/ + canp->can->IER &= ~CAN_IER_FMPIE0; + _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(1U)); + } + if ((rf0r & CAN_RF0R_FOVR0) > 0) { + /* Overflow events handling.*/ + canp->can->RF0R = CAN_RF0R_FOVR0; + _can_error_isr(canp, CAN_OVERFLOW_ERROR); + } +} + +/** + * @brief Common RX1 ISR handler. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +static void can_lld_rx1_handler(CANDriver *canp) { + uint32_t rf1r; + + rf1r = canp->can->RF1R; + if ((rf1r & CAN_RF1R_FMP1) > 0) { + /* No more receive events until the queue 0 has been emptied.*/ + canp->can->IER &= ~CAN_IER_FMPIE1; + _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(2U)); + } + if ((rf1r & CAN_RF1R_FOVR1) > 0) { + /* Overflow events handling.*/ + canp->can->RF1R = CAN_RF1R_FOVR1; + _can_error_isr(canp, CAN_OVERFLOW_ERROR); + } +} + +/** + * @brief Common SCE ISR handler. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +static void can_lld_sce_handler(CANDriver *canp) { + uint32_t msr; + + /* Clearing IRQ sources.*/ + msr = canp->can->MSR; + canp->can->MSR = msr; + + /* Wakeup event.*/ +#if CAN_USE_SLEEP_MODE + if (msr & CAN_MSR_WKUI) { + canp->state = CAN_READY; + canp->can->MCR &= ~CAN_MCR_SLEEP; + _can_wakeup_isr(canp); + } +#endif /* CAN_USE_SLEEP_MODE */ + /* Error event.*/ + if (msr & CAN_MSR_ERRI) { + eventflags_t flags; + uint32_t esr = canp->can->ESR; + +#if STM32_CAN_REPORT_ALL_ERRORS + flags = (eventflags_t)(esr & 7); + if ((esr & CAN_ESR_LEC) > 0) + flags |= CAN_FRAMING_ERROR; +#else + flags = 0; +#endif + + /* The content of the ESR register is copied unchanged in the upper + half word of the listener flags mask.*/ + _can_error_isr(canp, flags | (eventflags_t)(esr << 16U)); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__) +#if defined(STM32_CAN1_UNIFIED_HANDLER) +/** + * @brief CAN1 unified interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_UNIFIED_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND1); + can_lld_rx0_handler(&CAND1); + can_lld_rx1_handler(&CAND1); + can_lld_sce_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} +#else /* !defined(STM32_CAN1_UNIFIED_HANDLER) */ + +#if !defined(STM32_CAN1_TX_HANDLER) +#error "STM32_CAN1_TX_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_RX0_HANDLER) +#error "STM32_CAN1_RX0_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_RX1_HANDLER) +#error "STM32_CAN1_RX1_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_SCE_HANDLER) +#error "STM32_CAN1_SCE_HANDLER not defined" +#endif + +/** + * @brief CAN1 TX interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_TX_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN1 RX0 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_RX0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx0_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN1 RX1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_RX1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx1_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN1 SCE interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_sce_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_CAN1_UNIFIED_HANDLER) */ +#endif /* STM32_CAN_USE_CAN1 */ + +#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__) +#if defined(STM32_CAN2_UNIFIED_HANDLER) +/** + * @brief CAN1 unified interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_UNIFIED_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND2); + can_lld_rx0_handler(&CAND2); + can_lld_rx1_handler(&CAND2); + can_lld_sce_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} +#else /* !defined(STM32_CAN2_UNIFIED_HANDLER) */ + +#if !defined(STM32_CAN1_TX_HANDLER) +#error "STM32_CAN1_TX_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_RX0_HANDLER) +#error "STM32_CAN1_RX0_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_RX1_HANDLER) +#error "STM32_CAN1_RX1_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_SCE_HANDLER) +#error "STM32_CAN1_SCE_HANDLER not defined" +#endif + +/** + * @brief CAN2 TX interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_TX_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN2 RX0 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_RX0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx0_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN2 RX1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_RX1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx1_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN2 SCE interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_SCE_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_sce_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_CAN2_UNIFIED_HANDLER) */ +#endif /* STM32_CAN_USE_CAN2 */ + +#if STM32_CAN_USE_CAN3 || defined(__DOXYGEN__) +#if defined(STM32_CAN3_UNIFIED_HANDLER) +/** + * @brief CAN1 unified interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN3_UNIFIED_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND3); + can_lld_rx0_handler(&CAND3); + can_lld_rx1_handler(&CAND3); + can_lld_sce_handler(&CAND3); + + OSAL_IRQ_EPILOGUE(); +} +#else /* !defined(STM32_CAN3_UNIFIED_HANDLER) */ + +#if !defined(STM32_CAN3_TX_HANDLER) +#error "STM32_CAN3_TX_HANDLER not defined" +#endif +#if !defined(STM32_CAN3_RX0_HANDLER) +#error "STM32_CAN3_RX0_HANDLER not defined" +#endif +#if !defined(STM32_CAN3_RX1_HANDLER) +#error "STM32_CAN3_RX1_HANDLER not defined" +#endif +#if !defined(STM32_CAN3_SCE_HANDLER) +#error "STM32_CAN3_SCE_HANDLER not defined" +#endif + +/** + * @brief CAN3 TX interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN3_TX_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND3); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN3 RX0 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN3_RX0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx0_handler(&CAND3); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN1 RX3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN3_RX1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx1_handler(&CAND3); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN1 SCE interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN3_SCE_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_sce_handler(&CAND3); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_CAN1_UNIFIED_HANDLER) */ +#endif /* STM32_CAN_USE_CAN1 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level CAN driver initialization. + * + * @notapi + */ +void can_lld_init(void) { + +#if STM32_CAN_USE_CAN1 + /* Driver initialization.*/ + canObjectInit(&CAND1); + CAND1.can = CAN1; +#if defined(STM32_CAN1_UNIFIED_NUMBER) + nvicEnableVector(STM32_CAN1_UNIFIED_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); +#else + nvicEnableVector(STM32_CAN1_TX_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN1_RX0_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN1_RX1_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN1_SCE_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); +#endif +#endif + +#if STM32_CAN_USE_CAN2 + /* Driver initialization.*/ + canObjectInit(&CAND2); + CAND2.can = CAN2; +#if defined(STM32_CAN2_UNIFIED_NUMBER) + nvicEnableVector(STM32_CAN2_UNIFIED_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); +#else + nvicEnableVector(STM32_CAN2_TX_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN2_RX0_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN2_RX1_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN2_SCE_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); +#endif +#endif + +#if STM32_CAN_USE_CAN3 + /* Driver initialization.*/ + canObjectInit(&CAND3); + CAND3.can = CAN3; +#if defined(STM32_CAN3_UNIFIED_NUMBER) + nvicEnableVector(STM32_CAN3_UNIFIED_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY); +#else + nvicEnableVector(STM32_CAN3_TX_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN3_RX0_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN3_RX1_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN3_SCE_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY); +#endif +#endif + + /* Filters initialization.*/ +#if STM32_CAN_USE_CAN1 +#if STM32_HAS_CAN2 + can_lld_set_filters(&CAND1, STM32_CAN_MAX_FILTERS / 2, 0, NULL); +#else + can_lld_set_filters(&CAND1, STM32_CAN_MAX_FILTERS, 0, NULL); +#endif +#endif + +#if STM32_HAS_CAN3 +#if STM32_CAN_USE_CAN3 + can_lld_set_filters(&CAND3, STM32_CAN3_MAX_FILTERS, 0, NULL); +#endif +#endif +} + +/** + * @brief Configures and activates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_start(CANDriver *canp) { + + /* Clock activation.*/ +#if STM32_CAN_USE_CAN1 + if (&CAND1 == canp) { + rccEnableCAN1(true); + } +#endif + +#if STM32_CAN_USE_CAN2 + if (&CAND2 == canp) { + rccEnableCAN1(true); /* CAN 2 requires CAN1, so enabling it first.*/ + rccEnableCAN2(true); + } +#endif + +#if STM32_CAN_USE_CAN3 + if (&CAND3 == canp) { + rccEnableCAN3(true); + } +#endif + + /* Configuring CAN. */ + canp->can->MCR = CAN_MCR_INRQ; + while ((canp->can->MSR & CAN_MSR_INAK) == 0) + osalThreadSleepS(1); + canp->can->BTR = canp->config->btr; + canp->can->MCR = canp->config->mcr; + + /* Interrupt sources initialization.*/ +#if STM32_CAN_REPORT_ALL_ERRORS + canp->can->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | + CAN_IER_WKUIE | CAN_IER_ERRIE | CAN_IER_LECIE | + CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE | + CAN_IER_FOVIE0 | CAN_IER_FOVIE1; +#else + canp->can->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | + CAN_IER_WKUIE | CAN_IER_ERRIE | + CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE | + CAN_IER_FOVIE0 | CAN_IER_FOVIE1; +#endif +} + +/** + * @brief Deactivates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_stop(CANDriver *canp) { + + /* If in ready state then disables the CAN peripheral.*/ + if (canp->state == CAN_READY) { +#if STM32_CAN_USE_CAN1 + if (&CAND1 == canp) { + CAN1->MCR = 0x00010002; /* Register reset value. */ + CAN1->IER = 0x00000000; /* All sources disabled. */ +#if STM32_CAN_USE_CAN2 + /* If CAND2 is stopped then CAN1 clock is stopped here.*/ + if (CAND2.state == CAN_STOP) +#endif + { + rccDisableCAN1(); + } + } +#endif + +#if STM32_CAN_USE_CAN2 + if (&CAND2 == canp) { + CAN2->MCR = 0x00010002; /* Register reset value. */ + CAN2->IER = 0x00000000; /* All sources disabled. */ +#if STM32_CAN_USE_CAN1 + /* If CAND1 is stopped then CAN1 clock is stopped here.*/ + if (CAND1.state == CAN_STOP) +#endif + { + rccDisableCAN1(); + } + rccDisableCAN2(); + } +#endif + +#if STM32_CAN_USE_CAN3 + if (&CAND3 == canp) { + CAN3->MCR = 0x00010002; /* Register reset value. */ + CAN3->IER = 0x00000000; /* All sources disabled. */ + rccDisableCAN3(); + } +#endif + } +} + +/** + * @brief Determines whether a frame can be transmitted. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @return The queue space availability. + * @retval false no space in the transmit queue. + * @retval true transmit slot available. + * + * @notapi + */ +bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) { + + switch (mailbox) { + case CAN_ANY_MAILBOX: + return (canp->can->TSR & CAN_TSR_TME) != 0; + case 1: + return (canp->can->TSR & CAN_TSR_TME0) != 0; + case 2: + return (canp->can->TSR & CAN_TSR_TME1) != 0; + case 3: + return (canp->can->TSR & CAN_TSR_TME2) != 0; + default: + return false; + } +} + +/** + * @brief Inserts a frame into the transmit queue. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] ctfp pointer to the CAN frame to be transmitted + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @notapi + */ +void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *ctfp) { + uint32_t tir; + CAN_TxMailBox_TypeDef *tmbp; + + /* Pointer to a free transmission mailbox.*/ + switch (mailbox) { + case CAN_ANY_MAILBOX: + tmbp = &canp->can->sTxMailBox[(canp->can->TSR & CAN_TSR_CODE) >> 24]; + break; + case 1: + tmbp = &canp->can->sTxMailBox[0]; + break; + case 2: + tmbp = &canp->can->sTxMailBox[1]; + break; + case 3: + tmbp = &canp->can->sTxMailBox[2]; + break; + default: + return; + } + + /* Preparing the message.*/ + if (ctfp->IDE) + tir = ((uint32_t)ctfp->EID << 3) | ((uint32_t)ctfp->RTR << 1) | + CAN_TI0R_IDE; + else + tir = ((uint32_t)ctfp->SID << 21) | ((uint32_t)ctfp->RTR << 1); + tmbp->TDTR = ctfp->DLC; + tmbp->TDLR = ctfp->data32[0]; + tmbp->TDHR = ctfp->data32[1]; + tmbp->TIR = tir | CAN_TI0R_TXRQ; +} + +/** + * @brief Determines whether a frame has been received. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @return The queue space availability. + * @retval false no space in the transmit queue. + * @retval true transmit slot available. + * + * @notapi + */ +bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) { + + switch (mailbox) { + case CAN_ANY_MAILBOX: + return ((canp->can->RF0R & CAN_RF0R_FMP0) != 0 || + (canp->can->RF1R & CAN_RF1R_FMP1) != 0); + case 1: + return (canp->can->RF0R & CAN_RF0R_FMP0) != 0; + case 2: + return (canp->can->RF1R & CAN_RF1R_FMP1) != 0; + default: + return false; + } +} + +/** + * @brief Receives a frame from the input queue. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * @param[out] crfp pointer to the buffer where the CAN frame is copied + * + * @notapi + */ +void can_lld_receive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *crfp) { + uint32_t rir, rdtr; + + if (mailbox == CAN_ANY_MAILBOX) { + if ((canp->can->RF0R & CAN_RF0R_FMP0) != 0) + mailbox = 1; + else if ((canp->can->RF1R & CAN_RF1R_FMP1) != 0) + mailbox = 2; + else { + /* Should not happen, do nothing.*/ + return; + } + } + switch (mailbox) { + case 1: + /* Fetches the message.*/ + rir = canp->can->sFIFOMailBox[0].RIR; + rdtr = canp->can->sFIFOMailBox[0].RDTR; + crfp->data32[0] = canp->can->sFIFOMailBox[0].RDLR; + crfp->data32[1] = canp->can->sFIFOMailBox[0].RDHR; + + /* Releases the mailbox.*/ + canp->can->RF0R = CAN_RF0R_RFOM0; + + /* If the queue is empty re-enables the interrupt in order to generate + events again.*/ + if ((canp->can->RF0R & CAN_RF0R_FMP0) == 0) + canp->can->IER |= CAN_IER_FMPIE0; + break; + case 2: + /* Fetches the message.*/ + rir = canp->can->sFIFOMailBox[1].RIR; + rdtr = canp->can->sFIFOMailBox[1].RDTR; + crfp->data32[0] = canp->can->sFIFOMailBox[1].RDLR; + crfp->data32[1] = canp->can->sFIFOMailBox[1].RDHR; + + /* Releases the mailbox.*/ + canp->can->RF1R = CAN_RF1R_RFOM1; + + /* If the queue is empty re-enables the interrupt in order to generate + events again.*/ + if ((canp->can->RF1R & CAN_RF1R_FMP1) == 0) + canp->can->IER |= CAN_IER_FMPIE1; + break; + default: + /* Should not happen, do nothing.*/ + return; + } + + /* Decodes the various fields in the RX frame.*/ + crfp->RTR = (rir & CAN_RI0R_RTR) >> 1; + crfp->IDE = (rir & CAN_RI0R_IDE) >> 2; + if (crfp->IDE) + crfp->EID = rir >> 3; + else + crfp->SID = rir >> 21; + crfp->DLC = rdtr & CAN_RDT0R_DLC; + crfp->FMI = (uint8_t)(rdtr >> 8); + crfp->TIME = (uint16_t)(rdtr >> 16); +} + +/** + * @brief Tries to abort an ongoing transmission. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number + * + * @notapi + */ +void can_lld_abort(CANDriver *canp, + canmbx_t mailbox) { + + canp->can->TSR = 128U << ((mailbox - 1U) * 8U); +} + +#if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) +/** + * @brief Enters the sleep mode. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_sleep(CANDriver *canp) { + + canp->can->MCR |= CAN_MCR_SLEEP; +} + +/** + * @brief Enforces leaving the sleep mode. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_wakeup(CANDriver *canp) { + + canp->can->MCR &= ~CAN_MCR_SLEEP; +} +#endif /* CAN_USE_SLEEP_MODE */ + +/** + * @brief Programs the filters. + * @note This is an STM32-specific API. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] can2sb number of the first filter assigned to CAN2 + * @param[in] num number of entries in the filters array, if zero then + * a default filter is programmed + * @param[in] cfp pointer to the filters array, can be @p NULL if + * (num == 0) + * + * @api + */ +void canSTM32SetFilters(CANDriver *canp, uint32_t can2sb, + uint32_t num, const CANFilter *cfp) { + +#if STM32_CAN_USE_CAN2 + osalDbgCheck((can2sb <= STM32_CAN_MAX_FILTERS) && + (num <= STM32_CAN_MAX_FILTERS)); +#endif + +#if STM32_CAN_USE_CAN1 + osalDbgAssert(CAND1.state == CAN_STOP, "invalid state"); +#endif +#if STM32_CAN_USE_CAN2 + osalDbgAssert(CAND2.state == CAN_STOP, "invalid state"); +#endif +#if STM32_CAN_USE_CAN3 + osalDbgAssert(CAND3.state == CAN_STOP, "invalid state"); +#endif + +#if STM32_CAN_USE_CAN1 + if (canp == &CAND1) { + can_lld_set_filters(canp, can2sb, num, cfp); + } +#endif +#if STM32_CAN_USE_CAN3 + if (canp == &CAND3) { + can_lld_set_filters(canp, can2sb, num, cfp); + } +#endif +} + +#endif /* HAL_USE_CAN */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h new file mode 100644 index 0000000..e4eb6f6 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h @@ -0,0 +1,471 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file CANv1/hal_can_lld.h + * @brief STM32 CAN subsystem low level driver header. + * + * @addtogroup CAN + * @{ + */ + +#ifndef HAL_CAN_LLD_H +#define HAL_CAN_LLD_H + +#if HAL_USE_CAN || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* + * The following macros from the ST header file are replaced with better + * equivalents. + */ +#undef CAN_BTR_BRP +#undef CAN_BTR_TS1 +#undef CAN_BTR_TS2 +#undef CAN_BTR_SJW + +/** + * @brief This switch defines whether the driver implementation supports + * a low power switch mode with automatic an wakeup feature. + */ +#define CAN_SUPPORTS_SLEEP TRUE + +/** + * @brief This implementation supports three transmit mailboxes. + */ +#define CAN_TX_MAILBOXES 3 + +/** + * @brief This implementation supports two receive mailboxes. + */ +#define CAN_RX_MAILBOXES 2 + +/** + * @name CAN registers helper macros + * @{ + */ +#define CAN_BTR_BRP(n) (n) /**< @brief BRP field macro.*/ +#define CAN_BTR_TS1(n) ((n) << 16) /**< @brief TS1 field macro.*/ +#define CAN_BTR_TS2(n) ((n) << 20) /**< @brief TS2 field macro.*/ +#define CAN_BTR_SJW(n) ((n) << 24) /**< @brief SJW field macro.*/ + +#define CAN_IDE_STD 0 /**< @brief Standard id. */ +#define CAN_IDE_EXT 1 /**< @brief Extended id. */ + +#define CAN_RTR_DATA 0 /**< @brief Data frame. */ +#define CAN_RTR_REMOTE 1 /**< @brief Remote frame. */ +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief CAN pedantic errors report. + * @details Use of this option is IRQ-intensive. + */ +#if !defined(STM32_CAN_REPORT_ALL_ERRORS) || defined(__DOXYGEN__) +#define STM32_CAN_REPORT_ALL_ERRORS FALSE +#endif + +/** + * @brief CAN1 driver enable switch. + * @details If set to @p TRUE the support for CAN1 is included. + */ +#if !defined(STM32_CAN_USE_CAN1) || defined(__DOXYGEN__) +#define STM32_CAN_USE_CAN1 FALSE +#endif + +/** + * @brief CAN2 driver enable switch. + * @details If set to @p TRUE the support for CAN2 is included. + */ +#if !defined(STM32_CAN_USE_CAN2) || defined(__DOXYGEN__) +#define STM32_CAN_USE_CAN2 FALSE +#endif + +/** + * @brief CAN3 driver enable switch. + * @details If set to @p TRUE the support for CAN3 is included. + */ +#if !defined(STM32_CAN_USE_CAN3) || defined(__DOXYGEN__) +#define STM32_CAN_USE_CAN3 FALSE +#endif + +/** + * @brief CAN1 interrupt priority level setting. + */ +#if !defined(STM32_CAN_CAN1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CAN_CAN1_IRQ_PRIORITY 11 +#endif +/** @} */ + +/** + * @brief CAN2 interrupt priority level setting. + */ +#if !defined(STM32_CAN_CAN2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CAN_CAN2_IRQ_PRIORITY 11 +#endif +/** @} */ + +/** + * @brief CAN3 interrupt priority level setting. + */ +#if !defined(STM32_CAN_CAN3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CAN_CAN3_IRQ_PRIORITY 11 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_CAN1) +#error "STM32_HAS_CAN1 not defined in registry" +#endif + +#if !defined(STM32_HAS_CAN2) +#error "STM32_HAS_CAN2 not defined in registry" +#endif + +#if !defined(STM32_HAS_CAN3) +#error "STM32_HAS_CAN3 not defined in registry" +#endif + +#if (STM32_HAS_CAN1 | STM32_HAS_CAN2) && !defined(STM32_CAN_MAX_FILTERS) +#error "STM32_CAN_MAX_FILTERS not defined in registry" +#endif + +#if STM32_HAS_CAN3 && !defined(STM32_CAN3_MAX_FILTERS) +#error "STM32_CAN3_MAX_FILTERS not defined in registry" +#endif + +#if STM32_CAN_USE_CAN1 && !STM32_HAS_CAN1 +#error "CAN1 not present in the selected device" +#endif + +#if STM32_CAN_USE_CAN2 && !STM32_HAS_CAN2 +#error "CAN2 not present in the selected device" +#endif + +#if STM32_CAN_USE_CAN3 && !STM32_HAS_CAN3 +#error "CAN2 not present in the selected device" +#endif + +#if !STM32_CAN_USE_CAN1 && !STM32_CAN_USE_CAN2 && !STM32_CAN_USE_CAN3 +#error "CAN driver activated but no CAN peripheral assigned" +#endif + +#if !STM32_CAN_USE_CAN1 && STM32_CAN_USE_CAN2 +#error "CAN2 requires CAN1, it cannot operate independently" +#endif + +#if CAN_USE_SLEEP_MODE && !CAN_SUPPORTS_SLEEP +#error "CAN sleep mode not supported in this architecture" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an CAN driver. + */ +typedef struct CANDriver CANDriver; + +/** + * @brief Type of a transmission mailbox index. + */ +typedef uint32_t canmbx_t; + +#if (CAN_ENFORCE_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) +/** + * @brief Type of a CAN notification callback. + * + * @param[in] canp pointer to the @p CANDriver object triggering the + * callback + * @param[in] flags flags associated to the mailbox callback + */ +typedef void (*can_callback_t)(CANDriver *canp, uint32_t flags); +#endif + +/** + * @brief CAN transmission frame. + * @note Accessing the frame data as word16 or word32 is not portable because + * machine data endianness, it can be still useful for a quick filling. + */ +typedef struct { + struct { + uint8_t DLC:4; /**< @brief Data length. */ + uint8_t RTR:1; /**< @brief Frame type. */ + uint8_t IDE:1; /**< @brief Identifier type. */ + }; + union { + struct { + uint32_t SID:11; /**< @brief Standard identifier.*/ + }; + struct { + uint32_t EID:29; /**< @brief Extended identifier.*/ + }; + }; + union { + uint8_t data8[8]; /**< @brief Frame data. */ + uint16_t data16[4]; /**< @brief Frame data. */ + uint32_t data32[2]; /**< @brief Frame data. */ + uint64_t data64[1]; /**< @brief Frame data. */ + }; +} CANTxFrame; + +/** + * @brief CAN received frame. + * @note Accessing the frame data as word16 or word32 is not portable because + * machine data endianness, it can be still useful for a quick filling. + */ +typedef struct { + struct { + uint8_t FMI; /**< @brief Filter id. */ + uint16_t TIME; /**< @brief Time stamp. */ + }; + struct { + uint8_t DLC:4; /**< @brief Data length. */ + uint8_t RTR:1; /**< @brief Frame type. */ + uint8_t IDE:1; /**< @brief Identifier type. */ + }; + union { + struct { + uint32_t SID:11; /**< @brief Standard identifier.*/ + }; + struct { + uint32_t EID:29; /**< @brief Extended identifier.*/ + }; + }; + union { + uint8_t data8[8]; /**< @brief Frame data. */ + uint16_t data16[4]; /**< @brief Frame data. */ + uint32_t data32[2]; /**< @brief Frame data. */ + uint64_t data64[1]; /**< @brief Frame data. */ + }; +} CANRxFrame; + +/** + * @brief CAN filter. + * @note Refer to the STM32 reference manual for info about filters. + */ +typedef struct { + /** + * @brief Number of the filter bank to be programmed. + */ + uint32_t filter:16; + /** + * @brief Filter mode. + * @note This bit represent the CAN_FM1R register bit associated to this + * filter (0=mask mode, 1=list mode). + */ + uint32_t mode:1; + /** + * @brief Filter scale. + * @note This bit represent the CAN_FS1R register bit associated to this + * filter (0=16 bits mode, 1=32 bits mode). + */ + uint32_t scale:1; + /** + * @brief Filter mode. + * @note This bit represent the CAN_FFA1R register bit associated to this + * filter, must be set to zero in this version of the driver. + */ + uint32_t assignment:1; + /** + * @brief Filter register 1 (identifier). + */ + uint32_t register1; + /** + * @brief Filter register 2 (mask/identifier depending on mode=0/1). + */ + uint32_t register2; +} CANFilter; + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief CAN MCR register initialization data. + * @note Some bits in this register are enforced by the driver regardless + * their status in this field. + */ + uint32_t mcr; + /** + * @brief CAN BTR register initialization data. + * @note Some bits in this register are enforced by the driver regardless + * their status in this field. + */ + uint32_t btr; +} CANConfig; + +/** + * @brief Structure representing an CAN driver. + */ +struct CANDriver { + /** + * @brief Driver state. + */ + canstate_t state; + /** + * @brief Current configuration data. + */ + const CANConfig *config; + /** + * @brief Transmission threads queue. + */ + threads_queue_t txqueue; + /** + * @brief Receive threads queue. + */ + threads_queue_t rxqueue; +#if (CAN_ENFORCE_USE_CALLBACKS == FALSE) || defined(__DOXYGEN__) + /** + * @brief One or more frames become available. + * @note After broadcasting this event it will not be broadcasted again + * until the received frames queue has been completely emptied. It + * is not broadcasted for each received frame. It is + * responsibility of the application to empty the queue by + * repeatedly invoking @p canReceive() when listening to this event. + * This behavior minimizes the interrupt served by the system + * because CAN traffic. + * @note The flags associated to the listeners will indicate which + * receive mailboxes become non-empty. + */ + event_source_t rxfull_event; + /** + * @brief One or more transmission mailbox become available. + * @note The flags associated to the listeners will indicate which + * transmit mailboxes become empty. + * @note The upper 16 bits are transmission error flags associated + * to the transmit mailboxes. + */ + event_source_t txempty_event; + /** + * @brief A CAN bus error happened. + * @note The flags associated to the listeners will indicate that + * receive error(s) have occurred. + * @note In this implementation the upper 16 bits are filled with the + * unprocessed content of the ESR register. + */ + event_source_t error_event; +#if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__) + /** + * @brief Entering sleep state event. + */ + event_source_t sleep_event; + /** + * @brief Exiting sleep state event. + */ + event_source_t wakeup_event; +#endif /* CAN_USE_SLEEP_MODE */ +#else /* CAN_ENFORCE_USE_CALLBACKS == TRUE */ + /** + * @brief One or more frames become available. + * @note After calling this function it will not be called again + * until the received frames queue has been completely emptied. It + * is not called for each received frame. It is + * responsibility of the application to empty the queue by + * repeatedly invoking @p chTryReceiveI(). + * This behavior minimizes the interrupt served by the system + * because CAN traffic. + */ + can_callback_t rxfull_cb; + /** + * @brief One or more transmission mailbox become available. + * @note The flags associated to the callback will indicate which + * transmit mailboxes become empty. + */ + can_callback_t txempty_cb; + /** + * @brief A CAN bus error happened. + */ + can_callback_t error_cb; +#if (CAN_USE_SLEEP_MODE == TRUE) || defined (__DOXYGEN__) + /** + * @brief Exiting sleep state. + */ + can_callback_t wakeup_cb; +#endif +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the CAN registers. + */ + CAN_TypeDef *can; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_CAN_USE_CAN1 && !defined(__DOXYGEN__) +extern CANDriver CAND1; +#endif + +#if STM32_CAN_USE_CAN2 && !defined(__DOXYGEN__) +extern CANDriver CAND2; +#endif + +#if STM32_CAN_USE_CAN3 && !defined(__DOXYGEN__) +extern CANDriver CAND3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void can_lld_init(void); + void can_lld_start(CANDriver *canp); + void can_lld_stop(CANDriver *canp); + bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox); + void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *crfp); + bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox); + void can_lld_receive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *ctfp); + void can_lld_abort(CANDriver *canp, + canmbx_t mailbox); +#if CAN_USE_SLEEP_MODE + void can_lld_sleep(CANDriver *canp); + void can_lld_wakeup(CANDriver *canp); +#endif /* CAN_USE_SLEEP_MODE */ + void canSTM32SetFilters(CANDriver *canp, uint32_t can2sb, + uint32_t num, const CANFilter *cfp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_CAN */ + +#endif /* HAL_CAN_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/driver.mk new file mode 100644 index 0000000..43936d3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_CRY TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CRYPv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c new file mode 100644 index 0000000..6bb0448 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c @@ -0,0 +1,1901 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file CRYPv1/hal_crypto_lld.c + * @brief STM32 cryptographic subsystem low level driver source. + * + * @addtogroup CRYPTO + * @{ + */ + +#include + +#include "hal.h" + +#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define CRYP1_IN_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_CRY_CRYP1_IN_DMA_STREAM, \ + STM32_CRYP1_IN_DMA_CHN) + +#define CRYP1_OUT_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_CRY_CRYP1_OUT_DMA_STREAM, \ + STM32_CRYP1_OUT_DMA_CHN) + +#define HASH1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_CRY_HASH1_DMA_STREAM, \ + STM32_HASH1_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief CRY1 driver identifier.*/ +#if (STM32_CRY_ENABLED1 == TRUE) || defined(__DOXYGEN__) +CRYDriver CRYD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (STM32_CRY_USE_CRYP1 == TRUE) || defined (__DOXYGEN__) +/** + * @brief Setting AES key for encryption. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] algomode algorithm mode field of CR register + */ +static inline void cryp_set_key_encrypt(CRYDriver *cryp, uint32_t algomode) { + uint32_t cr; + + /* Loading key data.*/ + CRYP->K0LR = cryp->cryp_k[0]; + CRYP->K0RR = cryp->cryp_k[1]; + CRYP->K1LR = cryp->cryp_k[2]; + CRYP->K1RR = cryp->cryp_k[3]; + CRYP->K2LR = cryp->cryp_k[4]; + CRYP->K2RR = cryp->cryp_k[5]; + CRYP->K3LR = cryp->cryp_k[6]; + CRYP->K3RR = cryp->cryp_k[7]; + + /* Setting up then starting operation.*/ + cr = CRYP->CR; + cr &= ~(CRYP_CR_KEYSIZE_Msk | CRYP_CR_ALGOMODE_Msk | CRYP_CR_ALGODIR_Msk); + cr |= cryp->cryp_ksize | algomode | CRYP_CR_CRYPEN; + CRYP->CR = cr; + + cryp->cryp_ktype = cryp_key_aes_encrypt; +} + +/** + * @brief Setting AES key for decryption. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] algomode algorithm field of CR register + */ +static inline void cryp_set_key_decrypt(CRYDriver *cryp, uint32_t algomode) { + uint32_t cr; + + /* Loading key data then doing transformation for decrypt.*/ + cryp_set_key_encrypt(cryp, CRYP_CR_ALGOMODE_AES_KEY); + while ((CRYP->CR & CRYP_CR_CRYPEN) != 0U) { + } + + /* Setting up then starting operation.*/ + cr = CRYP->CR; + cr &= ~(CRYP_CR_KEYSIZE_Msk | CRYP_CR_ALGOMODE_Msk | CRYP_CR_ALGODIR_Msk); + cr |= cryp->cryp_ksize | algomode | CRYP_CR_ALGODIR | CRYP_CR_CRYPEN; + CRYP->CR = cr; + + cryp->cryp_ktype = cryp_key_aes_decrypt; +} + +/** + * @brief Setting IV. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] iv 128 bits initial vector + */ +static inline void cryp_set_iv(CRYDriver *cryp, const uint8_t *iv) { + + (void)cryp; + + CRYP->IV0LR = __REV(__UNALIGNED_UINT32_READ(&iv[0])); + CRYP->IV0RR = __REV(__UNALIGNED_UINT32_READ(&iv[4])); + CRYP->IV1LR = __REV(__UNALIGNED_UINT32_READ(&iv[8])); + CRYP->IV1RR = __REV(__UNALIGNED_UINT32_READ(&iv[12])); +} + +/** + * @brief Performs a CRYP operation using DMA. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] size size of both buffers, this number must be a + * multiple of 16 + * @param[in] in input buffer + * @param[out] out output buffer + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + */ +static cryerror_t cryp_do_transfer(CRYDriver *cryp, + size_t size, + const uint8_t *in, + uint8_t *out) { + uint32_t szw; + + szw = (uint32_t)(size / sizeof (uint32_t)); +#if STM32_CRY_CRYP_SIZE_THRESHOLD > 1 + if (size >= STM32_CRY_CRYP_SIZE_THRESHOLD) +#endif +#if STM32_CRY_CRYP_SIZE_THRESHOLD != 0 + { + /* DMA limitation.*/ + osalDbgCheck(size < 0x10000U * 4U); + + osalSysLock(); + + /* Preparing DMAs.*/ + dmaStreamSetTransactionSize(cryp->cryp_dma_in, szw); + dmaStreamSetTransactionSize(cryp->cryp_dma_out, szw); + dmaStreamSetMemory0(cryp->cryp_dma_in, in); + dmaStreamSetMemory0(cryp->cryp_dma_out, out); + dmaStreamEnable(cryp->cryp_dma_in); + dmaStreamEnable(cryp->cryp_dma_out); + + (void) osalThreadSuspendS(&cryp->cryp_tr); + + osalSysUnlock(); + } +#endif +#if STM32_CRY_CRYP_SIZE_THRESHOLD > 1 + else +#endif +#if STM32_CRY_CRYP_SIZE_THRESHOLD != 1 + { + uint32_t nr, nw; + + nr = 0U; + nw = 0U; + while (nw < szw) { + + if ((CRYP->SR & CRYP_SR_OFNE) != 0U) { + __UNALIGNED_UINT32_WRITE(out, CRYP->DOUT); + out += 4; + nw++; + continue; /* Priority to output FIFO.*/ + } + + if ((nr < szw) && ((CRYP->SR & CRYP_SR_IFNF) != 0U)) { + CRYP->DR = __UNALIGNED_UINT32_READ(in); + in += 4; + nr++; + } + } + } +#endif + + /* Disabling unit.*/ + CRYP->CR &= ~CRYP_CR_CRYPEN; + + return CRY_NOERROR; +} + +/** + * @brief CRYP-IN DMA ISR. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void cry_lld_serve_cryp_in_interrupt(CRYDriver *cryp, uint32_t flags) { + + (void)cryp; + + /* DMA errors handling.*/ +#if defined(STM32_CRY_CRYP_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) { + STM32_CRY_CRYP_DMA_ERROR_HOOK(cryp); + } +#endif +} + +/** + * @brief CRYP-OUT DMA ISR. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void cry_lld_serve_cryp_out_interrupt(CRYDriver *cryp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_CRY_CRYP_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) { + STM32_CRY_CRYP_DMA_ERROR_HOOK(cryp); + } +#endif + + /* End buffer interrupt.*/ + if ((flags & STM32_DMA_ISR_TCIF) != 0U) { + + /* Clearing flags of the other stream too.*/ + dmaStreamClearInterrupt(cryp->cryp_dma_in); + + /* Resuming waiting thread.*/ + osalSysLockFromISR(); + osalThreadResumeI(&cryp->cryp_tr, MSG_OK); + osalSysUnlockFromISR(); + } +} +#endif + +#if (STM32_CRY_USE_HASH1 == TRUE) || defined (__DOXYGEN__) +#if (STM32_CRY_HASH_SIZE_THRESHOLD != 0) || defined (__DOXYGEN__) +/** + * @brief HASH DMA ISR. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void cry_lld_serve_hash_interrupt(CRYDriver *cryp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_HASH_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) { + STM32_CRY_HASH_DMA_ERROR_HOOK(cryp); + } +#endif + + /* End buffer interrupt.*/ + if ((flags & STM32_DMA_ISR_TCIF) != 0U) { + + /* Resuming waiting thread.*/ + osalSysLockFromISR(); + osalThreadResumeI(&cryp->hash_tr, MSG_OK); + osalSysUnlockFromISR(); + } +} +#endif +#endif + +/** + * @brief Pushes a series of words into the hash engine. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] n the number of words to be pushed + * @param[in] p pointer to the words buffer + */ +static void cry_lld_hash_push(CRYDriver *cryp, uint32_t n, const uint32_t *p) { + + (void)cryp; /* Not touched in some cases, needs this.*/ + + /* Data is processed in 32kB blocks because DMA size limitations.*/ + while (n > 0U) { + uint32_t chunk = n > 0x8000U ? 0x8000U : n; + n -= chunk; + +#if STM32_CRY_HASH_SIZE_THRESHOLD > 1 + if (chunk >= STM32_CRY_HASH_SIZE_THRESHOLD) +#endif +#if STM32_CRY_HASH_SIZE_THRESHOLD != 0 + { + /* Setting up transfer.*/ + dmaStreamSetTransactionSize(cryp->hash_dma, chunk); + dmaStreamSetPeripheral(cryp->hash_dma, p); + p += chunk; + + osalSysLock(); + + /* Enabling DMA channel then HASH engine.*/ + dmaStreamEnable(cryp->hash_dma); + + /* Waiting for DMA operation completion.*/ + osalThreadSuspendS(&cryp->hash_tr); + + osalSysUnlock(); + } +#endif +#if STM32_CRY_HASH_SIZE_THRESHOLD > 1 + else +#endif +#if STM32_CRY_HASH_SIZE_THRESHOLD != 1 + { + /* Small chunk, just pushing data without touching DMA.*/ + do { + HASH->DIN = *p++; + chunk--; + } while (chunk > 0U); + } +#endif + } + +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level crypto driver initialization. + * + * @notapi + */ +void cry_lld_init(void) { + +#if STM32_CRY_ENABLED1 + cryObjectInit(&CRYD1); + +#if STM32_CRY_USE_CRYP1 +#if STM32_CRY_CRYP_SIZE_THRESHOLD != 0 + CRYD1.cryp_tr = NULL; + CRYD1.cryp_dma_in = NULL; + CRYD1.cryp_dma_out = NULL; +#endif +#endif + +#if STM32_CRY_USE_HASH1 +#if STM32_CRY_HASH_SIZE_THRESHOLD != 0 + CRYD1.hash_tr = NULL; + CRYD1.hash_dma = NULL; +#endif /* STM32_CRY_HASH_SIZE_THRESHOLD != 0 */ +#endif /* STM32_CRY_USE_HASH1 */ + +#endif /* STM32_CRY_ENABLED1 */ +} + +/** + * @brief Configures and activates the crypto peripheral. + * + * @param[in] cryp pointer to the @p CRYDriver object + * + * @notapi + */ +void cry_lld_start(CRYDriver *cryp) { + + if (cryp->state == CRY_STOP) { + +#if STM32_CRY_ENABLED1 + if (&CRYD1 == cryp) { +#if STM32_CRY_USE_CRYP1 == TRUE +#if STM32_CRY_CRYP_SIZE_THRESHOLD != 0 + /* Allocating DMA channels.*/ + cryp->cryp_dma_in = dmaStreamAllocI(STM32_CRY_CRYP1_IN_DMA_STREAM, + STM32_CRY_CRYP1_IRQ_PRIORITY, + (stm32_dmaisr_t)cry_lld_serve_cryp_in_interrupt, + (void *)cryp); + osalDbgAssert(cryp->cryp_dma_in != NULL, "unable to allocate stream"); + cryp->cryp_dma_out = dmaStreamAllocI(STM32_CRY_CRYP1_OUT_DMA_STREAM, + STM32_CRY_CRYP1_IRQ_PRIORITY, + (stm32_dmaisr_t)cry_lld_serve_cryp_out_interrupt, + (void *)cryp); + osalDbgAssert(cryp->cryp_dma_out != NULL, "unable to allocate stream"); + + /* Preparing the DMA channels.*/ + dmaStreamSetMode(cryp->cryp_dma_in, + STM32_DMA_CR_CHSEL(CRYP1_IN_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_CRY_CRYP1_IN_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE); + dmaStreamSetMode(cryp->cryp_dma_out, + STM32_DMA_CR_CHSEL(CRYP1_OUT_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_CRY_CRYP1_OUT_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_TCIE); + dmaStreamSetPeripheral(cryp->cryp_dma_in, &CRYP->DR); + dmaStreamSetPeripheral(cryp->cryp_dma_out, &CRYP->DOUT); + dmaStreamSetFIFO(cryp->cryp_dma_in, STM32_DMA_FCR_DMDIS); + dmaStreamSetFIFO(cryp->cryp_dma_out, STM32_DMA_FCR_DMDIS); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(cryp->dma_cryp_in, STM32_DMAMUX1_CRYP_IN); + dmaSetRequestSource(cryp->dma_cryp_out, STM32_DMAMUX1_CRYP_OUT); +#endif +#endif /* STM32_CRY_CRYP_SIZE_THRESHOLD != 0 */ + rccEnableCRYP(true); +#endif /* STM32_CRY_USE_CRYP1 == TRUE */ + +#if STM32_CRY_USE_HASH1 == TRUE +#if STM32_CRY_HASH_SIZE_THRESHOLD != 0 + cryp->hash_dma = dmaStreamAllocI(STM32_CRY_HASH1_DMA_STREAM, + STM32_CRY_HASH1_IRQ_PRIORITY, + (stm32_dmaisr_t)cry_lld_serve_hash_interrupt, + (void *)cryp); + osalDbgAssert(cryp->hash_dma != NULL, "unable to allocate stream"); + + /* Preparing the DMA channel.*/ + dmaStreamSetMode(cryp->hash_dma, + STM32_DMA_CR_CHSEL(HASH1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_CRY_HASH1_DMA_PRIORITY) | + STM32_DMA_CR_PINC | STM32_DMA_CR_DIR_M2M | + STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_TCIE); + dmaStreamSetMemory0(cryp->hash_dma, &HASH->DIN); + dmaStreamSetFIFO(cryp->hash_dma, STM32_DMA_FCR_DMDIS); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(cryp->dma_hash, STM32_DMAMUX1_HASH); +#endif +#endif /* STM32_CRY_HASH_SIZE_THRESHOLD != 0 */ + rccEnableHASH(true); +#endif /* STM32_CRY_USE_HASH1 == TRUE */ + } +#endif + } + + /* Resetting trasient key data.*/ + cryp->cryp_ktype = cryp_key_none; + cryp->cryp_ksize = 0U; + cryp->cryp_k[0] = 0U; + cryp->cryp_k[1] = 0U; + cryp->cryp_k[2] = 0U; + cryp->cryp_k[3] = 0U; + cryp->cryp_k[4] = 0U; + cryp->cryp_k[5] = 0U; + cryp->cryp_k[6] = 0U; + cryp->cryp_k[7] = 0U; + +#if STM32_CRY_USE_CRYP1 + /* CRYP setup.*/ + CRYP->CR = CRYP_CR_DATATYPE_1; + CRYP->DMACR = CRYP_DMACR_DIEN | CRYP_DMACR_DOEN; +#endif + +#if STM32_CRY_USE_HASH1 + /* HASH setup and enable.*/ +#endif +} + +/** + * @brief Deactivates the crypto peripheral. + * + * @param[in] cryp pointer to the @p CRYDriver object + * + * @notapi + */ +void cry_lld_stop(CRYDriver *cryp) { + + if (cryp->state == CRY_READY) { + + /* Resetting CRYP.*/ + CRYP->CR = 0U; + CRYP->DMACR = 0U; + +#if STM32_CRY_ENABLED1 + if (&CRYD1 == cryp) { +#if STM32_CRY_USE_CRYP1 +#if STM32_CRY_CRYP_SIZE_THRESHOLD != 0 + dmaStreamFreeI(cryp->cryp_dma_in); + dmaStreamFreeI(cryp->cryp_dma_out); + cryp->cryp_dma_in = NULL; + cryp->cryp_dma_out = NULL; +#endif + rccDisableCRYP(); +#endif + +#if STM32_CRY_USE_HASH1 +#if STM32_CRY_HASH_SIZE_THRESHOLD != 0 + dmaStreamFreeI(cryp->hash_dma); + cryp->hash_dma = NULL; +#endif + rccDisableHASH(); +#endif + } +#endif + } +} + +#if (CRY_LLD_SUPPORTS_AES == TRUE) || defined(__DOXYGEN__) +/** + * @brief Initializes the AES transient key. + * @note It is the underlying implementation to decide which key sizes are + * allowable. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] size key size in bytes + * @param[in] keyp pointer to the key data + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the algorithm is unsupported. + * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid for + * the specified algorithm. + * + * @notapi + */ +cryerror_t cry_lld_aes_loadkey(CRYDriver *cryp, + size_t size, + const uint8_t *keyp) { + + /* Fetching key data.*/ + if (size == (size_t)32) { + cryp->cryp_ksize = CRYP_CR_KEYSIZE_1; + cryp->cryp_k[0] = __REV(__UNALIGNED_UINT32_READ(&keyp[0])); + cryp->cryp_k[1] = __REV(__UNALIGNED_UINT32_READ(&keyp[4])); + cryp->cryp_k[2] = __REV(__UNALIGNED_UINT32_READ(&keyp[8])); + cryp->cryp_k[3] = __REV(__UNALIGNED_UINT32_READ(&keyp[12])); + cryp->cryp_k[4] = __REV(__UNALIGNED_UINT32_READ(&keyp[16])); + cryp->cryp_k[5] = __REV(__UNALIGNED_UINT32_READ(&keyp[20])); + cryp->cryp_k[6] = __REV(__UNALIGNED_UINT32_READ(&keyp[24])); + cryp->cryp_k[7] = __REV(__UNALIGNED_UINT32_READ(&keyp[28])); + } + else if (size == (size_t)24) { + cryp->cryp_ksize = CRYP_CR_KEYSIZE_0; + cryp->cryp_k[0] = 0U; + cryp->cryp_k[1] = 0U; + cryp->cryp_k[2] = __REV(__UNALIGNED_UINT32_READ(&keyp[8])); + cryp->cryp_k[3] = __REV(__UNALIGNED_UINT32_READ(&keyp[12])); + cryp->cryp_k[4] = __REV(__UNALIGNED_UINT32_READ(&keyp[16])); + cryp->cryp_k[5] = __REV(__UNALIGNED_UINT32_READ(&keyp[20])); + cryp->cryp_k[6] = __REV(__UNALIGNED_UINT32_READ(&keyp[24])); + cryp->cryp_k[7] = __REV(__UNALIGNED_UINT32_READ(&keyp[28])); + } + else if (size == (size_t)16) { + cryp->cryp_ksize = 0U; + cryp->cryp_k[0] = 0U; + cryp->cryp_k[1] = 0U; + cryp->cryp_k[2] = 0U; + cryp->cryp_k[3] = 0U; + cryp->cryp_k[4] = __REV(__UNALIGNED_UINT32_READ(&keyp[16])); + cryp->cryp_k[5] = __REV(__UNALIGNED_UINT32_READ(&keyp[20])); + cryp->cryp_k[6] = __REV(__UNALIGNED_UINT32_READ(&keyp[24])); + cryp->cryp_k[7] = __REV(__UNALIGNED_UINT32_READ(&keyp[28])); + } + else { + return CRY_ERR_INV_KEY_SIZE; + } + + return CRY_NOERROR; +} + +/** + * @brief Encryption of a single block using AES. + * @note The implementation of this function must guarantee that it can + * be called from any context. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_encrypt_AES(CRYDriver *cryp, + crykey_t key_id, + const uint8_t *in, + uint8_t *out) { + unsigned i; + + /* Only key zero is supported.*/ + if (key_id != 0U) { + return CRY_ERR_INV_KEY_ID; + } + + /* Setting the stored key.*/ + if (cryp->cryp_ktype != cryp_key_aes_encrypt) { + cryp_set_key_encrypt(cryp, CRYP_CR_ALGOMODE_AES_ECB); + } + + /* Pushing the AES block in the FIFO, it is assumed to be empty.*/ + CRYP->DR = __UNALIGNED_UINT32_READ(&in[0]); + CRYP->DR = __UNALIGNED_UINT32_READ(&in[4]); + CRYP->DR = __UNALIGNED_UINT32_READ(&in[8]); + CRYP->DR = __UNALIGNED_UINT32_READ(&in[12]); + + /* Reading the result.*/ + for (i = 0U; i < 4; i++, out += 4) { + while ((CRYP->SR & CRYP_SR_OFNE) == 0U) { + } + __UNALIGNED_UINT32_WRITE(out, CRYP->DOUT); + } + + /* Disabling unit.*/ + CRYP->CR &= ~CRYP_CR_CRYPEN; + + return CRY_NOERROR; +} + +/** + * @brief Decryption of a single block using AES. + * @note The implementation of this function must guarantee that it can + * be called from any context. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] in buffer containing the input ciphertext + * @param[out] out buffer for the output plaintext + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_decrypt_AES(CRYDriver *cryp, + crykey_t key_id, + const uint8_t *in, + uint8_t *out) { + unsigned i; + + /* Only key zero is supported.*/ + if (key_id != 0U) { + return CRY_ERR_INV_KEY_ID; + } + + /* Setting the stored key.*/ + if (cryp->cryp_ktype != cryp_key_aes_decrypt) { + cryp_set_key_decrypt(cryp, CRYP_CR_ALGOMODE_AES_ECB); + } + + /* Pushing the AES block in the FIFO, it is assumed to be empty.*/ + CRYP->DR = __UNALIGNED_UINT32_READ(&in[0]); + CRYP->DR = __UNALIGNED_UINT32_READ(&in[4]); + CRYP->DR = __UNALIGNED_UINT32_READ(&in[8]); + CRYP->DR = __UNALIGNED_UINT32_READ(&in[12]); + + /* Reading the result.*/ + for (i = 0U; i < 4; i++, out += 4) { + while ((CRYP->SR & CRYP_SR_OFNE) == 0U) { + } + __UNALIGNED_UINT32_WRITE(out, CRYP->DOUT); + } + + /* Disabling unit.*/ + CRYP->CR &= ~CRYP_CR_CRYPEN; + + return CRY_NOERROR; +} +#endif + +#if (CRY_LLD_SUPPORTS_AES_ECB == TRUE) || defined(__DOXYGEN__) +/** + * @brief Encryption operation using AES-ECB. + * @note The function operates on data buffers whose length is a multiple + * of an AES block, this means that padding must be done by the + * caller. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of both buffers, this number must be a + * multiple of 16 + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_encrypt_AES_ECB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out) { + + /* Only key zero is supported.*/ + if (key_id != 0U) { + return CRY_ERR_INV_KEY_ID; + } + + /* Setting the stored key.*/ + if (cryp->cryp_ktype != cryp_key_aes_encrypt) { + cryp_set_key_encrypt(cryp, CRYP_CR_ALGOMODE_AES_ECB); + } + + return cryp_do_transfer(cryp, size, in, out); +} + +/** + * @brief Decryption operation using AES-ECB. + * @note The function operates on data buffers whose length is a multiple + * of an AES block, this means that padding must be done by the + * caller. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of both buffers, this number must be a + * multiple of 16 + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_decrypt_AES_ECB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out) { + + /* Only key zero is supported.*/ + if (key_id != 0U) { + return CRY_ERR_INV_KEY_ID; + } + + /* Setting the stored key.*/ + if (cryp->cryp_ktype != cryp_key_aes_decrypt) { + cryp_set_key_decrypt(cryp, CRYP_CR_ALGOMODE_AES_ECB); + } + + return cryp_do_transfer(cryp, size, in, out); +} +#endif + +#if (CRY_LLD_SUPPORTS_AES_CBC == TRUE) || defined(__DOXYGEN__) +/** + * @brief Encryption operation using AES-CBC. + * @note The function operates on data buffers whose length is a multiple + * of an AES block, this means that padding must be done by the + * caller. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of both buffers, this number must be a + * multiple of 16 + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @param[in] iv 128 bits initial vector + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_encrypt_AES_CBC(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv) { + + /* Only key zero is supported.*/ + if (key_id != 0U) { + return CRY_ERR_INV_KEY_ID; + } + + /* Setting the stored key and IV.*/ + cryp_set_iv(cryp, iv); + if (cryp->cryp_ktype != cryp_key_aes_encrypt) { + cryp_set_key_encrypt(cryp, CRYP_CR_ALGOMODE_AES_CBC); + } + + return cryp_do_transfer(cryp, size, in, out); +} + +/** + * @brief Decryption operation using AES-CBC. + * @note The function operates on data buffers whose length is a multiple + * of an AES block, this means that padding must be done by the + * caller. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of both buffers, this number must be a + * multiple of 16 + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @param[in] iv 128 bits initial vector + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_decrypt_AES_CBC(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv) { + + /* Only key zero is supported.*/ + if (key_id != 0U) { + return CRY_ERR_INV_KEY_ID; + } + + /* Setting the stored key and IV.*/ + cryp_set_iv(cryp, iv); + if (cryp->cryp_ktype != cryp_key_aes_decrypt) { + cryp_set_key_decrypt(cryp, CRYP_CR_ALGOMODE_AES_CBC); + } + + return cryp_do_transfer(cryp, size, in, out); +} +#endif + +#if (CRY_LLD_SUPPORTS_AES_CFB == TRUE) || defined(__DOXYGEN__) +/** + * @brief Encryption operation using AES-CFB. + * @note This is a stream cipher, there are no size restrictions. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of both buffers + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @param[in] iv 128 bits initial vector + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_encrypt_AES_CFB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv) { + + (void)cryp; + (void)key_id; + (void)size; + (void)in; + (void)out; + (void)iv; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Decryption operation using AES-CFB. + * @note This is a stream cipher, there are no size restrictions. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of both buffers + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @param[in] iv 128 bits initial vector + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_decrypt_AES_CFB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv) { + + (void)cryp; + (void)key_id; + (void)size; + (void)in; + (void)out; + (void)iv; + + return CRY_ERR_INV_ALGO; +} +#endif + +#if (CRY_LLD_SUPPORTS_AES_CTR == TRUE) || defined(__DOXYGEN__) +/** + * @brief Encryption operation using AES-CTR. + * @note This is a stream cipher, there are no size restrictions. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of both buffers + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @param[in] iv 128 bits initial vector + counter, it contains + * a 96 bits IV and a 32 bits counter + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_encrypt_AES_CTR(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv) { + + (void)cryp; + (void)key_id; + (void)size; + (void)in; + (void)out; + (void)iv; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Decryption operation using AES-CTR. + * @note This is a stream cipher, there are no size restrictions. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of both buffers + * @param[in] in buffer containing the input ciphertext + * @param[out] out buffer for the output plaintext + * @param[in] iv 128 bits initial vector + counter, it contains + * a 96 bits IV and a 32 bits counter + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_decrypt_AES_CTR(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv) { + + (void)cryp; + (void)key_id; + (void)size; + (void)in; + (void)out; + (void)iv; + + return CRY_ERR_INV_ALGO; +} +#endif + +#if (CRY_LLD_SUPPORTS_AES_GCM == TRUE) || defined(__DOXYGEN__) +/** + * @brief Encryption operation using AES-GCM. + * @note This is a stream cipher, there are no size restrictions. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] auth_size size of the data buffer to be authenticated + * @param[in] auth_in buffer containing the data to be authenticated + * @param[in] text_size size of the text buffer + * @param[in] text_in buffer containing the input plaintext + * @param[out] text_out buffer for the output ciphertext + * @param[in] iv 128 bits input vector + * @param[in] tag_size size of the authentication tag, this number + * must be between 1 and 16 + * @param[out] tag_out buffer for the generated authentication tag + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_encrypt_AES_GCM(CRYDriver *cryp, + crykey_t key_id, + size_t auth_size, + const uint8_t *auth_in, + size_t text_size, + const uint8_t *text_in, + uint8_t *text_out, + const uint8_t *iv, + size_t tag_size, + uint8_t *tag_out) { + + (void)cryp; + (void)key_id; + (void)auth_size; + (void)auth_in; + (void)text_size; + (void)text_in; + (void)text_out; + (void)iv; + (void)tag_size; + (void)tag_out; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Decryption operation using AES-GCM. + * @note This is a stream cipher, there are no size restrictions. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] auth_size size of the data buffer to be authenticated + * @param[in] auth_in buffer containing the data to be authenticated + * @param[in] text_size size of the text buffer + * @param[in] text_in buffer containing the input plaintext + * @param[out] text_out buffer for the output ciphertext + * @param[in] iv 128 bits input vector + * @param[in] tag_size size of the authentication tag, this number + * must be between 1 and 16 + * @param[in] tag_in buffer for the generated authentication tag + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_AUTH_FAILED authentication failed + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_decrypt_AES_GCM(CRYDriver *cryp, + crykey_t key_id, + size_t auth_size, + const uint8_t *auth_in, + size_t text_size, + const uint8_t *text_in, + uint8_t *text_out, + const uint8_t *iv, + size_t tag_size, + const uint8_t *tag_in) { + + (void)cryp; + (void)key_id; + (void)auth_size; + (void)auth_in; + (void)text_size; + (void)text_in; + (void)text_out; + (void)iv; + (void)tag_size; + (void)tag_in; + + return CRY_ERR_INV_ALGO; +} +#endif + +#if (CRY_LLD_SUPPORTS_DES == TRUE) || defined(__DOXYGEN__) +/** + * @brief Initializes the DES transient key. + * @note It is the underlying implementation to decide which key sizes are + * allowable. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] size key size in bytes + * @param[in] keyp pointer to the key data + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the algorithm is unsupported. + * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid for + * the specified algorithm. + * + * @notapi + */ +cryerror_t cry_lld_des_loadkey(CRYDriver *cryp, + size_t size, + const uint8_t *keyp) { + + (void)cryp; + (void)size; + (void)keyp; + + return CRY_NOERROR; +} + +/** + * @brief Encryption of a single block using (T)DES. + * @note The implementation of this function must guarantee that it can + * be called from any context. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_encrypt_DES(CRYDriver *cryp, + crykey_t key_id, + const uint8_t *in, + uint8_t *out) { + + (void)cryp; + (void)key_id; + (void)in; + (void)out; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Decryption of a single block using (T)DES. + * @note The implementation of this function must guarantee that it can + * be called from any context. + * + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] in buffer containing the input ciphertext + * @param[out] out buffer for the output plaintext + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_decrypt_DES(CRYDriver *cryp, + crykey_t key_id, + const uint8_t *in, + uint8_t *out) { + + (void)cryp; + (void)key_id; + (void)in; + (void)out; + + return CRY_ERR_INV_ALGO; +} +#endif + +#if (CRY_LLD_SUPPORTS_DES_ECB == TRUE) || defined(__DOXYGEN__) +/** + * @brief Encryption operation using (T)DES-ECB. + * @note The function operates on data buffers whose length is a multiple + * of an DES block, this means that padding must be done by the + * caller. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of the plaintext buffer, this number must + * be a multiple of 8 + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_encrypt_DES_ECB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out) { + + (void)cryp; + (void)key_id; + (void)size; + (void)in; + (void)out; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Decryption operation using (T)DES-ECB. + * @note The function operates on data buffers whose length is a multiple + * of an DES block, this means that padding must be done by the + * caller. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of the plaintext buffer, this number must + * be a multiple of 8 + * @param[in] in buffer containing the input ciphertext + * @param[out] out buffer for the output plaintext + * @return T he operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_decrypt_DES_ECB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out) { + + (void)cryp; + (void)key_id; + (void)size; + (void)in; + (void)out; + + return CRY_ERR_INV_ALGO; +} +#endif + +#if (CRY_LLD_SUPPORTS_DES_CBC == TRUE) || defined(__DOXYGEN__) +/** + * @brief Encryption operation using (T)DES-CBC. + * @note The function operates on data buffers whose length is a multiple + * of an DES block, this means that padding must be done by the + * caller. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of the plaintext buffer, this number must + * be a multiple of 8 + * @param[in] in buffer containing the input plaintext + * @param[out] out buffer for the output ciphertext + * @param[in] iv 64 bits input vector + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_encrypt_DES_CBC(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv) { + + (void)cryp; + (void)key_id; + (void)size; + (void)in; + (void)out; + (void)iv; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Decryption operation using (T)DES-CBC. + * @note The function operates on data buffers whose length is a multiple + * of an DES block, this means that padding must be done by the + * caller. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] key_id the key to be used for the operation, zero is + * the transient key, other values are keys stored + * in an unspecified way + * @param[in] size size of the plaintext buffer, this number must + * be a multiple of 8 + * @param[in] in buffer containing the input ciphertext + * @param[out] out buffer for the output plaintext + * @param[in] iv 64 bits input vector + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation. + * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid + * or refers to an empty key slot. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_decrypt_DES_CBC(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv) { + + (void)cryp; + (void)key_id; + (void)size; + (void)in; + (void)out; + (void)iv; + + return CRY_ERR_INV_ALGO; +} +#endif + +#if (CRY_LLD_SUPPORTS_SHA1 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Hash initialization using SHA1. + * @note Use of this algorithm is not recommended because proven weak. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[out] sha1ctxp pointer to a SHA1 context to be initialized + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_SHA1_init(CRYDriver *cryp, SHA1Context *sha1ctxp) { + + (void)cryp; + (void)sha1ctxp; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Hash update using SHA1. + * @note Use of this algorithm is not recommended because proven weak. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] sha1ctxp pointer to a SHA1 context + * @param[in] size size of input buffer + * @param[in] in buffer containing the input text + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_SHA1_update(CRYDriver *cryp, SHA1Context *sha1ctxp, + size_t size, const uint8_t *in) { + + (void)cryp; + (void)sha1ctxp; + (void)size; + (void)in; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Hash finalization using SHA1. + * @note Use of this algorithm is not recommended because proven weak. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] sha1ctxp pointer to a SHA1 context + * @param[out] out 160 bits output buffer + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_SHA1_final(CRYDriver *cryp, SHA1Context *sha1ctxp, + uint8_t *out) { + + (void)cryp; + (void)sha1ctxp; + (void)out; + + return CRY_ERR_INV_ALGO; +} +#endif + +#if (CRY_LLD_SUPPORTS_SHA256 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Hash initialization using SHA256. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[out] sha256ctxp pointer to a SHA256 context to be initialized + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_SHA256_init(CRYDriver *cryp, SHA256Context *sha256ctxp) { + + (void)cryp; + + /* Initializing context structure.*/ + sha256ctxp->last_data = 0U; + sha256ctxp->last_size = 0U; + + /* Initializing operation.*/ + HASH->CR = /*HASH_CR_MDMAT |*/ HASH_CR_ALGO_1 | HASH_CR_ALGO_0 | + HASH_CR_DATATYPE_1 | HASH_CR_INIT; + + return CRY_NOERROR; +} + +/** + * @brief Hash update using SHA256. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] sha256ctxp pointer to a SHA256 context + * @param[in] size size of input buffer + * @param[in] in buffer containing the input text + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_SHA256_update(CRYDriver *cryp, SHA256Context *sha256ctxp, + size_t size, const uint8_t *in) { + const uint32_t *wp = (const uint32_t *)(const void *)in; + + /* This HW is unable to hash blocks that are not a multiple of 4 bytes + except for the last block in the stream which is handled in the + "final" function.*/ + if (sha256ctxp->last_size != 0U) { + return CRY_ERR_OP_FAILURE; + } + + /* Any unaligned data is deferred to the "final" function.*/ + sha256ctxp->last_size = 8U * (size % sizeof (uint32_t)); + if (sha256ctxp->last_size > 0U) { + sha256ctxp->last_data = wp[size / sizeof (uint32_t)]; + } + + /* Pushing data.*/ + cry_lld_hash_push(cryp, (uint32_t)(size / sizeof (uint32_t)), wp); + + return CRY_NOERROR; +} + +/** + * @brief Hash finalization using SHA256. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] sha256ctxp pointer to a SHA256 context + * @param[out] out 256 bits output buffer + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_SHA256_final(CRYDriver *cryp, SHA256Context *sha256ctxp, + uint8_t *out) { + uint32_t digest[8]; + + (void)cryp; + + if (sha256ctxp->last_size > 0U) { + HASH->DIN = sha256ctxp->last_data; + } + + /* Triggering final calculation and wait for result.*/ + HASH->SR = 0U; + HASH->STR = sha256ctxp->last_size; + HASH->STR = sha256ctxp->last_size | HASH_STR_DCAL; + while ((HASH->SR & HASH_SR_DCIS) == 0U) { + } + + /* Reading digest.*/ + digest[0] = HASH_DIGEST->HR[0]; + digest[1] = HASH_DIGEST->HR[1]; + digest[2] = HASH_DIGEST->HR[2]; + digest[3] = HASH_DIGEST->HR[3]; + digest[4] = HASH_DIGEST->HR[4]; + digest[5] = HASH_DIGEST->HR[5]; + digest[6] = HASH_DIGEST->HR[6]; + digest[7] = HASH_DIGEST->HR[7]; + memcpy((void *)out, (const void *)digest, sizeof digest); + + return CRY_NOERROR; +} +#endif + +#if (CRY_LLD_SUPPORTS_SHA512 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Hash initialization using SHA512. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[out] sha512ctxp pointer to a SHA512 context to be initialized + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_SHA512_init(CRYDriver *cryp, SHA512Context *sha512ctxp) { + + (void)cryp; + (void)sha512ctxp; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Hash update using SHA512. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] sha512ctxp pointer to a SHA512 context + * @param[in] size size of input buffer + * @param[in] in buffer containing the input text + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_SHA512_update(CRYDriver *cryp, SHA512Context *sha512ctxp, + size_t size, const uint8_t *in) { + + (void)cryp; + (void)sha512ctxp; + (void)size; + (void)in; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Hash finalization using SHA512. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] sha512ctxp pointer to a SHA512 context + * @param[out] out 512 bits output buffer + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_SHA512_final(CRYDriver *cryp, SHA512Context *sha512ctxp, + uint8_t *out) { + + (void)cryp; + (void)sha512ctxp; + (void)out; + + return CRY_ERR_INV_ALGO; +} +#endif + +#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Initializes the HMAC transient key. + * @note It is the underlying implementation to decide which key sizes are + * allowable. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] size key size in bytes + * @param[in] keyp pointer to the key data + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the algorithm is unsupported. + * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid for + * the specified algorithm. + * + * @notapi + */ +cryerror_t cry_lld_hmac_loadkey(CRYDriver *cryp, + size_t size, + const uint8_t *keyp) { + + (void)cryp; + (void)size; + (void)keyp; + + return CRY_NOERROR; +} + +/** + * @brief Hash initialization using HMAC_SHA256. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[out] hmacsha256ctxp pointer to a HMAC_SHA256 context to be + * initialized + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_HMACSHA256_init(CRYDriver *cryp, + HMACSHA256Context *hmacsha256ctxp) { + + (void)cryp; + (void)hmacsha256ctxp; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Hash update using HMAC. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] hmacsha256ctxp pointer to a HMAC_SHA256 context + * @param[in] size size of input buffer + * @param[in] in buffer containing the input text + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_HMACSHA256_update(CRYDriver *cryp, + HMACSHA256Context *hmacsha256ctxp, + size_t size, + const uint8_t *in) { + + (void)cryp; + (void)hmacsha256ctxp; + (void)size; + (void)in; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Hash finalization using HMAC. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] hmacsha256ctxp pointer to a HMAC_SHA256 context + * @param[out] out 256 bits output buffer + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_HMACSHA256_final(CRYDriver *cryp, + HMACSHA256Context *hmacsha256ctxp, + uint8_t *out) { + + (void)cryp; + (void)hmacsha256ctxp; + (void)out; + + return CRY_ERR_INV_ALGO; +} +#endif + +#if (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Hash initialization using HMAC_SHA512. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[out] hmacsha512ctxp pointer to a HMAC_SHA512 context to be + * initialized + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_HMACSHA512_init(CRYDriver *cryp, + HMACSHA512Context *hmacsha512ctxp) { + + (void)cryp; + (void)hmacsha512ctxp; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Hash update using HMAC. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] hmacsha512ctxp pointer to a HMAC_SHA512 context + * @param[in] size size of input buffer + * @param[in] in buffer containing the input text + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_HMACSHA512_update(CRYDriver *cryp, + HMACSHA512Context *hmacsha512ctxp, + size_t size, + const uint8_t *in) { + + (void)cryp; + (void)hmacsha512ctxp; + (void)size; + (void)in; + + return CRY_ERR_INV_ALGO; +} + +/** + * @brief Hash finalization using HMAC. + * + * @param[in] cryp pointer to the @p CRYDriver object + * @param[in] hmacsha512ctxp pointer to a HMAC_SHA512 context + * @param[out] out 512 bits output buffer + * @return The operation status. + * @retval CRY_NOERROR if the operation succeeded. + * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this + * device instance. + * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation + * dependent. + * + * @notapi + */ +cryerror_t cry_lld_HMACSHA512_final(CRYDriver *cryp, + HMACSHA512Context *hmacsha512ctxp, + uint8_t *out) { + + (void)cryp; + (void)hmacsha512ctxp; + (void)out; + + return CRY_ERR_INV_ALGO; +} +#endif + +#endif /* HAL_USE_CRY == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h new file mode 100644 index 0000000..257d396 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h @@ -0,0 +1,618 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file CRYPv1/hal_cry_lld.h + * @brief STM32 cryptographic subsystem low level driver header. + * + * @addtogroup CRYPTO + * @{ + */ + +#ifndef HAL_CRYPTO_LLD_H +#define HAL_CRYPTO_LLD_H + +#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name STM32 configuration options + * @{ + */ +/** + * @brief CRYP1 driver enable switch. + * @details If set to @p TRUE the support for CRYP1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_CRY_USE_CRYP1) || defined(__DOXYGEN__) +#define STM32_CRY_USE_CRYP1 FALSE +#endif + +/** + * @brief HASH1 driver enable switch. + * @details If set to @p TRUE the support for HASH1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_CRY_USE_HASH1) || defined(__DOXYGEN__) +#define STM32_CRY_USE_HASH1 FALSE +#endif + +/** + * @brief CRYP1 interrupt priority level setting. + */ +#if !defined(STM32_CRY_CRYP1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CRY_CRYP1_IRQ_PRIORITY 9 +#endif + +/** + * @brief HASH1 interrupt priority level setting. + */ +#if !defined(STM32_CRY_HASH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CRY_HASH1_IRQ_PRIORITY 9 +#endif + +/** + * @brief HASH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_CRY_CRYP1_OUT_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CRY_CRYP1_OUT_DMA_PRIORITY 0 +#endif + +/** + * @brief HASH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_CRY_HASH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CRY_HASH1_DMA_PRIORITY 0 +#endif + +/** + * @brief Minimum message size (in words) for DMA use. + * @note If set to zero then DMA is never used. + * @note If set to one then DMA is always used. + */ +#if !defined(STM32_CRY_HASH_SIZE_THRESHOLD) || defined(__DOXYGEN__) +#define STM32_CRY_HASH_SIZE_THRESHOLD 1024 +#endif + +/** + * @brief Minimum text size (in bytes) for DMA use. + * @note If set to zero then DMA is never used. + * @note If set to one then DMA is always used. + */ +#if !defined(STM32_CRY_CRYP_SIZE_THRESHOLD) || defined(__DOXYGEN__) +#define STM32_CRY_CRYP_SIZE_THRESHOLD 1024 +#endif + +/** + * @brief Hash DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(STM32_CRY_HASH_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_CRY_HASH_DMA_ERROR_HOOK(cryp) osalSysHalt("DMA failure") +#endif + +/** + * @brief CRYP DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(STM32_CRY_CRYP_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_CRY_CRYP_DMA_ERROR_HOOK(cryp) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (STM32_CRY_USE_CRYP1 == TRUE) || (STM32_CRY_USE_HASH1 == TRUE) || \ + defined (__DOXYGEN__) +#define STM32_CRY_ENABLED1 TRUE +#else +#define STM32_CRY_ENABLED1 FALSE +#endif + +#if !defined (STM32_HAS_CRYP1) +#define STM32_HAS_CRYP1 FALSE +#endif + +#if !defined (STM32_HAS_HASH1) +#define STM32_HAS_HASH1 FALSE +#endif + +#if STM32_CRY_USE_CRYP1 && !STM32_HAS_CRYP1 +#error "CRYP1 not present in the selected device" +#endif + +#if STM32_CRY_USE_HASH1 && !STM32_HAS_HASH1 +#error "HASH1 not present in the selected device" +#endif + +#if !STM32_CRY_ENABLED1 +#error "CRY driver activated but no CRYP nor HASH peripheral assigned" +#endif + +#if STM32_CRY_USE_HASH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_CRY_HASH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to HASH1" +#endif + +#if STM32_CRY_USE_CRYP1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_CRY_CRYP1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to CRYP1" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if !defined(STM32_CRY_HASH1_DMA_STREAM) +#error "HASH1 DMA streams not defined" +#endif + +/* Sanity checks on DMA streams settings in mcuconf.h.*/ +#if STM32_CRY_USE_HASH1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_CRY_HASH1_DMA_STREAM) +#error "Invalid DMA stream assigned to HASH1" +#endif + +/* Devices without DMAMUX require an additional check.*/ +#if !STM32_DMA_SUPPORTS_DMAMUX +#if STM32_CRY_USE_CRYP1 && \ + !STM32_DMA_IS_VALID_ID(STM32_CRY_CRYP1_IN_DMA_STREAM, \ + STM32_CRYP1_IN_DMA_MSK) +#error "invalid DMA stream associated to CRYP1_IN" +#endif + +#if STM32_CRY_USE_CRYP1 && \ + !STM32_DMA_IS_VALID_ID(STM32_CRY_CRYP1_OUT_DMA_STREAM, \ + STM32_CRYP1_OUT_DMA_MSK) +#error "invalid DMA stream associated to CRYP1_OUT" +#endif + +#if STM32_CRY_USE_HASH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_CRY_HASH1_DMA_STREAM, STM32_HASH1_DMA_MSK) +#error "invalid DMA stream associated to HASH1" +#endif +#endif /* !STM32_DMA_SUPPORTS_DMAMUX */ + +/* DMA priority check.*/ +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_CRY_CRYP1_IN_DMA_PRIORITY) +#error "Invalid DMA priority assigned to CRYP1_IN" +#endif + +/* DMA priority check.*/ +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_CRY_CRYP1_OUT_DMA_PRIORITY) +#error "Invalid DMA priority assigned to CRYP1_OUT" +#endif + +/* DMA priority check.*/ +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_CRY_HASH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to HASH1" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +#if STM32_CRY_HASH_SIZE_THRESHOLD < 0 +#error "invalid STM32_CRY_HASH_SIZE_THRESHOLD value" +#endif + +/** + * @name Driver capability switches + * @{ + */ +#if STM32_CRY_USE_CRYP1 || defined (__DOXYGEN__) +#define CRY_LLD_SUPPORTS_AES TRUE +#define CRY_LLD_SUPPORTS_AES_ECB TRUE +#define CRY_LLD_SUPPORTS_AES_CBC TRUE +#define CRY_LLD_SUPPORTS_AES_CFB FALSE +#define CRY_LLD_SUPPORTS_AES_CTR TRUE +#define CRY_LLD_SUPPORTS_AES_GCM TRUE +#define CRY_LLD_SUPPORTS_DES TRUE +#define CRY_LLD_SUPPORTS_DES_ECB TRUE +#define CRY_LLD_SUPPORTS_DES_CBC TRUE +#else +#define CRY_LLD_SUPPORTS_AES FALSE +#define CRY_LLD_SUPPORTS_AES_ECB FALSE +#define CRY_LLD_SUPPORTS_AES_CBC FALSE +#define CRY_LLD_SUPPORTS_AES_CFB FALSE +#define CRY_LLD_SUPPORTS_AES_CTR FALSE +#define CRY_LLD_SUPPORTS_AES_GCM FALSE +#define CRY_LLD_SUPPORTS_DES FALSE +#define CRY_LLD_SUPPORTS_DES_ECB FALSE +#define CRY_LLD_SUPPORTS_DES_CBC FALSE +#endif +#if STM32_CRY_USE_HASH1 || defined (__DOXYGEN__) +#define CRY_LLD_SUPPORTS_SHA1 FALSE +#define CRY_LLD_SUPPORTS_SHA256 TRUE +#define CRY_LLD_SUPPORTS_SHA512 FALSE +#define CRY_LLD_SUPPORTS_HMAC_SHA256 TRUE +#define CRY_LLD_SUPPORTS_HMAC_SHA512 FALSE +#else +#define CRY_LLD_SUPPORTS_SHA1 FALSE +#define CRY_LLD_SUPPORTS_SHA256 FALSE +#define CRY_LLD_SUPPORTS_SHA512 FALSE +#define CRY_LLD_SUPPORTS_HMAC_SHA256 FALSE +#define CRY_LLD_SUPPORTS_HMAC_SHA512 FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief CRY key identifier type. + */ +typedef uint32_t crykey_t; + +/** + * @brief Type of a structure representing an CRY driver. + */ +typedef struct CRYDriver CRYDriver; + +/** + * @brief Type of key stored in CRYP. + */ +typedef enum { + cryp_key_none = 0, + cryp_key_des = 1, + cryp_key_tdes = 2, + cryp_key_aes_encrypt = 3, + cryp_key_aes_decrypt = 4 +} cryp_ktype_t; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + uint32_t dummy; +} CRYConfig; + +/** + * @brief Structure representing an CRY driver. + */ +struct CRYDriver { + /** + * @brief Driver state. + */ + crystate_t state; + /** + * @brief Current configuration data. + */ + const CRYConfig *config; +#if defined(CRY_DRIVER_EXT_FIELDS) + CRY_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ +#if (STM32_CRY_USE_CRYP1 == TRUE) || defined (__DOXYGEN__) + /** + * @brief Type of the key currently stored in CRYP. + */ + cryp_ktype_t cryp_ktype; + /** + * @brief Key size setup value for CR register. + */ + uint32_t cryp_ksize; + /** + * @brief Transient key data. + */ + uint32_t cryp_k[8]; +#if (STM32_CRY_CRYP_SIZE_THRESHOLD != 0) || defined (__DOXYGEN__) + /** + * @brief Thread reference for CRYP operations. + */ + thread_reference_t cryp_tr; + /** + * @brief CRYP IN DMA stream. + */ + const stm32_dma_stream_t *cryp_dma_in; + /** + * @brief CRYP OUT DMA stream. + */ + const stm32_dma_stream_t *cryp_dma_out; +#endif /* STM32_CRY_CRYP_SIZE_THRESHOLD != 0 */ +#endif /* STM32_CRY_USE_CRYP1 == TRUE */ +#if (STM32_CRY_USE_HASH1 == TRUE) || defined (__DOXYGEN__) +#if (STM32_CRY_HASH_SIZE_THRESHOLD != 0) || defined (__DOXYGEN__) + /** + * @brief Thread reference for hash operations. + */ + thread_reference_t hash_tr; + /** + * @brief Hash DMA stream. + */ + const stm32_dma_stream_t *hash_dma; +#endif /* STM32_CRY_HASH_SIZE_THRESHOLD != 0 */ +#endif /* STM32_CRY_USE_HASH1 == TRUE */ +}; + +#if (CRY_LLD_SUPPORTS_SHA1 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Type of a SHA1 context. + */ +typedef struct { + uint32_t dummy; +} SHA1Context; +#endif + +#if (CRY_LLD_SUPPORTS_SHA256 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Type of a SHA256 context. + */ +typedef struct { + /** + * @brief Last data to be hashed on finalization. + */ + uint32_t last_data; + /** + * @brief Size, in bits, of the last data. + */ + uint32_t last_size; +} SHA256Context; +#endif + +#if (CRY_LLD_SUPPORTS_SHA512 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Type of a SHA512 context. + */ +typedef struct { + uint32_t dummy; +} SHA512Context; +#endif + +#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Type of a HMAC_SHA256 context. + */ +typedef struct { + uint32_t dummy; +} HMACSHA256Context; +#endif + +#if (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Type of a HMAC_SHA512 context. + */ +typedef struct { + uint32_t dummy; +} HMACSHA512Context; +#endif + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (STM32_CRY_ENABLED1 == TRUE) && !defined(__DOXYGEN__) +extern CRYDriver CRYD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void cry_lld_init(void); + void cry_lld_start(CRYDriver *cryp); + void cry_lld_stop(CRYDriver *cryp); +#if (CRY_LLD_SUPPORTS_AES == TRUE) || \ + (CRY_LLD_SUPPORTS_AES_ECB == TRUE) || \ + (CRY_LLD_SUPPORTS_AES_CBC == TRUE) || \ + (CRY_LLD_SUPPORTS_AES_CFB == TRUE) || \ + (CRY_LLD_SUPPORTS_AES_CTR == TRUE) || \ + (CRY_LLD_SUPPORTS_AES_GCM == TRUE) || \ + defined(__DOXYGEN__) + cryerror_t cry_lld_aes_loadkey(CRYDriver *cryp, + size_t size, + const uint8_t *keyp); +#endif +#if (CRY_LLD_SUPPORTS_AES == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_encrypt_AES(CRYDriver *cryp, + crykey_t key_id, + const uint8_t *in, + uint8_t *out); + cryerror_t cry_lld_decrypt_AES(CRYDriver *cryp, + crykey_t key_id, + const uint8_t *in, + uint8_t *out); +#endif +#if (CRY_LLD_SUPPORTS_AES_ECB == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_encrypt_AES_ECB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out); + cryerror_t cry_lld_decrypt_AES_ECB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out); +#endif +#if (CRY_LLD_SUPPORTS_AES_CBC == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_encrypt_AES_CBC(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv); + cryerror_t cry_lld_decrypt_AES_CBC(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv); +#endif +#if (CRY_LLD_SUPPORTS_AES_CFB == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_encrypt_AES_CFB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv); + cryerror_t cry_lld_decrypt_AES_CFB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv); +#endif +#if (CRY_LLD_SUPPORTS_AES_CTR == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_encrypt_AES_CTR(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv); + cryerror_t cry_lld_decrypt_AES_CTR(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv); +#endif +#if (CRY_LLD_SUPPORTS_AES_GCM == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_encrypt_AES_GCM(CRYDriver *cryp, + crykey_t key_id, + size_t auth_size, + const uint8_t *auth_in, + size_t text_size, + const uint8_t *text_in, + uint8_t *text_out, + const uint8_t *iv, + size_t tag_size, + uint8_t *tag_out); + cryerror_t cry_lld_decrypt_AES_GCM(CRYDriver *cryp, + crykey_t key_id, + size_t auth_size, + const uint8_t *auth_in, + size_t text_size, + const uint8_t *text_in, + uint8_t *text_out, + const uint8_t *iv, + size_t tag_size, + const uint8_t *tag_in); +#endif +#if (CRY_LLD_SUPPORTS_DES == TRUE) || \ + (CRY_LLD_SUPPORTS_DES_ECB == TRUE) || \ + (CRY_LLD_SUPPORTS_DES_CBC == TRUE) || \ + defined(__DOXYGEN__) + cryerror_t cry_lld_des_loadkey(CRYDriver *cryp, + size_t size, + const uint8_t *keyp); +#endif +#if (CRY_LLD_SUPPORTS_DES == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_encrypt_DES(CRYDriver *cryp, + crykey_t key_id, + const uint8_t *in, + uint8_t *out); + cryerror_t cry_lld_decrypt_DES(CRYDriver *cryp, + crykey_t key_id, + const uint8_t *in, + uint8_t *out); +#endif +#if (CRY_LLD_SUPPORTS_DES_ECB == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_encrypt_DES_ECB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out); + cryerror_t cry_lld_decrypt_DES_ECB(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out); +#endif +#if (CRY_LLD_SUPPORTS_DES_CBC == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_encrypt_DES_CBC(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv); + cryerror_t cry_lld_decrypt_DES_CBC(CRYDriver *cryp, + crykey_t key_id, + size_t size, + const uint8_t *in, + uint8_t *out, + const uint8_t *iv); +#endif +#if (CRY_LLD_SUPPORTS_SHA1 == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_SHA1_init(CRYDriver *cryp, SHA1Context *sha1ctxp); + cryerror_t cry_lld_SHA1_update(CRYDriver *cryp, SHA1Context *sha1ctxp, + size_t size, const uint8_t *in); + cryerror_t cry_lld_SHA1_final(CRYDriver *cryp, SHA1Context *sha1ctxp, + uint8_t *out); +#endif +#if (CRY_LLD_SUPPORTS_SHA256 == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_SHA256_init(CRYDriver *cryp, SHA256Context *sha256ctxp); + cryerror_t cry_lld_SHA256_update(CRYDriver *cryp, SHA256Context *sha256ctxp, + size_t size, const uint8_t *in); + cryerror_t cry_lld_SHA256_final(CRYDriver *cryp, SHA256Context *sha256ctxp, + uint8_t *out); +#endif +#if (CRY_LLD_SUPPORTS_SHA512 == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_SHA512_init(CRYDriver *cryp, SHA512Context *sha512ctxp); + cryerror_t cry_lld_SHA512_update(CRYDriver *cryp, SHA512Context *sha512ctxp, + size_t size, const uint8_t *in); + cryerror_t cry_lld_SHA512_final(CRYDriver *cryp, SHA512Context *sha512ctxp, + uint8_t *out); +#endif +#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || \ + (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) || \ + defined(__DOXYGEN__) + cryerror_t cry_lld_hmac_loadkey(CRYDriver *cryp, + size_t size, + const uint8_t *keyp); +#endif +#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_HMACSHA256_init(CRYDriver *cryp, + HMACSHA256Context *hmacsha256ctxp); + cryerror_t cry_lld_HMACSHA256_update(CRYDriver *cryp, + HMACSHA256Context *hmacsha256ctxp, + size_t size, const uint8_t *in); + cryerror_t cry_lld_HMACSHA256_final(CRYDriver *cryp, + HMACSHA256Context *hmacsha256ctxp, + uint8_t *out); +#endif +#if (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) || defined(__DOXYGEN__) + cryerror_t cry_lld_HMACSHA512_init(CRYDriver *cryp, + HMACSHA512Context *hmacsha512ctxp); + cryerror_t cry_lld_HMACSHA512_update(CRYDriver *cryp, + HMACSHA512Context *hmacsha512ctxp, + size_t size, const uint8_t *in); + cryerror_t cry_lld_HMACSHA512_final(CRYDriver *cryp, + HMACSHA512Context *hmacsha512ctxp, + uint8_t *out); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_CRY == TRUE */ + +#endif /* HAL_CRYPTO_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/driver.mk new file mode 100644 index 0000000..da95148 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c new file mode 100644 index 0000000..1b32a82 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c @@ -0,0 +1,769 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DACv1/hal_dac_lld.c + * @brief STM32 DAC subsystem low level driver source. + * + * @addtogroup DAC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_DAC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* Because ST headers naming inconsistencies.*/ +#if !defined(DAC1) +#define DAC1 DAC +#endif + +#define DAC1_CH1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC_DAC1_CH1_DMA_STREAM, \ + STM32_DAC1_CH1_DMA_CHN) + +#define DAC1_CH2_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC_DAC1_CH2_DMA_STREAM, \ + STM32_DAC1_CH2_DMA_CHN) + +#define DAC2_CH1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC_DAC2_CH1_DMA_STREAM, \ + STM32_DAC2_CH1_DMA_CHN) + +#define DAC2_CH2_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC_DAC2_CH2_DMA_STREAM, \ + STM32_DAC2_CH2_DMA_CHN) + +#define DAC3_CH1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC_DAC3_CH1_DMA_STREAM, \ + STM32_DAC3_CH1_DMA_CHN) + +#define DAC3_CH2_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC_DAC3_CH2_DMA_STREAM, \ + STM32_DAC3_CH2_DMA_CHN) + +#define DAC4_CH1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC_DAC4_CH1_DMA_STREAM, \ + STM32_DAC4_CH1_DMA_CHN) + +#define DAC4_CH2_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC_DAC4_CH2_DMA_STREAM, \ + STM32_DAC4_CH2_DMA_CHN) + +#define CHANNEL_DATA_OFFSET 3U + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief DAC1 CH1 driver identifier.*/ +#if STM32_DAC_USE_DAC1_CH1 || defined(__DOXYGEN__) +DACDriver DACD1; +#endif + +/** @brief DAC1 CH2 driver identifier.*/ +#if (STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +DACDriver DACD2; +#endif + +/** @brief DAC2 CH1 driver identifier.*/ +#if STM32_DAC_USE_DAC2_CH1 || defined(__DOXYGEN__) +DACDriver DACD3; +#endif + +/** @brief DAC2 CH2 driver identifier.*/ +#if (STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +DACDriver DACD4; +#endif + +/** @brief DAC3 CH1 driver identifier.*/ +#if STM32_DAC_USE_DAC3_CH1 || defined(__DOXYGEN__) +DACDriver DACD5; +#endif + +/** @brief DAC3 CH2 driver identifier.*/ +#if (STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +DACDriver DACD6; +#endif + +/** @brief DAC4 CH1 driver identifier.*/ +#if STM32_DAC_USE_DAC4_CH1 || defined(__DOXYGEN__) +DACDriver DACD7; +#endif + +/** @brief DAC4 CH2 driver identifier.*/ +#if (STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +DACDriver DACD8; +#endif + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +#if STM32_DAC_USE_DAC1_CH1 == TRUE +static const dacparams_t dac1_ch1_params = { + .dac = DAC1, + .dataoffset = 0U, + .regshift = 0U, + .regmask = 0xFFFF0000U, + .dmastream = STM32_DAC_DAC1_CH1_DMA_STREAM, +#if STM32_DMA_SUPPORTS_DMAMUX + .peripheral = STM32_DMAMUX1_DAC1_CH1, +#endif + .dmamode = STM32_DMA_CR_CHSEL(DAC1_CH1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC_DAC1_CH1_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE, + .dmairqprio = STM32_DAC_DAC1_CH1_IRQ_PRIORITY +}; +#endif + +#if STM32_DAC_USE_DAC1_CH2 == TRUE +static const dacparams_t dac1_ch2_params = { + .dac = DAC1, + .dataoffset = CHANNEL_DATA_OFFSET, + .regshift = 16U, + .regmask = 0x0000FFFFU, + .dmastream = STM32_DAC_DAC1_CH2_DMA_STREAM, +#if STM32_DMA_SUPPORTS_DMAMUX + .peripheral = STM32_DMAMUX1_DAC1_CH2, +#endif + .dmamode = STM32_DMA_CR_CHSEL(DAC1_CH2_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC_DAC1_CH2_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE, + .dmairqprio = STM32_DAC_DAC1_CH2_IRQ_PRIORITY +}; +#endif + +#if STM32_DAC_USE_DAC2_CH1 == TRUE +static const dacparams_t dac2_ch1_params = { + .dac = DAC2, + .dataoffset = 0U, + .regshift = 0U, + .regmask = 0xFFFF0000U, + .dmastream = STM32_DAC_DAC2_CH1_DMA_STREAM, +#if STM32_DMA_SUPPORTS_DMAMUX + .peripheral = STM32_DMAMUX1_DAC2_CH1, +#endif + .dmamode = STM32_DMA_CR_CHSEL(DAC2_CH1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC_DAC2_CH1_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE, + .dmairqprio = STM32_DAC_DAC2_CH1_IRQ_PRIORITY +}; +#endif + +#if STM32_DAC_USE_DAC2_CH2 == TRUE +static const dacparams_t dac2_ch2_params = { + .dac = DAC2, + .dataoffset = CHANNEL_DATA_OFFSET, + .regshift = 16U, + .regmask = 0x0000FFFFU, + .dmastream = STM32_DAC_DAC2_CH2_DMA_STREAM, +#if STM32_DMA_SUPPORTS_DMAMUX + .peripheral = STM32_DMAMUX1_DAC2_CH2, +#endif + .dmamode = STM32_DMA_CR_CHSEL(DAC2_CH2_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC_DAC2_CH2_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE, + .dmairqprio = STM32_DAC_DAC2_CH2_IRQ_PRIORITY +}; +#endif + +#if STM32_DAC_USE_DAC3_CH1 == TRUE +static const dacparams_t dac3_ch1_params = { + .dac = DAC3, + .dataoffset = 0U, + .regshift = 0U, + .regmask = 0xFFFF0000U, + .dmastream = STM32_DAC_DAC3_CH1_DMA_STREAM, +#if STM32_DMA_SUPPORTS_DMAMUX + .peripheral = STM32_DMAMUX1_DAC3_CH1, +#endif + .dmamode = STM32_DMA_CR_CHSEL(DAC3_CH1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC_DAC3_CH1_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE, + .dmairqprio = STM32_DAC_DAC3_CH1_IRQ_PRIORITY +}; +#endif + +#if STM32_DAC_USE_DAC3_CH2 == TRUE +static const dacparams_t dac3_ch2_params = { + .dac = DAC3, + .dataoffset = CHANNEL_DATA_OFFSET, + .regshift = 16U, + .regmask = 0x0000FFFFU, + .dmastream = STM32_DAC_DAC3_CH2_DMA_STREAM, +#if STM32_DMA_SUPPORTS_DMAMUX + .peripheral = STM32_DMAMUX1_DAC3_CH2, +#endif + .dmamode = STM32_DMA_CR_CHSEL(DAC3_CH2_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC_DAC3_CH2_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE, + .dmairqprio = STM32_DAC_DAC3_CH2_IRQ_PRIORITY +}; +#endif + +#if STM32_DAC_USE_DAC4_CH1 == TRUE +static const dacparams_t dac4_ch1_params = { + .dac = DAC4, + .dataoffset = 0U, + .regshift = 0U, + .regmask = 0xFFFF0000U, + .dmastream = STM32_DAC_DAC4_CH1_DMA_STREAM, +#if STM32_DMA_SUPPORTS_DMAMUX + .peripheral = STM32_DMAMUX1_DAC4_CH1, +#endif + .dmamode = STM32_DMA_CR_CHSEL(DAC4_CH1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC_DAC4_CH1_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE, + .dmairqprio = STM32_DAC_DAC4_CH1_IRQ_PRIORITY +}; +#endif + +#if STM32_DAC_USE_DAC4_CH2 == TRUE +static const dacparams_t dac4_ch2_params = { + .dac = DAC4, + .dataoffset = CHANNEL_DATA_OFFSET, + .regshift = 16U, + .regmask = 0x0000FFFFU, + .dmastream = STM32_DAC_DAC4_CH2_DMA_STREAM, +#if STM32_DMA_SUPPORTS_DMAMUX + .peripheral = STM32_DMAMUX1_DAC4_CH2, +#endif + .dmamode = STM32_DMA_CR_CHSEL(DAC4_CH2_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC_DAC4_CH2_DMA_PRIORITY) | + STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE, + .dmairqprio = STM32_DAC_DAC4_CH2_IRQ_PRIORITY +}; +#endif + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Shared end/half-of-tx service routine. + * + * @param[in] dacp pointer to the @p DACDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void dac_lld_serve_tx_interrupt(DACDriver *dacp, uint32_t flags) { + + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + /* DMA errors handling.*/ + //dac_lld_stop_conversion(dacp); + _dac_isr_error_code(dacp, DAC_ERR_DMAFAILURE); + } + else { + if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _dac_isr_half_code(dacp); + } + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _dac_isr_full_code(dacp); + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level DAC driver initialization. + * + * @notapi + */ +void dac_lld_init(void) { + +#if STM32_DAC_USE_DAC1_CH1 + dacObjectInit(&DACD1); + DACD1.params = &dac1_ch1_params; + DACD1.dma = NULL; +#endif + +#if STM32_DAC_USE_DAC1_CH2 + dacObjectInit(&DACD2); + DACD2.params = &dac1_ch2_params; + DACD2.dma = NULL; +#endif + +#if STM32_DAC_USE_DAC2_CH1 + dacObjectInit(&DACD3); + DACD3.params = &dac2_ch1_params; + DACD3.dma = NULL; +#endif + +#if STM32_DAC_USE_DAC2_CH2 + dacObjectInit(&DACD4); + DACD4.params = &dac2_ch2_params; + DACD4.dma = NULL; +#endif + +#if STM32_DAC_USE_DAC3_CH1 + dacObjectInit(&DACD5); + DACD5.params = &dac3_ch1_params; + DACD5.dma = NULL; +#endif + +#if STM32_DAC_USE_DAC3_CH2 + dacObjectInit(&DACD6); + DACD6.params = &dac3_ch2_params; + DACD6.dma = NULL; +#endif + +#if STM32_DAC_USE_DAC4_CH1 + dacObjectInit(&DACD7); + DACD7.params = &dac4_ch1_params; + DACD7.dma = NULL; +#endif + +#if STM32_DAC_USE_DAC4_CH2 + dacObjectInit(&DACD8); + DACD8.params = &dac4_ch2_params; + DACD8.dma = NULL; +#endif +} + +/** + * @brief Configures and activates the DAC peripheral. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @notapi + */ +void dac_lld_start(DACDriver *dacp) { + + /* If the driver is in DAC_STOP state then a full initialization is + required.*/ + if (dacp->state == DAC_STOP) { + dacchannel_t channel = 0; + + /* Enabling the clock source.*/ +#if STM32_DAC_USE_DAC1_CH1 + if (&DACD1 == dacp) { + rccEnableDAC1(true); + } +#endif + +#if STM32_DAC_USE_DAC1_CH2 + if (&DACD2 == dacp) { + rccEnableDAC1(true); + channel = 1; + } +#endif + +#if STM32_DAC_USE_DAC2_CH1 + if (&DACD3 == dacp) { + rccEnableDAC2(true); + } +#endif + +#if STM32_DAC_USE_DAC2_CH2 + if (&DACD4 == dacp) { + rccEnableDAC2(true); + channel = 1; + } +#endif + +#if STM32_DAC_USE_DAC3_CH1 + if (&DACD5 == dacp) { + rccEnableDAC3(true); + } +#endif + +#if STM32_DAC_USE_DAC3_CH2 + if (&DACD6 == dacp) { + rccEnableDAC3(true); + channel = 1; + } +#endif + +#if STM32_DAC_USE_DAC4_CH1 + if (&DACD7 == dacp) { + rccEnableDAC4(true); + } +#endif + +#if STM32_DAC_USE_DAC4_CH2 + if (&DACD8 == dacp) { + rccEnableDAC4(true); + channel = 1; + } +#endif + + /* Enabling DAC in SW triggering mode initially, initializing data to + zero.*/ +#if STM32_DAC_DUAL_MODE == FALSE + { + uint32_t cr; + + cr = dacp->params->dac->CR; + cr &= dacp->params->regmask; + cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift; + dacp->params->dac->CR = cr; + dac_lld_put_channel(dacp, channel, dacp->config->init); + } +#else + if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) || + (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) || + (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) { + dacp->params->dac->CR = DAC_CR_EN2 | (dacp->config->cr << 16) | DAC_CR_EN1 | dacp->config->cr; + dac_lld_put_channel(dacp, 1U, dacp->config->init); + } + else { + dacp->params->dac->CR = DAC_CR_EN1 | dacp->config->cr; + } + dac_lld_put_channel(dacp, channel, dacp->config->init); +#endif + } +} + +/** + * @brief Deactivates the DAC peripheral. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @notapi + */ +void dac_lld_stop(DACDriver *dacp) { + + /* If in ready state then disables the DAC clock.*/ + if (dacp->state == DAC_READY) { + + /* Disabling DAC.*/ + dacp->params->dac->CR &= dacp->params->regmask; + +#if STM32_DAC_USE_DAC1_CH1 + if (&DACD1 == dacp) { + if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) { + rccDisableDAC1(); + } + } +#endif + +#if STM32_DAC_USE_DAC1_CH2 + if (&DACD2 == dacp) { + if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) { + rccDisableDAC1(); + } + } +#endif + +#if STM32_DAC_USE_DAC2_CH1 + if (&DACD3 == dacp) { + if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) { + rccDisableDAC2(); + } + } +#endif + +#if STM32_DAC_USE_DAC2_CH2 + if (&DACD4 == dacp) { + if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) { + rccDisableDAC2(); + } + } +#endif + +#if STM32_DAC_USE_DAC3_CH1 + if (&DACD5 == dacp) { + if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) { + rccDisableDAC3(); + } + } +#endif + +#if STM32_DAC_USE_DAC3_CH2 + if (&DACD6 == dacp) { + if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) { + rccDisableDAC3(); + } + } +#endif + +#if STM32_DAC_USE_DAC4_CH1 + if (&DACD7 == dacp) { + if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) { + rccDisableDAC4(); + } + } +#endif + +#if STM32_DAC_USE_DAC4_CH2 + if (&DACD8 == dacp) { + if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) { + rccDisableDAC4(); + } + } +#endif + } +} + +/** + * @brief Outputs a value directly on a DAC channel. + * + * @param[in] dacp pointer to the @p DACDriver object + * @param[in] channel DAC channel number + * @param[in] sample value to be output + * + * @api + */ +void dac_lld_put_channel(DACDriver *dacp, + dacchannel_t channel, + dacsample_t sample) { + + switch (dacp->config->datamode) { + case DAC_DHRM_12BIT_RIGHT: +#if STM32_DAC_DUAL_MODE + case DAC_DHRM_12BIT_RIGHT_DUAL: +#endif + if (channel == 0U) { +#if STM32_DAC_DUAL_MODE + dacp->params->dac->DHR12R1 = (uint32_t)sample; +#else + *(&dacp->params->dac->DHR12R1 + dacp->params->dataoffset) = (uint32_t)sample; +#endif + } +#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \ + STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2) + else { + dacp->params->dac->DHR12R2 = (uint32_t)sample; + } +#endif + break; + case DAC_DHRM_12BIT_LEFT: +#if STM32_DAC_DUAL_MODE + case DAC_DHRM_12BIT_LEFT_DUAL: +#endif + if (channel == 0U) { +#if STM32_DAC_DUAL_MODE + dacp->params->dac->DHR12L1 = (uint32_t)sample; +#else + *(&dacp->params->dac->DHR12L1 + dacp->params->dataoffset) = (uint32_t)sample; +#endif + } +#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \ + STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2) + else { + dacp->params->dac->DHR12L2 = (uint32_t)sample; + } +#endif + break; + case DAC_DHRM_8BIT_RIGHT: +#if STM32_DAC_DUAL_MODE + case DAC_DHRM_8BIT_RIGHT_DUAL: +#endif + if (channel == 0U) { +#if STM32_DAC_DUAL_MODE + dacp->params->dac->DHR8R1 = (uint32_t)sample; +#else + *(&dacp->params->dac->DHR8R1 + dacp->params->dataoffset) = (uint32_t)sample; +#endif + } +#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \ + STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2) + else { + dacp->params->dac->DHR8R2 = (uint32_t)sample; + } +#endif + break; + default: + osalDbgAssert(false, "unexpected DAC mode"); + break; + } +} + +/** + * @brief Starts a DAC conversion. + * @details Starts an asynchronous conversion operation. + * @note In @p DAC_DHRM_8BIT_RIGHT mode the parameters passed to the + * callback are wrong because two samples are packed in a single + * dacsample_t element. This will not be corrected, do not rely + * on those parameters. + * @note In @p DAC_DHRM_8BIT_RIGHT_DUAL mode two samples are treated + * as a single 16 bits sample and packed into a single dacsample_t + * element. The num_channels must be set to one in the group + * conversion configuration structure. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @notapi + */ +void dac_lld_start_conversion(DACDriver *dacp) { + uint32_t n, cr, dmamode; + + /* Number of DMA operations per buffer.*/ + n = dacp->depth * dacp->grpp->num_channels; + + /* Allocating the DMA channel.*/ + dacp->dma = dmaStreamAllocI(dacp->params->dmastream, + dacp->params->dmairqprio, + (stm32_dmaisr_t)dac_lld_serve_tx_interrupt, + (void *)dacp); + osalDbgAssert(dacp->dma != NULL, "unable to allocate stream"); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(dacp->dma, dacp->params->peripheral); +#endif + + /* DMA settings depend on the chosen DAC mode.*/ + switch (dacp->config->datamode) { + /* Sets the DAC data register */ + case DAC_DHRM_12BIT_RIGHT: + osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); + + dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12R1 + + dacp->params->dataoffset); + dmamode = dacp->params->dmamode | + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + break; +// case DAC_DHRM_12BIT_LEFT: +// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12L1 + +// dacp->params->dataoffset); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; +// break; +// case DAC_DHRM_8BIT_RIGHT: +// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8R1 + +// dacp->params->dataoffset); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; +// +// /* In this mode the size of the buffer is halved because two samples +// packed in a single dacsample_t element.*/ +// n = (n + 1) / 2; +// break; +//#if STM32_DAC_DUAL_MODE == TRUE +// case DAC_DHRM_12BIT_RIGHT_DUAL: +// osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12RD); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD; +// n /= 2; +// break; +// case DAC_DHRM_12BIT_LEFT_DUAL: +// osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12LD); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD; +// n /= 2; +// break; +// case DAC_DHRM_8BIT_RIGHT_DUAL: +// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8RD); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; +// n /= 2; +// break; +//#endif + default: + osalDbgAssert(false, "unexpected DAC mode"); + return; + } + + dmaStreamSetMemory0(dacp->dma, dacp->samples); + dmaStreamSetTransactionSize(dacp->dma, n); + dmaStreamSetMode(dacp->dma, dmamode | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_HTIE | STM32_DMA_CR_TCIE); + dmaStreamEnable(dacp->dma); + + /* DAC configuration.*/ + cr = dacp->params->dac->CR; + +#if STM32_DAC_DUAL_MODE == FALSE + cr &= dacp->params->regmask; + cr |= (DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift; +#else + cr = DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr + | (dacp->grpp->trigger << DAC_CR_TSEL2_Pos) | DAC_CR_TEN2 | DAC_CR_EN2 | (dacp->config->cr << 16); +#endif + + dacp->params->dac->CR = cr; +} + +/** + * @brief Stops an ongoing conversion. + * @details This function stops the currently ongoing conversion and returns + * the driver in the @p DAC_READY state. If there was no conversion + * being processed then the function does nothing. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @iclass + */ +void dac_lld_stop_conversion(DACDriver *dacp) { + uint32_t cr; + + /* DMA channel disabled and released.*/ + dmaStreamDisable(dacp->dma); + dmaStreamFreeI(dacp->dma); + dacp->dma = NULL; + + cr = dacp->params->dac->CR; + +#if STM32_DAC_DUAL_MODE == FALSE + cr &= dacp->params->regmask; + cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift; +#else + if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) || + (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) || + (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) { + cr = DAC_CR_EN2 | (dacp->config->cr << 16) | + DAC_CR_EN1 | dacp->config->cr; + } + else { + cr = DAC_CR_EN1 | dacp->config->cr; + } +#endif + + dacp->params->dac->CR = cr; +} + +#endif /* HAL_USE_DAC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c.bak b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c.bak new file mode 100644 index 0000000..02aefc8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c.bak @@ -0,0 +1,735 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DACv1/hal_dac_lld.c + * @brief STM32 DAC subsystem low level driver source. + * + * @addtogroup DAC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_DAC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* Because ST headers naming inconsistencies.*/ +#if !defined(DAC1) +#define DAC1 DAC +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief DAC1 CH1 driver identifier.*/ +#if STM32_DAC_USE_DAC1_CH1 || defined(__DOXYGEN__) +DACDriver DACD1; +#endif + +///** @brief DAC1 CH2 driver identifier.*/ +//#if (STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +//DACDriver DACD2; +//#endif +// +///** @brief DAC2 CH1 driver identifier.*/ +//#if STM32_DAC_USE_DAC2_CH1 || defined(__DOXYGEN__) +//DACDriver DACD3; +//#endif +// +///** @brief DAC2 CH2 driver identifier.*/ +//#if (STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +//DACDriver DACD4; +//#endif +// +///** @brief DAC3 CH1 driver identifier.*/ +//#if STM32_DAC_USE_DAC3_CH1 || defined(__DOXYGEN__) +//DACDriver DACD5; +//#endif +// +///** @brief DAC3 CH2 driver identifier.*/ +//#if (STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +//DACDriver DACD6; +//#endif +// +///** @brief DAC4 CH1 driver identifier.*/ +//#if STM32_DAC_USE_DAC4_CH1 || defined(__DOXYGEN__) +//DACDriver DACD7; +//#endif +// +///** @brief DAC4 CH2 driver identifier.*/ +//#if (STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +//DACDriver DACD8; +//#endif + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +#if STM32_DAC_USE_DAC1_CH1 == TRUE +static const dacparams_t dac1_ch1_params = { + .dac = DAC1, + .dataoffset = 0U, + .regshift = 0U, + .regmask = 0xFFFF0000U, + .dmastream = STM32_DAC_DAC1_CH1_BDMA_STREAM, +#if STM32_DMA_SUPPORTS_DMAMUX + .peripheral = STM32_DMAMUX1_DAC1_CH1, +#endif + .dmamode = STM32_BDMA_CR_MSIZE_HWORD | STM32_BDMA_CR_PSIZE_WORD | + STM32_BDMA_CR_PL(STM32_DAC_DAC1_CH1_DMA_PRIORITY) | + STM32_BDMA_CR_DIR_M2P | + STM32_BDMA_CR_MINC | STM32_BDMA_CR_TCIE | STM32_BDMA_CR_HTIE | + STM32_BDMA_CR_TEIE | STM32_BDMA_CR_CIRC, + .dmairqprio = STM32_DAC_DAC1_CH1_IRQ_PRIORITY +}; +#endif + +//#if STM32_DAC_USE_DAC1_CH2 == TRUE +//static const dacparams_t dac1_ch2_params = { +// .dac = DAC1, +// .dataoffset = CHANNEL_DATA_OFFSET, +// .regshift = 16U, +// .regmask = 0x0000FFFFU, +// .dmastream = STM32_DAC_DAC1_CH2_DMA_STREAM, +//#if STM32_DMA_SUPPORTS_DMAMUX +// .peripheral = STM32_DMAMUX1_DAC1_CH2, +//#endif +// .dmamode = STM32_DMA_CR_CHSEL(DAC1_CH2_DMA_CHANNEL) | +// STM32_DMA_CR_PL(STM32_DAC_DAC1_CH2_DMA_PRIORITY) | +// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | +// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | +// STM32_DMA_CR_TCIE, +// .dmairqprio = STM32_DAC_DAC1_CH2_IRQ_PRIORITY +//}; +//#endif +// +//#if STM32_DAC_USE_DAC2_CH1 == TRUE +//static const dacparams_t dac2_ch1_params = { +// .dac = DAC2, +// .dataoffset = 0U, +// .regshift = 0U, +// .regmask = 0xFFFF0000U, +// .dmastream = STM32_DAC_DAC2_CH1_DMA_STREAM, +//#if STM32_DMA_SUPPORTS_DMAMUX +// .peripheral = STM32_DMAMUX1_DAC2_CH1, +//#endif +// .dmamode = STM32_DMA_CR_CHSEL(DAC2_CH1_DMA_CHANNEL) | +// STM32_DMA_CR_PL(STM32_DAC_DAC2_CH1_DMA_PRIORITY) | +// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | +// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | +// STM32_DMA_CR_TCIE, +// .dmairqprio = STM32_DAC_DAC2_CH1_IRQ_PRIORITY +//}; +//#endif +// +//#if STM32_DAC_USE_DAC2_CH2 == TRUE +//static const dacparams_t dac2_ch2_params = { +// .dac = DAC2, +// .dataoffset = CHANNEL_DATA_OFFSET, +// .regshift = 16U, +// .regmask = 0x0000FFFFU, +// .dmastream = STM32_DAC_DAC2_CH2_DMA_STREAM, +//#if STM32_DMA_SUPPORTS_DMAMUX +// .peripheral = STM32_DMAMUX1_DAC2_CH2, +//#endif +// .dmamode = STM32_DMA_CR_CHSEL(DAC2_CH2_DMA_CHANNEL) | +// STM32_DMA_CR_PL(STM32_DAC_DAC2_CH2_DMA_PRIORITY) | +// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | +// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | +// STM32_DMA_CR_TCIE, +// .dmairqprio = STM32_DAC_DAC2_CH2_IRQ_PRIORITY +//}; +//#endif +// +//#if STM32_DAC_USE_DAC3_CH1 == TRUE +//static const dacparams_t dac3_ch1_params = { +// .dac = DAC3, +// .dataoffset = 0U, +// .regshift = 0U, +// .regmask = 0xFFFF0000U, +// .dmastream = STM32_DAC_DAC3_CH1_DMA_STREAM, +//#if STM32_DMA_SUPPORTS_DMAMUX +// .peripheral = STM32_DMAMUX1_DAC3_CH1, +//#endif +// .dmamode = STM32_DMA_CR_CHSEL(DAC3_CH1_DMA_CHANNEL) | +// STM32_DMA_CR_PL(STM32_DAC_DAC3_CH1_DMA_PRIORITY) | +// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | +// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | +// STM32_DMA_CR_TCIE, +// .dmairqprio = STM32_DAC_DAC3_CH1_IRQ_PRIORITY +//}; +//#endif +// +//#if STM32_DAC_USE_DAC3_CH2 == TRUE +//static const dacparams_t dac3_ch2_params = { +// .dac = DAC3, +// .dataoffset = CHANNEL_DATA_OFFSET, +// .regshift = 16U, +// .regmask = 0x0000FFFFU, +// .dmastream = STM32_DAC_DAC3_CH2_DMA_STREAM, +//#if STM32_DMA_SUPPORTS_DMAMUX +// .peripheral = STM32_DMAMUX1_DAC3_CH2, +//#endif +// .dmamode = STM32_DMA_CR_CHSEL(DAC3_CH2_DMA_CHANNEL) | +// STM32_DMA_CR_PL(STM32_DAC_DAC3_CH2_DMA_PRIORITY) | +// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | +// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | +// STM32_DMA_CR_TCIE, +// .dmairqprio = STM32_DAC_DAC3_CH2_IRQ_PRIORITY +//}; +//#endif +// +//#if STM32_DAC_USE_DAC4_CH1 == TRUE +//static const dacparams_t dac4_ch1_params = { +// .dac = DAC4, +// .dataoffset = 0U, +// .regshift = 0U, +// .regmask = 0xFFFF0000U, +// .dmastream = STM32_DAC_DAC4_CH1_DMA_STREAM, +//#if STM32_DMA_SUPPORTS_DMAMUX +// .peripheral = STM32_DMAMUX1_DAC4_CH1, +//#endif +// .dmamode = STM32_DMA_CR_CHSEL(DAC4_CH1_DMA_CHANNEL) | +// STM32_DMA_CR_PL(STM32_DAC_DAC4_CH1_DMA_PRIORITY) | +// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | +// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | +// STM32_DMA_CR_TCIE, +// .dmairqprio = STM32_DAC_DAC4_CH1_IRQ_PRIORITY +//}; +//#endif +// +//#if STM32_DAC_USE_DAC4_CH2 == TRUE +//static const dacparams_t dac4_ch2_params = { +// .dac = DAC4, +// .dataoffset = CHANNEL_DATA_OFFSET, +// .regshift = 16U, +// .regmask = 0x0000FFFFU, +// .dmastream = STM32_DAC_DAC4_CH2_DMA_STREAM, +//#if STM32_DMA_SUPPORTS_DMAMUX +// .peripheral = STM32_DMAMUX1_DAC4_CH2, +//#endif +// .dmamode = STM32_DMA_CR_CHSEL(DAC4_CH2_DMA_CHANNEL) | +// STM32_DMA_CR_PL(STM32_DAC_DAC4_CH2_DMA_PRIORITY) | +// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P | +// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE | +// STM32_DMA_CR_TCIE, +// .dmairqprio = STM32_DAC_DAC4_CH2_IRQ_PRIORITY +//}; +//#endif + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Shared end/half-of-tx service routine. + * + * @param[in] dacp pointer to the @p DACDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void dac_lld_serve_tx_interrupt(DACDriver *dacp, uint32_t flags) { + if ((flags & STM32_BDMA_ISR_TEIF) != 0) { + /* DMA errors handling.*/ + dac_lld_stop_conversion(dacp); + _dac_isr_error_code(dacp, DAC_ERR_DMAFAILURE); + } + else { + if ((flags & STM32_BDMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _dac_isr_half_code(dacp); + } + if ((flags & STM32_BDMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _dac_isr_full_code(dacp); + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level DAC driver initialization. + * + * @notapi + */ +void dac_lld_init(void) { + +#if STM32_DAC_USE_DAC1_CH1 + dacObjectInit(&DACD1); + DACD1.params = &dac1_ch1_params; + DACD1.bdma = NULL; +#endif + +//#if STM32_DAC_USE_DAC1_CH2 +// dacObjectInit(&DACD2); +// DACD2.params = &dac1_ch2_params; +// DACD2.dma = NULL; +//#endif +// +//#if STM32_DAC_USE_DAC2_CH1 +// dacObjectInit(&DACD3); +// DACD3.params = &dac2_ch1_params; +// DACD3.dma = NULL; +//#endif +// +//#if STM32_DAC_USE_DAC2_CH2 +// dacObjectInit(&DACD4); +// DACD4.params = &dac2_ch2_params; +// DACD4.dma = NULL; +//#endif +// +//#if STM32_DAC_USE_DAC3_CH1 +// dacObjectInit(&DACD5); +// DACD5.params = &dac3_ch1_params; +// DACD5.dma = NULL; +//#endif +// +//#if STM32_DAC_USE_DAC3_CH2 +// dacObjectInit(&DACD6); +// DACD6.params = &dac3_ch2_params; +// DACD6.dma = NULL; +//#endif +// +//#if STM32_DAC_USE_DAC4_CH1 +// dacObjectInit(&DACD7); +// DACD7.params = &dac4_ch1_params; +// DACD7.dma = NULL; +//#endif +// +//#if STM32_DAC_USE_DAC4_CH2 +// dacObjectInit(&DACD8); +// DACD8.params = &dac4_ch2_params; +// DACD8.dma = NULL; +//#endif +} + +/** + * @brief Configures and activates the DAC peripheral. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @notapi + */ +void dac_lld_start(DACDriver *dacp) { + + /* If the driver is in DAC_STOP state then a full initialization is + required.*/ + if (dacp->state == DAC_STOP) { + dacchannel_t channel = 0; + + /* Enabling the clock source.*/ +#if STM32_DAC_USE_DAC1_CH1 + if (&DACD1 == dacp) { + rccEnableDAC1(true); + } +#endif + +//#if STM32_DAC_USE_DAC1_CH2 +// if (&DACD2 == dacp) { +// rccEnableDAC1(true); +// channel = 1; +// } +//#endif +// +//#if STM32_DAC_USE_DAC2_CH1 +// if (&DACD3 == dacp) { +// rccEnableDAC2(true); +// } +//#endif +// +//#if STM32_DAC_USE_DAC2_CH2 +// if (&DACD4 == dacp) { +// rccEnableDAC2(true); +// channel = 1; +// } +//#endif +// +//#if STM32_DAC_USE_DAC3_CH1 +// if (&DACD5 == dacp) { +// rccEnableDAC3(true); +// } +//#endif +// +//#if STM32_DAC_USE_DAC3_CH2 +// if (&DACD6 == dacp) { +// rccEnableDAC3(true); +// channel = 1; +// } +//#endif +// +//#if STM32_DAC_USE_DAC4_CH1 +// if (&DACD7 == dacp) { +// rccEnableDAC4(true); +// } +//#endif +// +//#if STM32_DAC_USE_DAC4_CH2 +// if (&DACD8 == dacp) { +// rccEnableDAC4(true); +// channel = 1; +// } +//#endif + + /* Enabling DAC in SW triggering mode initially, initializing data to + zero.*/ +#if STM32_DAC_DUAL_MODE == FALSE + { + uint32_t cr; + + cr = dacp->params->dac->CR; + cr &= dacp->params->regmask; + cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift; + dacp->params->dac->MCR = 2; + dacp->params->dac->CR = cr; + dac_lld_put_channel(dacp, channel, dacp->config->init); + } +#else + if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) || + (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) || + (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) { + dacp->params->dac->CR = DAC_CR_EN2 | (dacp->config->cr << 16) | DAC_CR_EN1 | dacp->config->cr; + dac_lld_put_channel(dacp, 1U, dacp->config->init); + } + else { + dacp->params->dac->CR = DAC_CR_EN1 | dacp->config->cr; + } + dac_lld_put_channel(dacp, channel, dacp->config->init); +#endif + } +} + +/** + * @brief Deactivates the DAC peripheral. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @notapi + */ +void dac_lld_stop(DACDriver *dacp) { + + /* If in ready state then disables the DAC clock.*/ + if (dacp->state == DAC_READY) { + + /* Disabling DAC.*/ + dacp->params->dac->CR &= dacp->params->regmask; + +#if STM32_DAC_USE_DAC1_CH1 + if (&DACD1 == dacp) { + if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) { + rccDisableDAC1(); + } + } +#endif + +//#if STM32_DAC_USE_DAC1_CH2 +// if (&DACD2 == dacp) { +// if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) { +// rccDisableDAC1(); +// } +// } +//#endif +// +//#if STM32_DAC_USE_DAC2_CH1 +// if (&DACD3 == dacp) { +// if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) { +// rccDisableDAC2(); +// } +// } +//#endif +// +//#if STM32_DAC_USE_DAC2_CH2 +// if (&DACD4 == dacp) { +// if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) { +// rccDisableDAC2(); +// } +// } +//#endif +// +//#if STM32_DAC_USE_DAC3_CH1 +// if (&DACD5 == dacp) { +// if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) { +// rccDisableDAC3(); +// } +// } +//#endif +// +//#if STM32_DAC_USE_DAC3_CH2 +// if (&DACD6 == dacp) { +// if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) { +// rccDisableDAC3(); +// } +// } +//#endif +// +//#if STM32_DAC_USE_DAC4_CH1 +// if (&DACD7 == dacp) { +// if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) { +// rccDisableDAC4(); +// } +// } +//#endif +// +//#if STM32_DAC_USE_DAC4_CH2 +// if (&DACD8 == dacp) { +// if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) { +// rccDisableDAC4(); +// } +// } +//#endif + } +} + +/** + * @brief Outputs a value directly on a DAC channel. + * + * @param[in] dacp pointer to the @p DACDriver object + * @param[in] channel DAC channel number + * @param[in] sample value to be output + * + * @api + */ +void dac_lld_put_channel(DACDriver *dacp, + dacchannel_t channel, + dacsample_t sample) { + + switch (dacp->config->datamode) { + case DAC_DHRM_12BIT_RIGHT: +#if STM32_DAC_DUAL_MODE + case DAC_DHRM_12BIT_RIGHT_DUAL: +#endif + if (channel == 0U) { +#if STM32_DAC_DUAL_MODE + dacp->params->dac->DHR12R1 = (uint32_t)sample; +#else + *(&dacp->params->dac->DHR12R1 + dacp->params->dataoffset) = (uint32_t)sample; +#endif + } +#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \ + STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2) + else { + dacp->params->dac->DHR12R2 = (uint32_t)sample; + } +#endif + break; + case DAC_DHRM_12BIT_LEFT: +#if STM32_DAC_DUAL_MODE + case DAC_DHRM_12BIT_LEFT_DUAL: +#endif + if (channel == 0U) { +#if STM32_DAC_DUAL_MODE + dacp->params->dac->DHR12L1 = (uint32_t)sample; +#else + *(&dacp->params->dac->DHR12L1 + dacp->params->dataoffset) = (uint32_t)sample; +#endif + } +#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \ + STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2) + else { + dacp->params->dac->DHR12L2 = (uint32_t)sample; + } +#endif + break; + case DAC_DHRM_8BIT_RIGHT: +#if STM32_DAC_DUAL_MODE + case DAC_DHRM_8BIT_RIGHT_DUAL: +#endif + if (channel == 0U) { +#if STM32_DAC_DUAL_MODE + dacp->params->dac->DHR8R1 = (uint32_t)sample; +#else + *(&dacp->params->dac->DHR8R1 + dacp->params->dataoffset) = (uint32_t)sample; +#endif + } +#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \ + STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2) + else { + dacp->params->dac->DHR8R2 = (uint32_t)sample; + } +#endif + break; + default: + osalDbgAssert(false, "unexpected DAC mode"); + break; + } +} + +/** + * @brief Starts a DAC conversion. + * @details Starts an asynchronous conversion operation. + * @note In @p DAC_DHRM_8BIT_RIGHT mode the parameters passed to the + * callback are wrong because two samples are packed in a single + * dacsample_t element. This will not be corrected, do not rely + * on those parameters. + * @note In @p DAC_DHRM_8BIT_RIGHT_DUAL mode two samples are treated + * as a single 16 bits sample and packed into a single dacsample_t + * element. The num_channels must be set to one in the group + * conversion configuration structure. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @notapi + */ +void dac_lld_start_conversion(DACDriver *dacp) { + uint32_t n, cr, dmamode; + + /* Number of DMA operations per buffer.*/ + n = dacp->depth * dacp->grpp->num_channels; + + /* Allocating the DMA channel.*/ + dacp->bdma = bdmaStreamAllocI(dacp->params->dmastream, + dacp->params->dmairqprio, + (stm32_dmaisr_t)dac_lld_serve_tx_interrupt, + (void *)dacp); + osalDbgAssert(dacp->bdma != NULL, "unable to allocate stream"); +#if STM32_DMA_SUPPORTS_DMAMUX + bdmaSetRequestSource(dacp->bdma, dacp->params->peripheral); +#endif + + /* DMA settings depend on the chosen DAC mode.*/ + switch (dacp->config->datamode) { + /* Sets the DAC data register */ + case DAC_DHRM_12BIT_RIGHT: + osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); + + bdmaStreamSetPeripheral(dacp->bdma, &dacp->params->dac->DHR12R1 + + dacp->params->dataoffset); + dmamode = dacp->params->dmamode | + STM32_BDMA_CR_PSIZE_WORD | STM32_BDMA_CR_MSIZE_HWORD; + break; +// case DAC_DHRM_12BIT_LEFT: +// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12L1 + +// dacp->params->dataoffset); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; +// break; +// case DAC_DHRM_8BIT_RIGHT: +// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8R1 + +// dacp->params->dataoffset); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; +// +// /* In this mode the size of the buffer is halved because two samples +// packed in a single dacsample_t element.*/ +// n = (n + 1) / 2; +// break; +//#if STM32_DAC_DUAL_MODE == TRUE +// case DAC_DHRM_12BIT_RIGHT_DUAL: +// osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12RD); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD; +// n /= 2; +// break; +// case DAC_DHRM_12BIT_LEFT_DUAL: +// osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12LD); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD; +// n /= 2; +// break; +// case DAC_DHRM_8BIT_RIGHT_DUAL: +// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); +// +// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8RD); +// dmamode = dacp->params->dmamode | +// STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; +// n /= 2; +// break; +//#endif + default: + osalDbgAssert(false, "unexpected DAC mode"); + return; + } + + bdmaStreamSetMemory(dacp->bdma, dacp->samples); + bdmaStreamSetTransactionSize(dacp->bdma, n); + bdmaStreamSetMode(dacp->bdma, dmamode | + STM32_BDMA_CR_TEIE | + STM32_BDMA_CR_HTIE | STM32_BDMA_CR_TCIE); + bdmaStreamEnable(dacp->bdma); + + /* DAC configuration.*/ + cr = dacp->params->dac->CR; + +#if STM32_DAC_DUAL_MODE == FALSE + cr &= dacp->params->regmask; + cr |= (DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift; +#else + cr = DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr + | (dacp->grpp->trigger << DAC_CR_TSEL2_Pos) | DAC_CR_TEN2 | DAC_CR_EN2 | (dacp->config->cr << 16); +#endif + + dacp->params->dac->CR = cr; +} + +/** + * @brief Stops an ongoing conversion. + * @details This function stops the currently ongoing conversion and returns + * the driver in the @p DAC_READY state. If there was no conversion + * being processed then the function does nothing. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @iclass + */ +void dac_lld_stop_conversion(DACDriver *dacp) { + uint32_t cr; + + /* DMA channel disabled and released.*/ + bdmaStreamDisable(dacp->bdma); + bdmaStreamFreeI(dacp->bdma); + dacp->bdma = NULL; + + cr = dacp->params->dac->CR; + +#if STM32_DAC_DUAL_MODE == FALSE + cr &= dacp->params->regmask; + cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift; +#else + if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) || + (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) || + (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) { + cr = DAC_CR_EN2 | (dacp->config->cr << 16) | + DAC_CR_EN1 | dacp->config->cr; + } + else { + cr = DAC_CR_EN1 | dacp->config->cr; + } +#endif + + dacp->params->dac->CR = cr; +} + +#endif /* HAL_USE_DAC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h new file mode 100644 index 0000000..09550fa --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h @@ -0,0 +1,662 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DACv1/hal_dac_lld.h + * @brief STM32 DAC subsystem low level driver header. + * + * @addtogroup DAC + * @{ + */ + +#ifndef HAL_DAC_LLD_H +#define HAL_DAC_LLD_H + +#if HAL_USE_DAC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name DAC trigger modes + * @{ + */ +#define DAC_TRG_MASK 7U +#define DAC_TRG(n) (n) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief Enables the DAC dual mode. + * @note In dual mode DAC second channels cannot be accessed individually. + */ +#if !defined(STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +#define STM32_DAC_DUAL_MODE FALSE +#endif + +/** + * @brief DAC1 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC1 channel 1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC1_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC1_CH1 FALSE +#endif + +/** + * @brief DAC1 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC1 channel 2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC1_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC1_CH2 FALSE +#endif + +/** + * @brief DAC2 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC2 channel 1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC2_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC2_CH1 FALSE +#endif + +/** + * @brief DAC2 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC2 channel 2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC2_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC2_CH2 FALSE +#endif + +/** + * @brief DAC3 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC3 channel 1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC3_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC3_CH1 FALSE +#endif + +/** + * @brief DAC3 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC3 channel 2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC3_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC3_CH2 FALSE +#endif + +/** + * @brief DAC4 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC4 channel 1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC4_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC4_CH1 FALSE +#endif + +/** + * @brief DAC4 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC4 channel 2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC4_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC4_CH2 FALSE +#endif + +/** + * @brief DAC1 CH1 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC1_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC1 CH2 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC1_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC2 CH1 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC2_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC2_CH1_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC2 CH2 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC2_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC2_CH2_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC3 CH1 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC3_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC3_CH1_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC3 CH2 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC3_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC3_CH2_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC4 CH1 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC4_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC4_CH1_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC4 CH2 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC4_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC4_CH2_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC1 CH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC1_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC1 CH2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC1_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC2 CH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC2_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC2_CH1_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC2 CH2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC2_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC2_CH2_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC3 CH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC3_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC3_CH1_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC3 CH2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC3_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC3_CH2_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC4 CH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC4_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC4_CH1_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC4 CH2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC4_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC4_CH2_DMA_PRIORITY 2 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Handling missing registry keys.*/ +#if !defined(STM32_HAS_DAC1_CH1) +#define STM32_HAS_DAC1_CH1 FALSE +#endif +#if !defined(STM32_HAS_DAC1_CH2) +#define STM32_HAS_DAC1_CH2 FALSE +#endif +#if !defined(STM32_HAS_DAC2_CH1) +#define STM32_HAS_DAC2_CH1 FALSE +#endif +#if !defined(STM32_HAS_DAC2_CH2) +#define STM32_HAS_DAC2_CH2 FALSE +#endif +#if !defined(STM32_HAS_DAC3_CH1) +#define STM32_HAS_DAC3_CH1 FALSE +#endif +#if !defined(STM32_HAS_DAC3_CH2) +#define STM32_HAS_DAC3_CH2 FALSE +#endif +#if !defined(STM32_HAS_DAC4_CH1) +#define STM32_HAS_DAC4_CH1 FALSE +#endif +#if !defined(STM32_HAS_DAC4_CH2) +#define STM32_HAS_DAC4_CH2 FALSE +#endif + +#if STM32_DAC_USE_DAC1_CH1 && !STM32_HAS_DAC1_CH1 +#error "DAC1 CH1 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && !STM32_HAS_DAC1_CH2 +#error "DAC1 CH2 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && !STM32_HAS_DAC2_CH1 +#error "DAC2 CH1 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && !STM32_HAS_DAC2_CH2 +#error "DAC2 CH2 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && !STM32_HAS_DAC3_CH1 +#error "DAC3 CH1 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && !STM32_HAS_DAC3_CH2 +#error "DAC3 CH2 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && !STM32_HAS_DAC4_CH1 +#error "DAC4 CH1 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && !STM32_HAS_DAC4_CH2 +#error "DAC4 CH2 not present in the selected device" +#endif + +#if (STM32_DAC_USE_DAC1_CH2 || STM32_DAC_USE_DAC2_CH2 || \ + STM32_DAC_USE_DAC3_CH2 || STM32_DAC_USE_DAC4_CH2) && STM32_DAC_DUAL_MODE +#error "DACx CH2 cannot be used independently in dual mode" +#endif + +#if !STM32_DAC_USE_DAC1_CH1 && !STM32_DAC_USE_DAC1_CH2 && \ + !STM32_DAC_USE_DAC2_CH1 && !STM32_DAC_USE_DAC2_CH2 && \ + !STM32_DAC_USE_DAC3_CH1 && !STM32_DAC_USE_DAC3_CH2 && \ + !STM32_DAC_USE_DAC4_CH1 && !STM32_DAC_USE_DAC4_CH2 +#error "DAC driver activated but no DAC peripheral assigned" +#endif + +#if STM32_DAC_USE_DAC1_CH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC1 CH1" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC1 CH2" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC2 CH1" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC2 CH2" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC3 CH1" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC3 CH2" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC4 CH1" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC4 CH2" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_DAC_USE_DAC1_CH1 && !defined(STM32_DAC_DAC1_CH1_DMA_STREAM) +#error "DAC1 CH1 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && !defined(STM32_DAC_DAC1_CH2_DMA_STREAM) +#error "DAC1 CH2 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && !defined(STM32_DAC_DAC2_CH1_DMA_STREAM) +#error "DAC2 CH1 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && !defined(STM32_DAC_DAC2_CH2_DMA_STREAM) +#error "DAC2 CH2 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && !defined(STM32_DAC_DAC3_CH1_DMA_STREAM) +#error "DAC3 CH1 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && !defined(STM32_DAC_DAC3_CH2_DMA_STREAM) +#error "DAC3 CH2 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && !defined(STM32_DAC_DAC4_CH1_DMA_STREAM) +#error "DAC4 CH1 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && !defined(STM32_DAC_DAC4_CH2_DMA_STREAM) +#error "DAC4 CH2 DMA stream not defined" +#endif + +#if STM32_DMA_SUPPORTS_DMAMUX + +#else /* !STM32_DMA_SUPPORTS_DMAMUX */ + +/* Check on the validity of the assigned DMA streams.*/ +#if STM32_DAC_USE_DAC1_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH1_DMA_STREAM, STM32_DAC1_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH1" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH2_DMA_STREAM, STM32_DAC1_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH2" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH1_DMA_STREAM, STM32_DAC2_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH1" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH2_DMA_STREAM, STM32_DAC2_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH2" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH1_DMA_STREAM, STM32_DAC3_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH1" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH2_DMA_STREAM, STM32_DAC3_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH2" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH1_DMA_STREAM, STM32_DAC4_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH1" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH2_DMA_STREAM, STM32_DAC4_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH2" +#endif + +#endif /* !STM32_DMA_SUPPORTS_DMAMUX */ + +#endif /* STM32_ADVANCED_DMA */ + +#if STM32_DAC_USE_DAC1_CH1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC1 CH1" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC1 CH2" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC2 CH1" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC2 CH2" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC3 CH1" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC3 CH2" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC4 CH1" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC4 CH2" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/** + * @brief Max DAC channels. + */ +#if STM32_DAC_DUAL_MODE == FALSE +#define DAC_MAX_CHANNELS 2 +#else +#define DAC_MAX_CHANNELS 1 +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a DAC channel index. + */ +typedef uint32_t dacchannel_t; + +/** + * @brief Type representing a DAC sample. + */ +typedef uint16_t dacsample_t; + +/** + * @brief DAC channel parameters type. + */ +typedef struct { + /** + * @brief Pointer to the DAC registers block. + */ + DAC_TypeDef *dac; + /** + * @brief DAC data registers offset. + */ + uint32_t dataoffset; + /** + * @brief DAC CR register bit offset. + */ + uint32_t regshift; + /** + * @brief DAC CR register mask. + */ + uint32_t regmask; + /** + * @brief Associated DMA stream. + */ + uint32_t dmastream; + /** + * @brief Mode bits for the DMA. + */ + uint32_t dmamode; + /** + * @brief DMA channel IRQ priority. + */ + uint32_t dmairqprio; +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__) + /** + * @brief DMAMUX peripheral selector. + */ + uint32_t peripheral; +#endif +} dacparams_t; + +/** + * @brief Possible DAC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + DAC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ + DAC_ERR_UNDERFLOW = 1 /**< DAC overflow condition. */ +} dacerror_t; + +/** + * @brief Samples alignment and size mode. + */ +typedef enum { + DAC_DHRM_12BIT_RIGHT = 0, + DAC_DHRM_12BIT_LEFT = 1, + DAC_DHRM_8BIT_RIGHT = 2, +#if STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) + DAC_DHRM_12BIT_RIGHT_DUAL = 3, + DAC_DHRM_12BIT_LEFT_DUAL = 4, + DAC_DHRM_8BIT_RIGHT_DUAL = 5 +#endif +} dacdhrmode_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the DAC driver structure. + */ +#define dac_lld_driver_fields \ + /* DAC channel parameters.*/ \ + const dacparams_t *params; \ + /* Associated DMA.*/ \ + const stm32_dma_stream_t *dma + +/** + * @brief Low level fields of the DAC configuration structure. + */ +#define dac_lld_config_fields \ + /* Initial output on DAC channels.*/ \ + dacsample_t init; \ + /* DAC data holding register mode.*/ \ + dacdhrmode_t datamode; \ + /* DAC control register lower 16 bits.*/ \ + uint32_t cr + +/** + * @brief Low level fields of the DAC group configuration structure. + */ +#define dac_lld_conversion_group_fields \ + /* DAC initialization data. This field contains the (not shifted) value \ + to be put into the TSEL field of the DAC CR register during \ + initialization. All other fields are handled internally.*/ \ + uint32_t trigger + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_DAC_USE_DAC1_CH1 && !defined(__DOXYGEN__) +extern DACDriver DACD1; +#endif + +#if STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) +extern DACDriver DACD2; +#endif + +#if STM32_DAC_USE_DAC2_CH1 && !defined(__DOXYGEN__) +extern DACDriver DACD3; +#endif + +#if STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) +extern DACDriver DACD4; +#endif + +#if STM32_DAC_USE_DAC3_CH1 && !defined(__DOXYGEN__) +extern DACDriver DACD5; +#endif + +#if STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) +extern DACDriver DACD6; +#endif + +#if STM32_DAC_USE_DAC4_CH1 && !defined(__DOXYGEN__) +extern DACDriver DACD7; +#endif + +#if STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) +extern DACDriver DACD8; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void dac_lld_init(void); + void dac_lld_start(DACDriver *dacp); + void dac_lld_stop(DACDriver *dacp); + void dac_lld_put_channel(DACDriver *dacp, + dacchannel_t channel, + dacsample_t sample); + void dac_lld_start_conversion(DACDriver *dacp); + void dac_lld_stop_conversion(DACDriver *dacp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_DAC */ + +#endif /* HAL_DAC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h.bak b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h.bak new file mode 100644 index 0000000..1e369ca --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h.bak @@ -0,0 +1,662 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DACv1/hal_dac_lld.h + * @brief STM32 DAC subsystem low level driver header. + * + * @addtogroup DAC + * @{ + */ + +#ifndef HAL_DAC_LLD_H +#define HAL_DAC_LLD_H + +#if HAL_USE_DAC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name DAC trigger modes + * @{ + */ +#define DAC_TRG_MASK 7U +#define DAC_TRG(n) (n) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief Enables the DAC dual mode. + * @note In dual mode DAC second channels cannot be accessed individually. + */ +#if !defined(STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +#define STM32_DAC_DUAL_MODE FALSE +#endif + +/** + * @brief DAC1 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC1 channel 1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC1_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC1_CH1 FALSE +#endif + +/** + * @brief DAC1 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC1 channel 2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC1_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC1_CH2 FALSE +#endif + +/** + * @brief DAC2 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC2 channel 1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC2_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC2_CH1 FALSE +#endif + +/** + * @brief DAC2 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC2 channel 2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC2_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC2_CH2 FALSE +#endif + +/** + * @brief DAC3 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC3 channel 1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC3_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC3_CH1 FALSE +#endif + +/** + * @brief DAC3 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC3 channel 2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC3_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC3_CH2 FALSE +#endif + +/** + * @brief DAC4 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC4 channel 1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC4_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC4_CH1 FALSE +#endif + +/** + * @brief DAC4 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC4 channel 2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_DAC_USE_DAC4_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC4_CH2 FALSE +#endif + +/** + * @brief DAC1 CH1 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC1_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC1 CH2 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC1_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC2 CH1 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC2_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC2_CH1_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC2 CH2 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC2_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC2_CH2_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC3 CH1 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC3_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC3_CH1_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC3 CH2 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC3_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC3_CH2_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC4 CH1 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC4_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC4_CH1_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC4 CH2 interrupt priority level setting. + */ +#if !defined(STM32_DAC_DAC4_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC4_CH2_IRQ_PRIORITY 10 +#endif + +/** + * @brief DAC1 CH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC1_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC1 CH2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC1_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC2 CH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC2_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC2_CH1_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC2 CH2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC2_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC2_CH2_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC3 CH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC3_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC3_CH1_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC3 CH2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC3_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC3_CH2_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC4 CH1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC4_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC4_CH1_DMA_PRIORITY 2 +#endif + +/** + * @brief DAC4 CH2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_DAC_DAC4_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC_DAC4_CH2_DMA_PRIORITY 2 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Handling missing registry keys.*/ +#if !defined(STM32_HAS_DAC1_CH1) +#define STM32_HAS_DAC1_CH1 FALSE +#endif +#if !defined(STM32_HAS_DAC1_CH2) +#define STM32_HAS_DAC1_CH2 FALSE +#endif +#if !defined(STM32_HAS_DAC2_CH1) +#define STM32_HAS_DAC2_CH1 FALSE +#endif +#if !defined(STM32_HAS_DAC2_CH2) +#define STM32_HAS_DAC2_CH2 FALSE +#endif +#if !defined(STM32_HAS_DAC3_CH1) +#define STM32_HAS_DAC3_CH1 FALSE +#endif +#if !defined(STM32_HAS_DAC3_CH2) +#define STM32_HAS_DAC3_CH2 FALSE +#endif +#if !defined(STM32_HAS_DAC4_CH1) +#define STM32_HAS_DAC4_CH1 FALSE +#endif +#if !defined(STM32_HAS_DAC4_CH2) +#define STM32_HAS_DAC4_CH2 FALSE +#endif + +#if STM32_DAC_USE_DAC1_CH1 && !STM32_HAS_DAC1_CH1 +#error "DAC1 CH1 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && !STM32_HAS_DAC1_CH2 +#error "DAC1 CH2 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && !STM32_HAS_DAC2_CH1 +#error "DAC2 CH1 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && !STM32_HAS_DAC2_CH2 +#error "DAC2 CH2 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && !STM32_HAS_DAC3_CH1 +#error "DAC3 CH1 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && !STM32_HAS_DAC3_CH2 +#error "DAC3 CH2 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && !STM32_HAS_DAC4_CH1 +#error "DAC4 CH1 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && !STM32_HAS_DAC4_CH2 +#error "DAC4 CH2 not present in the selected device" +#endif + +#if (STM32_DAC_USE_DAC1_CH2 || STM32_DAC_USE_DAC2_CH2 || \ + STM32_DAC_USE_DAC3_CH2 || STM32_DAC_USE_DAC4_CH2) && STM32_DAC_DUAL_MODE +#error "DACx CH2 cannot be used independently in dual mode" +#endif + +#if !STM32_DAC_USE_DAC1_CH1 && !STM32_DAC_USE_DAC1_CH2 && \ + !STM32_DAC_USE_DAC2_CH1 && !STM32_DAC_USE_DAC2_CH2 && \ + !STM32_DAC_USE_DAC3_CH1 && !STM32_DAC_USE_DAC3_CH2 && \ + !STM32_DAC_USE_DAC4_CH1 && !STM32_DAC_USE_DAC4_CH2 +#error "DAC driver activated but no DAC peripheral assigned" +#endif + +#if STM32_DAC_USE_DAC1_CH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC1 CH1" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC1 CH2" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC2 CH1" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC2 CH2" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC3 CH1" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC3 CH2" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC4 CH1" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to DAC4 CH2" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_DAC_USE_DAC1_CH1 && !defined(STM32_DAC_DAC1_CH1_BDMA_STREAM) +#error "DAC1 CH1 BDMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && !defined(STM32_DAC_DAC1_CH2_DMA_STREAM) +#error "DAC1 CH2 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && !defined(STM32_DAC_DAC2_CH1_DMA_STREAM) +#error "DAC2 CH1 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && !defined(STM32_DAC_DAC2_CH2_DMA_STREAM) +#error "DAC2 CH2 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && !defined(STM32_DAC_DAC3_CH1_DMA_STREAM) +#error "DAC3 CH1 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && !defined(STM32_DAC_DAC3_CH2_DMA_STREAM) +#error "DAC3 CH2 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && !defined(STM32_DAC_DAC4_CH1_DMA_STREAM) +#error "DAC4 CH1 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && !defined(STM32_DAC_DAC4_CH2_DMA_STREAM) +#error "DAC4 CH2 DMA stream not defined" +#endif + +#if STM32_DMA_SUPPORTS_DMAMUX + +#else /* !STM32_DMA_SUPPORTS_DMAMUX */ + +/* Check on the validity of the assigned DMA streams.*/ +#if STM32_DAC_USE_DAC1_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH1_DMA_STREAM, STM32_DAC1_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH1" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH2_DMA_STREAM, STM32_DAC1_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH2" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH1_DMA_STREAM, STM32_DAC2_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH1" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH2_DMA_STREAM, STM32_DAC2_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH2" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH1_DMA_STREAM, STM32_DAC3_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH1" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH2_DMA_STREAM, STM32_DAC3_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH2" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH1_DMA_STREAM, STM32_DAC4_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH1" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH2_DMA_STREAM, STM32_DAC4_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH2" +#endif + +#endif /* !STM32_DMA_SUPPORTS_DMAMUX */ + +#endif /* STM32_ADVANCED_DMA */ + +#if STM32_DAC_USE_DAC1_CH1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC1 CH1" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC1 CH2" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC2 CH1" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC2 CH2" +#endif + +#if STM32_DAC_USE_DAC3_CH1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC3 CH1" +#endif + +#if STM32_DAC_USE_DAC3_CH2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC3 CH2" +#endif + +#if STM32_DAC_USE_DAC4_CH1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC4 CH1" +#endif + +#if STM32_DAC_USE_DAC4_CH2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to DAC4 CH2" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/** + * @brief Max DAC channels. + */ +#if STM32_DAC_DUAL_MODE == FALSE +#define DAC_MAX_CHANNELS 2 +#else +#define DAC_MAX_CHANNELS 1 +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a DAC channel index. + */ +typedef uint32_t dacchannel_t; + +/** + * @brief Type representing a DAC sample. + */ +typedef uint16_t dacsample_t; + +/** + * @brief DAC channel parameters type. + */ +typedef struct { + /** + * @brief Pointer to the DAC registers block. + */ + DAC_TypeDef *dac; + /** + * @brief DAC data registers offset. + */ + uint32_t dataoffset; + /** + * @brief DAC CR register bit offset. + */ + uint32_t regshift; + /** + * @brief DAC CR register mask. + */ + uint32_t regmask; + /** + * @brief Associated DMA stream. + */ + uint32_t dmastream; + /** + * @brief Mode bits for the DMA. + */ + uint32_t dmamode; + /** + * @brief DMA channel IRQ priority. + */ + uint32_t dmairqprio; +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__) + /** + * @brief DMAMUX peripheral selector. + */ + uint32_t peripheral; +#endif +} dacparams_t; + +/** + * @brief Possible DAC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + DAC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ + DAC_ERR_UNDERFLOW = 1 /**< DAC overflow condition. */ +} dacerror_t; + +/** + * @brief Samples alignment and size mode. + */ +typedef enum { + DAC_DHRM_12BIT_RIGHT = 0, + DAC_DHRM_12BIT_LEFT = 1, + DAC_DHRM_8BIT_RIGHT = 2, +#if STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) + DAC_DHRM_12BIT_RIGHT_DUAL = 3, + DAC_DHRM_12BIT_LEFT_DUAL = 4, + DAC_DHRM_8BIT_RIGHT_DUAL = 5 +#endif +} dacdhrmode_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the DAC driver structure. + */ +#define dac_lld_driver_fields \ + /* DAC channel parameters.*/ \ + const dacparams_t *params; \ + /* Associated DMA.*/ \ + const stm32_bdma_stream_t *bdma + +/** + * @brief Low level fields of the DAC configuration structure. + */ +#define dac_lld_config_fields \ + /* Initial output on DAC channels.*/ \ + dacsample_t init; \ + /* DAC data holding register mode.*/ \ + dacdhrmode_t datamode; \ + /* DAC control register lower 16 bits.*/ \ + uint32_t cr + +/** + * @brief Low level fields of the DAC group configuration structure. + */ +#define dac_lld_conversion_group_fields \ + /* DAC initialization data. This field contains the (not shifted) value \ + to be put into the TSEL field of the DAC CR register during \ + initialization. All other fields are handled internally.*/ \ + uint32_t trigger + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_DAC_USE_DAC1_CH1 && !defined(__DOXYGEN__) +extern DACDriver DACD1; +#endif + +#if STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) +extern DACDriver DACD2; +#endif + +#if STM32_DAC_USE_DAC2_CH1 && !defined(__DOXYGEN__) +extern DACDriver DACD3; +#endif + +#if STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) +extern DACDriver DACD4; +#endif + +#if STM32_DAC_USE_DAC3_CH1 && !defined(__DOXYGEN__) +extern DACDriver DACD5; +#endif + +#if STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) +extern DACDriver DACD6; +#endif + +#if STM32_DAC_USE_DAC4_CH1 && !defined(__DOXYGEN__) +extern DACDriver DACD7; +#endif + +#if STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) +extern DACDriver DACD8; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void dac_lld_init(void); + void dac_lld_start(DACDriver *dacp); + void dac_lld_stop(DACDriver *dacp); + void dac_lld_put_channel(DACDriver *dacp, + dacchannel_t channel, + dacsample_t sample); + void dac_lld_start_conversion(DACDriver *dacp); + void dac_lld_stop_conversion(DACDriver *dacp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_DAC */ + +#endif /* HAL_DAC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/driver.mk new file mode 100644 index 0000000..6080cec --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/notes.txt new file mode 100644 index 0000000..dc46638 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/notes.txt @@ -0,0 +1,26 @@ +STM32 DMAv1 driver. + +Driver capability: + +- The driver supports the STM32 traditional DMA controller in the following + configurations: 5ch, 7ch, 7ch+5ch, 7ch+7ch. +- Support for automatic the channel selection through the CSELR register. +- For devices without CSELR register it is possible to select channels but + the SYSCFG CFGR register is not configured, the user has to configure it + before starting the DMA driver. +- The driver supports shared ISR handlers with a quirk: the IRQ priority is + established by the first allocated channel among the channels sharing the + ISR. + +The file registry must export: + +STM32_ADVANCED_DMA - TRUE not used by the DMA drivers but other + drivers use it to enable checks on DMA + channels. Probably will be removed in the + future. +STM32_DMA_SUPPORTS_CSELR - TRUE if the DMA have a CSELR register. +STM32_DMA_SUPPORTS_DMAMUX - TRUE if the DMA is riven by a DMAMUX. +STM32_DMAn_NUM_CHANNELS - Number of channels in DMAs "n" (1..2). +STM32_DMAn_CHx_HANDLER - Vector name for IRQ "x" (1..7). If the macro + is not exported then the ISR is not declared. +STM32_DMAn_CHx_NUMBER - Vector number for IRQ "x" (1..7). diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c new file mode 100644 index 0000000..141b4ff --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c @@ -0,0 +1,816 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DMAv1/stm32_dma.c + * @brief DMA helper driver code. + * + * @addtogroup STM32_DMA + * @details DMA sharing helper driver. In the STM32 the DMA streams are a + * shared resource, this driver allows to allocate and free DMA + * streams at runtime in order to allow all the other device + * drivers to coordinate the access to the resource. + * @note The DMA ISR handlers are all declared into this module because + * sharing, the various device drivers can associate a callback to + * ISRs when allocating streams. + * @{ + */ + +#include "hal.h" + +/* The following macro is only defined if some driver requiring DMA services + has been enabled.*/ +#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/** + * @brief Mask of the DMA1 streams in @p dma_streams_mask. + */ +#define STM32_DMA1_STREAMS_MASK ((1U << STM32_DMA1_NUM_CHANNELS) - 1U) + +/** + * @brief Mask of the DMA2 streams in @p dma_streams_mask. + */ +#define STM32_DMA2_STREAMS_MASK (((1U << STM32_DMA2_NUM_CHANNELS) - \ + 1U) << STM32_DMA1_NUM_CHANNELS) + +#if STM32_DMA_SUPPORTS_CSELR == TRUE + +#if defined(DMA1_CSELR) +#define __DMA1_CSELR &DMA1_CSELR->CSELR +#else +#define __DMA1_CSELR &DMA1->CSELR +#endif + +#if defined(DMA2_CSELR) +#define __DMA2_CSELR &DMA2_CSELR->CSELR +#else +#define __DMA2_CSELR &DMA2->CSELR +#endif + +#define DMA1_CH1_VARIANT __DMA1_CSELR +#define DMA1_CH2_VARIANT __DMA1_CSELR +#define DMA1_CH3_VARIANT __DMA1_CSELR +#define DMA1_CH4_VARIANT __DMA1_CSELR +#define DMA1_CH5_VARIANT __DMA1_CSELR +#define DMA1_CH6_VARIANT __DMA1_CSELR +#define DMA1_CH7_VARIANT __DMA1_CSELR +#define DMA1_CH8_VARIANT __DMA1_CSELR +#define DMA2_CH1_VARIANT __DMA2_CSELR +#define DMA2_CH2_VARIANT __DMA2_CSELR +#define DMA2_CH3_VARIANT __DMA2_CSELR +#define DMA2_CH4_VARIANT __DMA2_CSELR +#define DMA2_CH5_VARIANT __DMA2_CSELR +#define DMA2_CH6_VARIANT __DMA2_CSELR +#define DMA2_CH7_VARIANT __DMA2_CSELR +#define DMA2_CH8_VARIANT __DMA2_CSELR + +#elif STM32_DMA_SUPPORTS_DMAMUX == TRUE + +#define DMAMUX1_CHANNEL(id) (DMAMUX1_BASE + ((id) * 4U)) + +#define DMA1_CH1_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(0)) +#define DMA1_CH2_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(1)) +#define DMA1_CH3_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(2)) +#define DMA1_CH4_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(3)) +#define DMA1_CH5_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(4)) +#define DMA1_CH6_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(5)) +#define DMA1_CH7_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(6)) +#define DMA1_CH8_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(7)) +#define DMA2_CH1_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(8)) +#define DMA2_CH2_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(9)) +#define DMA2_CH3_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(10)) +#define DMA2_CH4_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(11)) +#define DMA2_CH5_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(12)) +#define DMA2_CH6_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(13)) +#define DMA2_CH7_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(14)) +#define DMA2_CH8_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(15)) + +#else /* !(STM32_DMA_SUPPORTS_DMAMUX == TRUE) */ + +#define DMA1_CH1_VARIANT 0 +#define DMA1_CH2_VARIANT 0 +#define DMA1_CH3_VARIANT 0 +#define DMA1_CH4_VARIANT 0 +#define DMA1_CH5_VARIANT 0 +#define DMA1_CH6_VARIANT 0 +#define DMA1_CH7_VARIANT 0 +#define DMA2_CH1_VARIANT 0 +#define DMA2_CH2_VARIANT 0 +#define DMA2_CH3_VARIANT 0 +#define DMA2_CH4_VARIANT 0 +#define DMA2_CH5_VARIANT 0 +#define DMA2_CH6_VARIANT 0 +#define DMA2_CH7_VARIANT 0 + +#endif /* !(STM32_DMA_SUPPORTS_DMAMUX == TRUE) */ + +/* + * Default ISR collision masks. + */ +#if !defined(STM32_DMA1_CH1_CMASK) +#define STM32_DMA1_CH1_CMASK (1U << 0U) +#endif + +#if !defined(STM32_DMA1_CH2_CMASK) +#define STM32_DMA1_CH2_CMASK (1U << 1U) +#endif + +#if !defined(STM32_DMA1_CH3_CMASK) +#define STM32_DMA1_CH3_CMASK (1U << 2U) +#endif + +#if !defined(STM32_DMA1_CH4_CMASK) +#define STM32_DMA1_CH4_CMASK (1U << 3U) +#endif + +#if !defined(STM32_DMA1_CH5_CMASK) +#define STM32_DMA1_CH5_CMASK (1U << 4U) +#endif + +#if !defined(STM32_DMA1_CH6_CMASK) +#define STM32_DMA1_CH6_CMASK (1U << 5U) +#endif + +#if !defined(STM32_DMA1_CH7_CMASK) +#define STM32_DMA1_CH7_CMASK (1U << 6U) +#endif + +#if !defined(STM32_DMA1_CH8_CMASK) +#define STM32_DMA1_CH8_CMASK (1U << 7U) +#endif + +#if !defined(STM32_DMA2_CH1_CMASK) +#define STM32_DMA2_CH1_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 0U)) +#endif + +#if !defined(STM32_DMA2_CH2_CMASK) +#define STM32_DMA2_CH2_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 1U)) +#endif + +#if !defined(STM32_DMA2_CH3_CMASK) +#define STM32_DMA2_CH3_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 2U)) +#endif + +#if !defined(STM32_DMA2_CH4_CMASK) +#define STM32_DMA2_CH4_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 3U)) +#endif + +#if !defined(STM32_DMA2_CH5_CMASK) +#define STM32_DMA2_CH5_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 4U)) +#endif + +#if !defined(STM32_DMA2_CH6_CMASK) +#define STM32_DMA2_CH6_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 5U)) +#endif + +#if !defined(STM32_DMA2_CH7_CMASK) +#define STM32_DMA2_CH7_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 6U)) +#endif + +#if !defined(STM32_DMA2_CH8_CMASK) +#define STM32_DMA2_CH8_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 7U)) +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief DMA streams descriptors. + * @details This table keeps the association between an unique stream + * identifier and the involved physical registers. + * @note Don't use this array directly, use the appropriate wrapper macros + * instead: @p STM32_DMA1_STREAM1, @p STM32_DMA1_STREAM2 etc. + */ +const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = { +#if STM32_DMA1_NUM_CHANNELS > 0 + {DMA1, DMA1_Channel1, STM32_DMA1_CH1_CMASK, DMA1_CH1_VARIANT, 0, 0, STM32_DMA1_CH1_NUMBER}, +#endif +#if STM32_DMA1_NUM_CHANNELS > 1 + {DMA1, DMA1_Channel2, STM32_DMA1_CH2_CMASK, DMA1_CH2_VARIANT, 4, 1, STM32_DMA1_CH2_NUMBER}, +#endif +#if STM32_DMA1_NUM_CHANNELS > 2 + {DMA1, DMA1_Channel3, STM32_DMA1_CH3_CMASK, DMA1_CH3_VARIANT, 8, 2, STM32_DMA1_CH3_NUMBER}, +#endif +#if STM32_DMA1_NUM_CHANNELS > 3 + {DMA1, DMA1_Channel4, STM32_DMA1_CH4_CMASK, DMA1_CH4_VARIANT, 12, 3, STM32_DMA1_CH4_NUMBER}, +#endif +#if STM32_DMA1_NUM_CHANNELS > 4 + {DMA1, DMA1_Channel5, STM32_DMA1_CH5_CMASK, DMA1_CH5_VARIANT, 16, 4, STM32_DMA1_CH5_NUMBER}, +#endif +#if STM32_DMA1_NUM_CHANNELS > 5 + {DMA1, DMA1_Channel6, STM32_DMA1_CH6_CMASK, DMA1_CH6_VARIANT, 20, 5, STM32_DMA1_CH6_NUMBER}, +#endif +#if STM32_DMA1_NUM_CHANNELS > 6 + {DMA1, DMA1_Channel7, STM32_DMA1_CH7_CMASK, DMA1_CH7_VARIANT, 24, 6, STM32_DMA1_CH7_NUMBER}, +#endif +#if STM32_DMA1_NUM_CHANNELS > 7 + {DMA1, DMA1_Channel8, STM32_DMA1_CH8_CMASK, DMA1_CH8_VARIANT, 28, 7, STM32_DMA1_CH8_NUMBER}, +#endif +#if STM32_DMA2_NUM_CHANNELS > 0 + {DMA2, DMA2_Channel1, STM32_DMA2_CH1_CMASK, DMA2_CH1_VARIANT, 0, 0 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH1_NUMBER}, +#endif +#if STM32_DMA2_NUM_CHANNELS > 1 + {DMA2, DMA2_Channel2, STM32_DMA2_CH2_CMASK, DMA2_CH2_VARIANT, 4, 1 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH2_NUMBER}, +#endif +#if STM32_DMA2_NUM_CHANNELS > 2 + {DMA2, DMA2_Channel3, STM32_DMA2_CH3_CMASK, DMA2_CH3_VARIANT, 8, 2 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH3_NUMBER}, +#endif +#if STM32_DMA2_NUM_CHANNELS > 3 + {DMA2, DMA2_Channel4, STM32_DMA2_CH4_CMASK, DMA2_CH4_VARIANT, 12, 3 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH4_NUMBER}, +#endif +#if STM32_DMA2_NUM_CHANNELS > 4 + {DMA2, DMA2_Channel5, STM32_DMA2_CH5_CMASK, DMA2_CH5_VARIANT, 16, 4 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH5_NUMBER}, +#endif +#if STM32_DMA2_NUM_CHANNELS > 5 + {DMA2, DMA2_Channel6, STM32_DMA2_CH6_CMASK, DMA2_CH6_VARIANT, 20, 5 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH6_NUMBER}, +#endif +#if STM32_DMA2_NUM_CHANNELS > 6 + {DMA2, DMA2_Channel7, STM32_DMA2_CH7_CMASK, DMA2_CH7_VARIANT, 24, 6 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH7_NUMBER}, +#endif +#if STM32_DMA2_NUM_CHANNELS > 7 + {DMA2, DMA2_Channel8, STM32_DMA2_CH8_CMASK, DMA2_CH8_VARIANT, 28, 7 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH8_NUMBER}, +#endif +}; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Global DMA-related data structures. + */ +static struct { + /** + * @brief Mask of the allocated streams. + */ + uint32_t allocated_mask; + /** + * @brief Mask of the enabled streams ISRs. + */ + uint32_t isr_mask; + /** + * @brief DMA IRQ redirectors. + */ + struct { + /** + * @brief DMA callback function. + */ + stm32_dmaisr_t func; + /** + * @brief DMA callback parameter. + */ + void *param; + } streams[STM32_DMA_STREAMS]; +} dma; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_DMA1_CH1_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA1 stream 1 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA1_STREAM1); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA1_CH2_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA1 stream 2 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA1_STREAM2); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA1_CH3_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA1 stream 3 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA1_STREAM3); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA1_CH4_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA1 stream 4 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA1_STREAM4); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA1_CH5_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA1 stream 5 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA1_STREAM5); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA1_CH6_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA1 stream 6 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA1_STREAM6); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA1_CH7_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA1 stream 7 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA1_STREAM7); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA1_CH8_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA1 stream 8 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH8_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA1_STREAM8); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA2_CH1_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA2 stream 1 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA2_STREAM1); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA2_CH2_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA2 stream 2 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA2_STREAM2); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA2_CH3_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA2 stream 3 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA2_STREAM3); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA2_CH4_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA2 stream 4 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA2_STREAM4); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA2_CH5_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA2 stream 5 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA2_STREAM5); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA2_CH6_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA2 stream 6 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA2_STREAM6); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA2_CH7_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA2 stream 7 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA2_STREAM7); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_DMA2_CH8_HANDLER) || defined(__DOXYGEN__) +/** + * @brief DMA2 stream 8 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH8_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + dmaServeInterrupt(STM32_DMA2_STREAM8); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief STM32 DMA helper initialization. + * + * @init + */ +void dmaInit(void) { + int i; + + dma.allocated_mask = 0U; + dma.isr_mask = 0U; + for (i = 0; i < STM32_DMA_STREAMS; i++) { + _stm32_dma_streams[i].channel->CCR = STM32_DMA_CCR_RESET_VALUE; + dma.streams[i].func = NULL; + } + DMA1->IFCR = 0xFFFFFFFFU; +#if STM32_DMA2_NUM_CHANNELS > 0 + DMA2->IFCR = 0xFFFFFFFFU; +#endif +} + +/** + * @brief Allocates a DMA stream. + * @details The stream is allocated and, if required, the DMA clock enabled. + * The function also enables the IRQ vector associated to the stream + * and initializes its priority. + * + * @param[in] id numeric identifiers of a specific stream or: + * - @p STM32_DMA_STREAM_ID_ANY for any stream. + * - @p STM32_DMA_STREAM_ID_ANY_DMA1 for any stream + * on DMA1. + * - @p STM32_DMA_STREAM_ID_ANY_DMA2 for any stream + * on DMA2. + * . + * @param[in] priority IRQ priority for the DMA stream + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return Pointer to the allocated @p stm32_dma_stream_t + * structure. + * @retval NULL if a/the stream is not available. + * + * @iclass + */ +const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id, + uint32_t priority, + stm32_dmaisr_t func, + void *param) { + uint32_t i, startid, endid; + + osalDbgCheckClassI(); + + if (id < STM32_DMA_STREAMS) { + startid = id; + endid = id; + } +#if STM32_DMA_SUPPORTS_DMAMUX == TRUE + else if (id == STM32_DMA_STREAM_ID_ANY) { + startid = 0U; + endid = STM32_DMA_STREAMS - 1U; + } + else if (id == STM32_DMA_STREAM_ID_ANY_DMA1) { + startid = 0U; + endid = STM32_DMA1_NUM_CHANNELS - 1U; + } +#if STM32_DMA2_NUM_CHANNELS > 0 + else if (id == STM32_DMA_STREAM_ID_ANY_DMA2) { + startid = STM32_DMA1_NUM_CHANNELS; + endid = STM32_DMA_STREAMS - 1U; + } +#endif +#endif + else { + osalDbgCheck(false); + return NULL; + } + + for (i = startid; i <= endid; i++) { + uint32_t mask = (1U << i); + if ((dma.allocated_mask & mask) == 0U) { + const stm32_dma_stream_t *dmastp = STM32_DMA_STREAM(i); + + /* Installs the DMA handler.*/ + dma.streams[i].func = func; + dma.streams[i].param = param; + dma.allocated_mask |= mask; + + /* Enabling DMA clocks required by the current streams set.*/ + if ((STM32_DMA1_STREAMS_MASK & mask) != 0U) { + rccEnableDMA1(true); + } +#if STM32_DMA2_NUM_CHANNELS > 0 + if ((STM32_DMA2_STREAMS_MASK & mask) != 0U) { + rccEnableDMA2(true); + } +#endif + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && defined(rccEnableDMAMUX) + /* Enabling DMAMUX if present.*/ + if (dma.allocated_mask != 0U) { + rccEnableDMAMUX(true); + } +#endif + + /* Enables the associated IRQ vector if not already enabled and if a + callback is defined.*/ + if (func != NULL) { + if ((dma.isr_mask & dmastp->cmask) == 0U) { + nvicEnableVector(dmastp->vector, priority); + } + dma.isr_mask |= mask; + } + + /* Putting the stream in a known state.*/ + dmaStreamDisable(dmastp); + dmastp->channel->CCR = STM32_DMA_CCR_RESET_VALUE; + + return dmastp; + } + } + + return NULL; +} + +/** + * @brief Allocates a DMA stream. + * @details The stream is allocated and, if required, the DMA clock enabled. + * The function also enables the IRQ vector associated to the stream + * and initializes its priority. + * + * @param[in] id numeric identifiers of a specific stream or: + * - @p STM32_DMA_STREAM_ID_ANY for any stream. + * - @p STM32_DMA_STREAM_ID_ANY_DMA1 for any stream + * on DMA1. + * - @p STM32_DMA_STREAM_ID_ANY_DMA2 for any stream + * on DMA2. + * . + * @param[in] priority IRQ priority for the DMA stream + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return Pointer to the allocated @p stm32_dma_stream_t + * structure. + * @retval NULL if a/the stream is not available. + * + * @api + */ +const stm32_dma_stream_t *dmaStreamAlloc(uint32_t id, + uint32_t priority, + stm32_dmaisr_t func, + void *param) { + const stm32_dma_stream_t *dmastp; + + osalSysLock(); + dmastp = dmaStreamAllocI(id, priority, func, param); + osalSysUnlock(); + + return dmastp; +} + +/** + * @brief Releases a DMA stream. + * @details The stream is freed and, if required, the DMA clock disabled. + * Trying to release a unallocated stream is an illegal operation + * and is trapped if assertions are enabled. + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @iclass + */ +void dmaStreamFreeI(const stm32_dma_stream_t *dmastp) { + uint32_t selfindex = (uint32_t)dmastp->selfindex; + + osalDbgCheck(dmastp != NULL); + + /* Check if the streams is not taken.*/ + osalDbgAssert((dma.allocated_mask & (1 << selfindex)) != 0U, + "not allocated"); + + /* Marks the stream as not allocated.*/ + dma.allocated_mask &= ~(1U << selfindex); + dma.isr_mask &= ~(1U << selfindex); + + /* Disables the associated IRQ vector if it is no more in use.*/ + if ((dma.isr_mask & dmastp->cmask) == 0U) { + nvicDisableVector(dmastp->vector); + } + + /* Removes the DMA handler.*/ + dma.streams[selfindex].func = NULL; + dma.streams[selfindex].param = NULL; + + /* Shutting down clocks that are no more required, if any.*/ + if ((dma.allocated_mask & STM32_DMA1_STREAMS_MASK) == 0U) { + rccDisableDMA1(); + } +#if STM32_DMA2_NUM_CHANNELS > 0 + if ((dma.allocated_mask & STM32_DMA2_STREAMS_MASK) == 0U) { + rccDisableDMA2(); + } +#endif + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && defined(rccDisableDMAMUX) + /* Shutting down DMAMUX if present.*/ + if (dma.allocated_mask == 0U) { + rccDisableDMAMUX(); + } +#endif +} + +/** + * @brief Releases a DMA stream. + * @details The stream is freed and, if required, the DMA clock disabled. + * Trying to release a unallocated stream is an illegal operation + * and is trapped if assertions are enabled. + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @api + */ +void dmaStreamFree(const stm32_dma_stream_t *dmastp) { + + osalSysLock(); + dmaStreamFreeI(dmastp); + osalSysUnlock(); +} + +/** + * @brief Serves a DMA IRQ. + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +void dmaServeInterrupt(const stm32_dma_stream_t *dmastp) { + uint32_t flags; + uint32_t selfindex = (uint32_t)dmastp->selfindex; + + flags = (dmastp->dma->ISR >> dmastp->shift) & STM32_DMA_ISR_MASK; + if (flags & dmastp->channel->CCR) { + dmastp->dma->IFCR = flags << dmastp->shift; + if (dma.streams[selfindex].func) { + dma.streams[selfindex].func(dma.streams[selfindex].param, flags); + } + } +} + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__) +/** + * @brief Associates a peripheral request to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * + * @param[in] dmastp pointer to a @p stm32_dma_stream_t structure + * @param[in] per peripheral identifier + * + * @special + */ +void dmaSetRequestSource(const stm32_dma_stream_t *dmastp, uint32_t per) { + + osalDbgCheck(per < 256U); + + dmastp->mux->CCR = per; +} +#endif + +#endif /* STM32_DMA_REQUIRED */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h new file mode 100644 index 0000000..54b6bde --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h @@ -0,0 +1,554 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DMAv1/stm32_dma.h + * @brief DMA helper driver header. + * @note This driver uses the new naming convention used for the STM32F2xx + * so the "DMA channels" are referred as "DMA streams". + * + * @addtogroup STM32_DMA + * @{ + */ + +#ifndef STM32_DMA_H +#define STM32_DMA_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief DMA capability. + * @details if @p TRUE then the DMA is able of burst transfers, FIFOs, + * scatter gather and other advanced features. + */ +#define STM32_DMA_ADVANCED FALSE + +/** + * @brief Total number of DMA streams. + * @details This is the total number of streams among all the DMA units. + */ +#define STM32_DMA_STREAMS (STM32_DMA1_NUM_CHANNELS + \ + STM32_DMA2_NUM_CHANNELS) + +/** + * @brief Mask of the ISR bits passed to the DMA callback functions. + */ +#define STM32_DMA_ISR_MASK 0x0E + +/** + * @brief Returns the request line associated to the specified stream. + * @note In some STM32 manuals the request line is named confusingly + * channel. + * + * @param[in] id the unique numeric stream identifier + * @param[in] c a stream/request association word, one request per + * nibble + * @return Returns the request associated to the stream. + */ +#define STM32_DMA_GETCHANNEL(id, c) \ + (((uint32_t)(c) >> (((uint32_t)(id) % (uint32_t)STM32_DMA1_NUM_CHANNELS) * 4U)) & 15U) + +/** + * @brief Checks if a DMA priority is within the valid range. + * @param[in] prio DMA priority + * + * @retval The check result. + * @retval false invalid DMA priority. + * @retval true correct DMA priority. + */ +#define STM32_DMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U)) + +#if (STM32_DMA_SUPPORTS_DMAMUX == FALSE) || defined(_DOXYGEN__) +/** + * @brief Checks if a DMA stream id is within the valid range. + * + * @param[in] id DMA stream id + * @retval The check result. + * @retval false invalid DMA channel. + * @retval true correct DMA channel. + */ +#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \ + ((id) < STM32_DMA_STREAMS)) +#else /* STM32_DMA_SUPPORTS_DMAMUX == FALSE */ +#if STM32_DMA2_NUM_CHANNELS > 0 +#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \ + ((id) <= (STM32_DMA_STREAMS + 2))) +#else +#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \ + ((id) <= (STM32_DMA_STREAMS + 1))) +#endif +#endif /* STM32_DMA_SUPPORTS_DMAMUX == FALSE */ + +/** + * @brief Returns an unique numeric identifier for a DMA stream. + * + * @param[in] dma the DMA unit number + * @param[in] stream the stream number + * @return An unique numeric stream identifier. + */ +#define STM32_DMA_STREAM_ID(dma, stream) \ + ((((dma) - 1) * STM32_DMA1_NUM_CHANNELS) + ((stream) - 1)) + +/** + * @brief Returns a DMA stream identifier mask. + * + * + * @param[in] dma the DMA unit number + * @param[in] stream the stream number + * @return A DMA stream identifier mask. + */ +#define STM32_DMA_STREAM_ID_MSK(dma, stream) \ + (1U << STM32_DMA_STREAM_ID(dma, stream)) + +/** + * @brief Checks if a DMA stream unique identifier belongs to a mask. + * + * @param[in] id the stream numeric identifier + * @param[in] mask the stream numeric identifiers mask + * + * @retval The check result. + * @retval false id does not belong to the mask. + * @retval true id belongs to the mask. + */ +#define STM32_DMA_IS_VALID_ID(id, mask) (((1U << (id)) & (mask))) + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(_DOXYGEN__) +/** + * @name Special stream identifiers + * @{ + */ +#define STM32_DMA_STREAM_ID_ANY STM32_DMA_STREAMS +#define STM32_DMA_STREAM_ID_ANY_DMA1 (STM32_DMA_STREAM_ID_ANY + 1) +#if STM32_DMA2_NUM_CHANNELS > 0 +#define STM32_DMA_STREAM_ID_ANY_DMA2 (STM32_DMA_STREAM_ID_ANY_DMA1 + 1) +#endif +/** @} */ +#endif + +/** + * @name DMA streams identifiers + * @{ + */ +/** + * @brief Returns a pointer to a stm32_dma_stream_t structure. + * + * @param[in] id the stream numeric identifier + * @return A pointer to the stm32_dma_stream_t constant structure + * associated to the DMA stream. + */ +#define STM32_DMA_STREAM(id) (&_stm32_dma_streams[id]) + +#if STM32_DMA1_NUM_CHANNELS > 0 +#define STM32_DMA1_STREAM1 STM32_DMA_STREAM(0) +#endif +#if STM32_DMA1_NUM_CHANNELS > 1 +#define STM32_DMA1_STREAM2 STM32_DMA_STREAM(1) +#endif +#if STM32_DMA1_NUM_CHANNELS > 2 +#define STM32_DMA1_STREAM3 STM32_DMA_STREAM(2) +#endif +#if STM32_DMA1_NUM_CHANNELS > 3 +#define STM32_DMA1_STREAM4 STM32_DMA_STREAM(3) +#endif +#if STM32_DMA1_NUM_CHANNELS > 4 +#define STM32_DMA1_STREAM5 STM32_DMA_STREAM(4) +#endif +#if STM32_DMA1_NUM_CHANNELS > 5 +#define STM32_DMA1_STREAM6 STM32_DMA_STREAM(5) +#endif +#if STM32_DMA1_NUM_CHANNELS > 6 +#define STM32_DMA1_STREAM7 STM32_DMA_STREAM(6) +#endif +#if STM32_DMA1_NUM_CHANNELS > 7 +#define STM32_DMA1_STREAM8 STM32_DMA_STREAM(7) +#endif +#if STM32_DMA2_NUM_CHANNELS > 0 +#define STM32_DMA2_STREAM1 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 0) +#endif +#if STM32_DMA2_NUM_CHANNELS > 1 +#define STM32_DMA2_STREAM2 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 1) +#endif +#if STM32_DMA2_NUM_CHANNELS > 2 +#define STM32_DMA2_STREAM3 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 2) +#endif +#if STM32_DMA2_NUM_CHANNELS > 3 +#define STM32_DMA2_STREAM4 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 3) +#endif +#if STM32_DMA2_NUM_CHANNELS > 4 +#define STM32_DMA2_STREAM5 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 4) +#endif +#if STM32_DMA2_NUM_CHANNELS > 5 +#define STM32_DMA2_STREAM6 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 5) +#endif +#if STM32_DMA2_NUM_CHANNELS > 6 +#define STM32_DMA2_STREAM7 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 6) +#endif +#if STM32_DMA2_NUM_CHANNELS > 7 +#define STM32_DMA2_STREAM8 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 7) +#endif +/** @} */ + +/** + * @name CR register constants common to all DMA types + * @{ + */ +#define STM32_DMA_CCR_RESET_VALUE 0x00000000U +#define STM32_DMA_CR_EN DMA_CCR_EN +#define STM32_DMA_CR_TEIE DMA_CCR_TEIE +#define STM32_DMA_CR_HTIE DMA_CCR_HTIE +#define STM32_DMA_CR_TCIE DMA_CCR_TCIE +#define STM32_DMA_CR_DIR_MASK (DMA_CCR_DIR | DMA_CCR_MEM2MEM) +#define STM32_DMA_CR_DIR_P2M 0U +#define STM32_DMA_CR_DIR_M2P DMA_CCR_DIR +#define STM32_DMA_CR_DIR_M2M DMA_CCR_MEM2MEM +#define STM32_DMA_CR_CIRC DMA_CCR_CIRC +#define STM32_DMA_CR_PINC DMA_CCR_PINC +#define STM32_DMA_CR_MINC DMA_CCR_MINC +#define STM32_DMA_CR_PSIZE_MASK DMA_CCR_PSIZE +#define STM32_DMA_CR_PSIZE_BYTE 0U +#define STM32_DMA_CR_PSIZE_HWORD DMA_CCR_PSIZE_0 +#define STM32_DMA_CR_PSIZE_WORD DMA_CCR_PSIZE_1 +#define STM32_DMA_CR_MSIZE_MASK DMA_CCR_MSIZE +#define STM32_DMA_CR_MSIZE_BYTE 0U +#define STM32_DMA_CR_MSIZE_HWORD DMA_CCR_MSIZE_0 +#define STM32_DMA_CR_MSIZE_WORD DMA_CCR_MSIZE_1 +#define STM32_DMA_CR_SIZE_MASK (STM32_DMA_CR_PSIZE_MASK | \ + STM32_DMA_CR_MSIZE_MASK) +#define STM32_DMA_CR_PL_MASK DMA_CCR_PL +#define STM32_DMA_CR_PL(n) ((n) << 12U) +/** @} */ + +/** + * @name Request line selector macro + * @{ + */ +#if STM32_DMA_SUPPORTS_CSELR || defined(__DOXYGEN__) +#define STM32_DMA_CR_CHSEL_MASK (15U << 16U) +#define STM32_DMA_CR_CHSEL(n) ((n) << 16U) +#else +#define STM32_DMA_CR_CHSEL_MASK 0U +#define STM32_DMA_CR_CHSEL(n) 0U +#endif +/** @} */ + +/** + * @name CR register constants only found in enhanced DMA + * @{ + */ +#define STM32_DMA_CR_DMEIE 0U /**< @brief Ignored by normal DMA. */ +/** @} */ + +/** + * @name Status flags passed to the ISR callbacks + * @{ + */ +#define STM32_DMA_ISR_FEIF 0U +#define STM32_DMA_ISR_DMEIF 0U +#define STM32_DMA_ISR_TEIF DMA_ISR_TEIF1 +#define STM32_DMA_ISR_HTIF DMA_ISR_HTIF1 +#define STM32_DMA_ISR_TCIF DMA_ISR_TCIF1 +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_DMA_SUPPORTS_DMAMUX) +#error "STM32_DMA_SUPPORTS_DMAMUX not defined in registry" +#endif + +#if !defined(STM32_DMA_SUPPORTS_CSELR) +#error "STM32_DMA_SUPPORTS_CSELR not defined in registry" +#endif + +#if STM32_DMA_SUPPORTS_DMAMUX && STM32_DMA_SUPPORTS_CSELR +#error "STM32_DMA_SUPPORTS_DMAMUX and STM32_DMA_SUPPORTS_CSELR both TRUE" +#endif + +#if !defined(STM32_DMA1_NUM_CHANNELS) +#error "STM32_DMA1_NUM_CHANNELS not defined in registry" +#endif + +#if !defined(STM32_DMA2_NUM_CHANNELS) +#error "STM32_DMA2_NUM_CHANNELS not defined in registry" +#endif + +#if (STM32_DMA1_NUM_CHANNELS < 0) || (STM32_DMA1_NUM_CHANNELS > 8) +#error "unsupported channels configuration" +#endif + +#if (STM32_DMA2_NUM_CHANNELS < 0) || (STM32_DMA2_NUM_CHANNELS > 8) +#error "unsupported channels configuration" +#endif + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__) +#include "stm32_dmamux.h" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a DMA callback. + * + * @param[in] p parameter for the registered function + * @param[in] flags pre-shifted content of the ISR register, the bits + * are aligned to bit zero + */ +typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags); + +/** + * @brief STM32 DMA stream descriptor structure. + */ +typedef struct { + DMA_TypeDef *dma; /**< @brief Associated DMA. */ + DMA_Channel_TypeDef *channel; /**< @brief Associated DMA channel. */ + uint32_t cmask; /**< @brief Mask of streams sharing + the same ISR. */ +#if (STM32_DMA_SUPPORTS_CSELR == TRUE) || defined(__DOXYGEN__) + volatile uint32_t *cselr; /**< @brief Associated CSELR reg. */ +#elif STM32_DMA_SUPPORTS_DMAMUX == TRUE + DMAMUX_Channel_TypeDef *mux; /**< @brief Associated DMA mux. */ +#else + uint8_t dummy; /**< @brief Filler. */ +#endif + uint8_t shift; /**< @brief Bit offset in ISR, IFCR + and CSELR registers. */ + uint8_t selfindex; /**< @brief Index to self in array. */ + uint8_t vector; /**< @brief Associated IRQ vector. */ +} stm32_dma_stream_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Associates a peripheral data register to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the CPAR register + * + * @special + */ +#define dmaStreamSetPeripheral(dmastp, addr) { \ + (dmastp)->channel->CPAR = (uint32_t)(addr); \ +} + +/** + * @brief Associates a memory destination to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the CMAR register + * + * @special + */ +#define dmaStreamSetMemory0(dmastp, addr) { \ + (dmastp)->channel->CMAR = (uint32_t)(addr); \ +} + +/** + * @brief Sets the number of transfers to be performed. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] size value to be written in the CNDTR register + * + * @special + */ +#define dmaStreamSetTransactionSize(dmastp, size) { \ + (dmastp)->channel->CNDTR = (uint32_t)(size); \ +} + +/** + * @brief Returns the number of transfers to be performed. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @return The number of transfers to be performed. + * + * @special + */ +#define dmaStreamGetTransactionSize(dmastp) ((size_t)((dmastp)->channel->CNDTR)) + +/** + * @brief Programs the stream mode settings. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] mode value to be written in the CCR register + * + * @special + */ +#if STM32_DMA_SUPPORTS_CSELR || defined(__DOXYGEN__) +#define dmaStreamSetMode(dmastp, mode) { \ + uint32_t cselr = *(dmastp)->cselr; \ + cselr &= ~(0x0000000FU << (dmastp)->shift); \ + cselr |= (((uint32_t)(mode) >> 16U) << (dmastp)->shift); \ + *(dmastp)->cselr = cselr; \ + (dmastp)->channel->CCR = (uint32_t)(mode); \ +} +#else +#define dmaStreamSetMode(dmastp, mode) { \ + (dmastp)->channel->CCR = (uint32_t)(mode); \ +} +#endif + +/** + * @brief DMA stream enable. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +#define dmaStreamEnable(dmastp) { \ + (dmastp)->channel->CCR |= STM32_DMA_CR_EN; \ +} + +/** + * @brief DMA stream disable. + * @details The function disables the specified stream and then clears any + * pending interrupt. + * @note This function can be invoked in both ISR or thread context. + * @note Interrupts enabling flags are set to zero after this call, see + * bug 3607518. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +#define dmaStreamDisable(dmastp) { \ + (dmastp)->channel->CCR &= ~(STM32_DMA_CR_TCIE | STM32_DMA_CR_HTIE | \ + STM32_DMA_CR_TEIE | STM32_DMA_CR_EN); \ + dmaStreamClearInterrupt(dmastp); \ +} + +/** + * @brief DMA stream interrupt sources clear. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +#define dmaStreamClearInterrupt(dmastp) { \ + (dmastp)->dma->IFCR = STM32_DMA_ISR_MASK << (dmastp)->shift; \ +} + +/** + * @brief Starts a memory to memory operation using the specified stream. + * @note The default transfer data mode is "byte to byte" but it can be + * changed by specifying extra options in the @p mode parameter. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] mode value to be written in the CCR register, this value + * is implicitly ORed with: + * - @p STM32_DMA_CR_MINC + * - @p STM32_DMA_CR_PINC + * - @p STM32_DMA_CR_DIR_M2M + * - @p STM32_DMA_CR_EN + * . + * @param[in] src source address + * @param[in] dst destination address + * @param[in] n number of data units to copy + */ +#define dmaStartMemCopy(dmastp, mode, src, dst, n) { \ + dmaStreamSetPeripheral(dmastp, src); \ + dmaStreamSetMemory0(dmastp, dst); \ + dmaStreamSetTransactionSize(dmastp, n); \ + dmaStreamSetMode(dmastp, (mode) | \ + STM32_DMA_CR_MINC | STM32_DMA_CR_PINC | \ + STM32_DMA_CR_DIR_M2M | STM32_DMA_CR_EN); \ +} + +/** + * @brief Polled wait for DMA transfer end. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + */ +#define dmaWaitCompletion(dmastp) { \ + while ((dmastp)->channel->CNDTR > 0U) \ + ; \ + dmaStreamDisable(dmastp); \ +} +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS]; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void dmaInit(void); + const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id, + uint32_t priority, + stm32_dmaisr_t func, + void *param); + const stm32_dma_stream_t *dmaStreamAlloc(uint32_t id, + uint32_t priority, + stm32_dmaisr_t func, + void *param); + void dmaStreamFreeI(const stm32_dma_stream_t *dmastp); + void dmaStreamFree(const stm32_dma_stream_t *dmastp); + void dmaServeInterrupt(const stm32_dma_stream_t *dmastp); +#if STM32_DMA_SUPPORTS_DMAMUX == TRUE + void dmaSetRequestSource(const stm32_dma_stream_t *dmastp, uint32_t per); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* STM32_DMA_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch23.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch23.inc new file mode 100644 index 0000000..c67f5b4 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch23.inc @@ -0,0 +1,78 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DMAv1/stm32_dma1_ch23.inc + * @brief Shared DMA1 Channels 2 and 3 handler. + * + * @addtogroup STM32_DMA1_CH23_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Other checks.*/ +#if !defined(STM32_DMA1_CH23_HANDLER) +#error "STM32_DMA1_CH23_HANDLER not defined in stm32_isr.h" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__) +/** + * @brief DMA1 streams 2 and 3 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH23_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + /* Check on channel 2.*/ + dmaServeInterrupt(STM32_DMA1_STREAM2); + + /* Check on channel 3.*/ + dmaServeInterrupt(STM32_DMA1_STREAM3); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch4567.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch4567.inc new file mode 100644 index 0000000..1de4597 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch4567.inc @@ -0,0 +1,84 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DMAv1/stm32_dma1_ch4567.inc + * @brief Shared DMA1 Channels 4, 5, 6 and 7 handler. + * + * @addtogroup STM32_DMA1_CH4567_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Other checks.*/ +#if !defined(STM32_DMA1_CH4567_HANDLER) +#error "STM32_DMA1_CH4567_HANDLER not defined in stm32_isr.h" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__) +/** + * @brief DMA1 streams 4, 5, 6 and 7 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH4567_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + /* Check on channel 4.*/ + dmaServeInterrupt(STM32_DMA1_STREAM4); + + /* Check on channel 5.*/ + dmaServeInterrupt(STM32_DMA1_STREAM5); + + /* Check on channel 6.*/ + dmaServeInterrupt(STM32_DMA1_STREAM6); + + /* Check on channel 7.*/ + dmaServeInterrupt(STM32_DMA1_STREAM7); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/driver.mk new file mode 100644 index 0000000..bdc468a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv2 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/notes.txt new file mode 100644 index 0000000..4c01d83 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/notes.txt @@ -0,0 +1,18 @@ +STM32 DMAv2 driver. + +Driver capability: + +- The driver supports the STM32 enhanced DMA controller found on F2, F4 and + F7 sub-families. +- Support for automatic the channel selection. +- Support for cache flushing and invalidation. + +The file registry must export: + +STM32_ADVANCED_DMA - TRUE not used by the DMA drivers but other + drivers use it to enable checks on DMA + channels. Probably will be removed in the + future. +STM32_HAS_DMAx - Support for DMA unit "x" (1..2). +STM32_DMAx_CHn_HANDLER - Vector name for channel "n" (0..7). +STM32_DMAn_CHx_NUMBER - Vector number for channel "n" (0..7). diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c new file mode 100644 index 0000000..10b4b68 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c @@ -0,0 +1,675 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DMAv2/stm32_dma.c + * @brief Enhanced DMA helper driver code. + * + * @addtogroup STM32_DMA + * @details DMA sharing helper driver. In the STM32 the DMA streams are a + * shared resource, this driver allows to allocate and free DMA + * streams at runtime in order to allow all the other device + * drivers to coordinate the access to the resource. + * @note The DMA ISR handlers are all declared into this module because + * sharing, the various device drivers can associate a callback to + * ISRs when allocating streams. + * @{ + */ + +#include "hal.h" + +/* The following macro is only defined if some driver requiring DMA services + has been enabled.*/ +#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/** + * @brief Mask of the DMA1 streams in @p dma.allocated_mask. + */ +#define STM32_DMA1_STREAMS_MASK 0x000000FFU + +/** + * @brief Mask of the DMA2 streams in @p dma.allocated_mask. + */ +#define STM32_DMA2_STREAMS_MASK 0x0000FF00U + +#if STM32_DMA_SUPPORTS_DMAMUX == TRUE + +#define DMA1_CH0_VARIANT DMAMUX1_Channel0 +#define DMA1_CH1_VARIANT DMAMUX1_Channel1 +#define DMA1_CH2_VARIANT DMAMUX1_Channel2 +#define DMA1_CH3_VARIANT DMAMUX1_Channel3 +#define DMA1_CH4_VARIANT DMAMUX1_Channel4 +#define DMA1_CH5_VARIANT DMAMUX1_Channel5 +#define DMA1_CH6_VARIANT DMAMUX1_Channel6 +#define DMA1_CH7_VARIANT DMAMUX1_Channel7 +#define DMA2_CH0_VARIANT DMAMUX1_Channel8 +#define DMA2_CH1_VARIANT DMAMUX1_Channel9 +#define DMA2_CH2_VARIANT DMAMUX1_Channel10 +#define DMA2_CH3_VARIANT DMAMUX1_Channel11 +#define DMA2_CH4_VARIANT DMAMUX1_Channel12 +#define DMA2_CH5_VARIANT DMAMUX1_Channel13 +#define DMA2_CH6_VARIANT DMAMUX1_Channel14 +#define DMA2_CH7_VARIANT DMAMUX1_Channel15 + +#else /* !(STM32_DMA_SUPPORTS_DMAMUX == TRUE) */ + +#define DMA1_CH0_VARIANT 0 +#define DMA1_CH1_VARIANT 0 +#define DMA1_CH2_VARIANT 0 +#define DMA1_CH3_VARIANT 0 +#define DMA1_CH4_VARIANT 0 +#define DMA1_CH5_VARIANT 0 +#define DMA1_CH6_VARIANT 0 +#define DMA1_CH7_VARIANT 0 +#define DMA2_CH0_VARIANT 0 +#define DMA2_CH1_VARIANT 0 +#define DMA2_CH2_VARIANT 0 +#define DMA2_CH3_VARIANT 0 +#define DMA2_CH4_VARIANT 0 +#define DMA2_CH5_VARIANT 0 +#define DMA2_CH6_VARIANT 0 +#define DMA2_CH7_VARIANT 0 + +#endif /* !(STM32_DMA_SUPPORTS_DMAMUX == TRUE) */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief DMA streams descriptors. + * @details This table keeps the association between an unique stream + * identifier and the involved physical registers. + * @note Don't use this array directly, use the appropriate wrapper macros + * instead: @p STM32_DMA1_STREAM0, @p STM32_DMA1_STREAM1 etc. + */ +const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = { + {DMA1_Stream0, &DMA1->LIFCR, DMA1_CH0_VARIANT, 0, 0, STM32_DMA1_CH0_NUMBER}, + {DMA1_Stream1, &DMA1->LIFCR, DMA1_CH1_VARIANT, 6, 1, STM32_DMA1_CH1_NUMBER}, + {DMA1_Stream2, &DMA1->LIFCR, DMA1_CH2_VARIANT, 16, 2, STM32_DMA1_CH2_NUMBER}, + {DMA1_Stream3, &DMA1->LIFCR, DMA1_CH3_VARIANT, 22, 3, STM32_DMA1_CH3_NUMBER}, + {DMA1_Stream4, &DMA1->HIFCR, DMA1_CH4_VARIANT, 0, 4, STM32_DMA1_CH4_NUMBER}, + {DMA1_Stream5, &DMA1->HIFCR, DMA1_CH5_VARIANT, 6, 5, STM32_DMA1_CH5_NUMBER}, + {DMA1_Stream6, &DMA1->HIFCR, DMA1_CH6_VARIANT, 16, 6, STM32_DMA1_CH6_NUMBER}, + {DMA1_Stream7, &DMA1->HIFCR, DMA1_CH7_VARIANT, 22, 7, STM32_DMA1_CH7_NUMBER}, + {DMA2_Stream0, &DMA2->LIFCR, DMA2_CH0_VARIANT, 0, 8, STM32_DMA2_CH0_NUMBER}, + {DMA2_Stream1, &DMA2->LIFCR, DMA2_CH1_VARIANT, 6, 9, STM32_DMA2_CH1_NUMBER}, + {DMA2_Stream2, &DMA2->LIFCR, DMA2_CH2_VARIANT, 16, 10, STM32_DMA2_CH2_NUMBER}, + {DMA2_Stream3, &DMA2->LIFCR, DMA2_CH3_VARIANT, 22, 11, STM32_DMA2_CH3_NUMBER}, + {DMA2_Stream4, &DMA2->HIFCR, DMA2_CH4_VARIANT, 0, 12, STM32_DMA2_CH4_NUMBER}, + {DMA2_Stream5, &DMA2->HIFCR, DMA2_CH5_VARIANT, 6, 13, STM32_DMA2_CH5_NUMBER}, + {DMA2_Stream6, &DMA2->HIFCR, DMA2_CH6_VARIANT, 16, 14, STM32_DMA2_CH6_NUMBER}, + {DMA2_Stream7, &DMA2->HIFCR, DMA2_CH7_VARIANT, 22, 15, STM32_DMA2_CH7_NUMBER}, +}; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Global DMA-related data structures. + */ +static struct { + /** + * @brief Mask of the allocated streams. + */ + uint32_t allocated_mask; + /** + * @brief DMA IRQ redirectors. + */ + struct { + /** + * @brief DMA callback function. + */ + stm32_dmaisr_t func; + /** + * @brief DMA callback parameter. + */ + void *param; + } streams[STM32_DMA_STREAMS]; +} dma; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief DMA1 stream 0 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH0_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->LISR >> 0U) & STM32_DMA_ISR_MASK; + DMA1->LIFCR = flags << 0U; + if (dma.streams[0].func) + dma.streams[0].func(dma.streams[0].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 1 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH1_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->LISR >> 6U) & STM32_DMA_ISR_MASK; + DMA1->LIFCR = flags << 6U; + if (dma.streams[1].func) + dma.streams[1].func(dma.streams[1].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 2 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH2_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->LISR >> 16U) & STM32_DMA_ISR_MASK; + DMA1->LIFCR = flags << 16U; + if (dma.streams[2].func) + dma.streams[2].func(dma.streams[2].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 3 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH3_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->LISR >> 22U) & STM32_DMA_ISR_MASK; + DMA1->LIFCR = flags << 22U; + if (dma.streams[3].func) + dma.streams[3].func(dma.streams[3].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 4 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH4_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->HISR >> 0U) & STM32_DMA_ISR_MASK; + DMA1->HIFCR = flags << 0U; + if (dma.streams[4].func) + dma.streams[4].func(dma.streams[4].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 5 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH5_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->HISR >> 6U) & STM32_DMA_ISR_MASK; + DMA1->HIFCR = flags << 6U; + if (dma.streams[5].func) + dma.streams[5].func(dma.streams[5].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 6 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH6_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->HISR >> 16U) & STM32_DMA_ISR_MASK; + DMA1->HIFCR = flags << 16U; + if (dma.streams[6].func) + dma.streams[6].func(dma.streams[6].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 7 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH7_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->HISR >> 22U) & STM32_DMA_ISR_MASK; + DMA1->HIFCR = flags << 22U; + if (dma.streams[7].func) + dma.streams[7].func(dma.streams[7].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 0 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH0_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->LISR >> 0U) & STM32_DMA_ISR_MASK; + DMA2->LIFCR = flags << 0U; + if (dma.streams[8].func) + dma.streams[8].func(dma.streams[8].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 1 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH1_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->LISR >> 6U) & STM32_DMA_ISR_MASK; + DMA2->LIFCR = flags << 6U; + if (dma.streams[9].func) + dma.streams[9].func(dma.streams[9].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 2 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH2_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->LISR >> 16U) & STM32_DMA_ISR_MASK; + DMA2->LIFCR = flags << 16U; + if (dma.streams[10].func) + dma.streams[10].func(dma.streams[10].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 3 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH3_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->LISR >> 22U) & STM32_DMA_ISR_MASK; + DMA2->LIFCR = flags << 22U; + if (dma.streams[11].func) + dma.streams[11].func(dma.streams[11].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 4 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH4_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->HISR >> 0U) & STM32_DMA_ISR_MASK; + DMA2->HIFCR = flags << 0U; + if (dma.streams[12].func) + dma.streams[12].func(dma.streams[12].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 5 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH5_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->HISR >> 6U) & STM32_DMA_ISR_MASK; + DMA2->HIFCR = flags << 6U; + if (dma.streams[13].func) + dma.streams[13].func(dma.streams[13].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 6 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH6_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->HISR >> 16U) & STM32_DMA_ISR_MASK; + DMA2->HIFCR = flags << 16U; + if (dma.streams[14].func) + dma.streams[14].func(dma.streams[14].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 7 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH7_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->HISR >> 22U) & STM32_DMA_ISR_MASK; + DMA2->HIFCR = flags << 22U; + if (dma.streams[15].func) + dma.streams[15].func(dma.streams[15].param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief STM32 DMA helper initialization. + * + * @init + */ +void dmaInit(void) { + unsigned i; + + dma.allocated_mask = 0U; + for (i = 0U; i < STM32_DMA_STREAMS; i++) { + _stm32_dma_streams[i].stream->CR = STM32_DMA_CR_RESET_VALUE; + dma.streams[i].func = NULL; + } + DMA1->LIFCR = 0xFFFFFFFFU; + DMA1->HIFCR = 0xFFFFFFFFU; + DMA2->LIFCR = 0xFFFFFFFFU; + DMA2->HIFCR = 0xFFFFFFFFU; +} + +/** + * @brief Allocates a DMA stream. + * @details The stream is allocated and, if required, the DMA clock enabled. + * The function also enables the IRQ vector associated to the stream + * and initializes its priority. + * + * @param[in] id numeric identifiers of a specific stream or: + * - @p STM32_DMA_STREAM_ID_ANY for any stream. + * - @p STM32_DMA_STREAM_ID_ANY_DMA1 for any stream + * on DMA1. + * - @p STM32_DMA_STREAM_ID_ANY_DMA2 for any stream + * on DMA2. + * . + * @param[in] priority IRQ priority for the DMA stream + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return Pointer to the allocated @p stm32_dma_stream_t + * structure. + * @retval NULL if a/the stream is not available. + * + * @iclass + */ +const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id, + uint32_t priority, + stm32_dmaisr_t func, + void *param) { + uint32_t i, startid, endid; + + osalDbgCheckClassI(); + + if (id < STM32_DMA_STREAMS) { + startid = id; + endid = id; + } +#if STM32_DMA_SUPPORTS_DMAMUX == TRUE + else if (id == STM32_DMA_STREAM_ID_ANY) { + startid = 0U; + endid = STM32_DMA_STREAMS - 1U; + } + else if (id == STM32_DMA_STREAM_ID_ANY_DMA1) { + startid = 0U; + endid = (STM32_DMA_STREAMS / 2U) - 1U; + } + else if (id == STM32_DMA_STREAM_ID_ANY_DMA2) { + startid = (STM32_DMA_STREAMS / 2U) - 1U; + endid = STM32_DMA_STREAMS - 1U; + } +#endif + else { + osalDbgCheck(false); + return NULL; + } + + for (i = startid; i <= endid; i++) { + uint32_t mask = (1U << i); + if ((dma.allocated_mask & mask) == 0U) { + const stm32_dma_stream_t *dmastp = STM32_DMA_STREAM(i); + + /* Installs the DMA handler.*/ + dma.streams[i].func = func; + dma.streams[i].param = param; + dma.allocated_mask |= mask; + + /* Enabling DMA clocks required by the current streams set.*/ + if ((STM32_DMA1_STREAMS_MASK & mask) != 0U) { + rccEnableDMA1(true); + } + if ((STM32_DMA2_STREAMS_MASK & mask) != 0U) { + rccEnableDMA2(true); + } + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && defined(rccEnableDMAMUX) + /* Enabling DMAMUX if present.*/ + if (dma.allocated_mask != 0U) { + rccEnableDMAMUX(true); + } +#endif + + /* Putting the stream in a safe state.*/ + dmaStreamDisable(dmastp); + dmastp->stream->CR = STM32_DMA_CR_RESET_VALUE; + dmastp->stream->FCR = STM32_DMA_FCR_RESET_VALUE; + + /* Enables the associated IRQ vector if a callback is defined.*/ + if (func != NULL) { + nvicEnableVector(dmastp->vector, priority); + } + + return dmastp; + } + } + + return NULL; +} + +/** + * @brief Allocates a DMA stream. + * @details The stream is allocated and, if required, the DMA clock enabled. + * The function also enables the IRQ vector associated to the stream + * and initializes its priority. + * + * @param[in] id numeric identifiers of a specific stream or: + * - @p STM32_DMA_STREAM_ID_ANY for any stream. + * - @p STM32_DMA_STREAM_ID_ANY_DMA1 for any stream + * on DMA1. + * - @p STM32_DMA_STREAM_ID_ANY_DMA2 for any stream + * on DMA2. + * . + * @param[in] priority IRQ priority for the DMA stream + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return Pointer to the allocated @p stm32_dma_stream_t + * structure. + * @retval NULL if a/the stream is not available. + * + * @api + */ +const stm32_dma_stream_t *dmaStreamAlloc(uint32_t id, + uint32_t priority, + stm32_dmaisr_t func, + void *param) { + const stm32_dma_stream_t *dmastp; + + osalSysLock(); + dmastp = dmaStreamAllocI(id, priority, func, param); + osalSysUnlock(); + + return dmastp; +} + +/** + * @brief Releases a DMA stream. + * @details The stream is freed and, if required, the DMA clock disabled. + * Trying to release a unallocated stream is an illegal operation + * and is trapped if assertions are enabled. + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @iclass + */ +void dmaStreamFreeI(const stm32_dma_stream_t *dmastp) { + + osalDbgCheck(dmastp != NULL); + + /* Check if the streams is not taken.*/ + osalDbgAssert((dma.allocated_mask & (1U << dmastp->selfindex)) != 0U, + "not allocated"); + + /* Disables the associated IRQ vector.*/ + nvicDisableVector(dmastp->vector); + + /* Marks the stream as not allocated.*/ + dma.allocated_mask &= ~(1U << dmastp->selfindex); + + /* Shutting down clocks that are no more required, if any.*/ + if ((dma.allocated_mask & STM32_DMA1_STREAMS_MASK) == 0U) { + rccDisableDMA1(); + } + if ((dma.allocated_mask & STM32_DMA2_STREAMS_MASK) == 0U) { + rccDisableDMA2(); + } + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && defined(rccDisableDMAMUX) + /* Shutting down DMAMUX if present.*/ + if (dma.allocated_mask == 0U) { + rccDisableDMAMUX(); + } +#endif +} + +/** + * @brief Releases a DMA stream. + * @details The stream is freed and, if required, the DMA clock disabled. + * Trying to release a unallocated stream is an illegal operation + * and is trapped if assertions are enabled. + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @api + */ +void dmaStreamFree(const stm32_dma_stream_t *dmastp) { + + osalSysLock(); + dmaStreamFreeI(dmastp); + osalSysUnlock(); +} + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__) +/** + * @brief Associates a peripheral request to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * + * @param[in] dmastp pointer to a @p stm32_dma_stream_t structure + * @param[in] per peripheral identifier + * + * @special + */ +void dmaSetRequestSource(const stm32_dma_stream_t *dmastp, uint32_t per) { + + osalDbgCheck(per < 256U); + + dmastp->mux->CCR = per; +} +#endif + +#endif /* STM32_DMA_REQUIRED */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h new file mode 100644 index 0000000..2562039 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h @@ -0,0 +1,682 @@ +/* + ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file DMAv2/stm32_dma.h + * @brief Enhanced-DMA helper driver header. + * + * @addtogroup STM32_DMA + * @{ + */ + +#ifndef STM32_DMA_H +#define STM32_DMA_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief DMA capability. + * @details if @p TRUE then the DMA is able of burst transfers, FIFOs, + * scatter gather and other advanced features. + */ +#define STM32_DMA_ADVANCED TRUE + +/** + * @brief Total number of DMA streams. + * @details This is the total number of streams among all the DMA units. + */ +#define STM32_DMA_STREAMS 16U + +/** + * @brief Mask of the ISR bits passed to the DMA callback functions. + */ +#define STM32_DMA_ISR_MASK 0x3DU + +/** + * @brief Returns the channel associated to the specified stream. + * + * @param[in] id the unique numeric stream identifier + * @param[in] c a stream/channel association word, one channel per + * nibble + * @return Returns the channel associated to the stream. + */ +#define STM32_DMA_GETCHANNEL(id, c) (((c) >> (((id) & 7U) * 4U)) & 15U) + +/** + * @brief Checks if a DMA priority is within the valid range. + * @param[in] prio DMA priority + * + * @retval The check result. + * @retval false invalid DMA priority. + * @retval true correct DMA priority. + */ +#define STM32_DMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U)) + +#if (STM32_DMA_SUPPORTS_DMAMUX == FALSE) || defined(_DOXYGEN__) +/** + * @brief Checks if a DMA stream id is within the valid range. + * + * @param[in] id DMA stream id + * @retval The check result. + * @retval false invalid DMA stream. + * @retval true correct DMA stream. + */ +#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \ + ((id) <= STM32_DMA_STREAMS)) +#else /* STM32_DMA_SUPPORTS_DMAMUX == FALSE */ +#if STM32_HAS_DMA2 == TRUE +#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \ + ((id) <= (STM32_DMA_STREAMS + 2))) +#else +#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \ + ((id) <= (STM32_DMA_STREAMS + 1))) +#endif +#endif /* STM32_DMA_SUPPORTS_DMAMUX == FALSE */ + +/** + * @brief Returns an unique numeric identifier for a DMA stream. + * + * @param[in] dma the DMA unit number + * @param[in] stream the stream number + * @return An unique numeric stream identifier. + */ +#define STM32_DMA_STREAM_ID(dma, stream) ((((dma) - 1U) * 8U) + (stream)) + +/** + * @brief Returns a DMA stream identifier mask. + * + * + * @param[in] dma the DMA unit number + * @param[in] stream the stream number + * @return A DMA stream identifier mask. + */ +#define STM32_DMA_STREAM_ID_MSK(dma, stream) \ + (1U << STM32_DMA_STREAM_ID(dma, stream)) + +/** + * @brief Checks if a DMA stream unique identifier belongs to a mask. + * @param[in] id the stream numeric identifier + * @param[in] mask the stream numeric identifiers mask + * + * @retval The check result. + * @retval false id does not belong to the mask. + * @retval true id belongs to the mask. + */ +#define STM32_DMA_IS_VALID_ID(id, mask) (((1U << (id)) & (mask))) + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(_DOXYGEN__) +/** + * @name Special stream identifiers + * @{ + */ +#define STM32_DMA_STREAM_ID_ANY STM32_DMA_STREAMS +#define STM32_DMA_STREAM_ID_ANY_DMA1 (STM32_DMA_STREAM_ID_ANY + 1) +#if STM32_HAS_DMA2 == TRUE +#define STM32_DMA_STREAM_ID_ANY_DMA2 (STM32_DMA_STREAM_ID_ANY_DMA1 + 1) +#endif +/** @} */ +#endif + +/** + * @name DMA streams identifiers + * @{ + */ +/** + * @brief Returns a pointer to a stm32_dma_stream_t structure. + * + * @param[in] id the stream numeric identifier + * @return A pointer to the stm32_dma_stream_t constant structure + * associated to the DMA stream. + */ +#define STM32_DMA_STREAM(id) (&_stm32_dma_streams[id]) + +#define STM32_DMA1_STREAM0 STM32_DMA_STREAM(0) +#define STM32_DMA1_STREAM1 STM32_DMA_STREAM(1) +#define STM32_DMA1_STREAM2 STM32_DMA_STREAM(2) +#define STM32_DMA1_STREAM3 STM32_DMA_STREAM(3) +#define STM32_DMA1_STREAM4 STM32_DMA_STREAM(4) +#define STM32_DMA1_STREAM5 STM32_DMA_STREAM(5) +#define STM32_DMA1_STREAM6 STM32_DMA_STREAM(6) +#define STM32_DMA1_STREAM7 STM32_DMA_STREAM(7) +#define STM32_DMA2_STREAM0 STM32_DMA_STREAM(8) +#define STM32_DMA2_STREAM1 STM32_DMA_STREAM(9) +#define STM32_DMA2_STREAM2 STM32_DMA_STREAM(10) +#define STM32_DMA2_STREAM3 STM32_DMA_STREAM(11) +#define STM32_DMA2_STREAM4 STM32_DMA_STREAM(12) +#define STM32_DMA2_STREAM5 STM32_DMA_STREAM(13) +#define STM32_DMA2_STREAM6 STM32_DMA_STREAM(14) +#define STM32_DMA2_STREAM7 STM32_DMA_STREAM(15) +/** @} */ + +/** + * @name CR register constants common to all DMA types + * @{ + */ +#define STM32_DMA_CR_RESET_VALUE 0x00000000U +#define STM32_DMA_CR_EN DMA_SxCR_EN +#define STM32_DMA_CR_TEIE DMA_SxCR_TEIE +#define STM32_DMA_CR_HTIE DMA_SxCR_HTIE +#define STM32_DMA_CR_TCIE DMA_SxCR_TCIE +#define STM32_DMA_CR_PFCTRL DMA_SxCR_PFCTRL +#define STM32_DMA_CR_DIR_MASK DMA_SxCR_DIR +#define STM32_DMA_CR_DIR_P2M 0 +#define STM32_DMA_CR_DIR_M2P DMA_SxCR_DIR_0 +#define STM32_DMA_CR_DIR_M2M DMA_SxCR_DIR_1 +#define STM32_DMA_CR_CIRC DMA_SxCR_CIRC +#define STM32_DMA_CR_PINC DMA_SxCR_PINC +#define STM32_DMA_CR_MINC DMA_SxCR_MINC +#define STM32_DMA_CR_PSIZE_MASK DMA_SxCR_PSIZE +#define STM32_DMA_CR_PSIZE_BYTE 0 +#define STM32_DMA_CR_PSIZE_HWORD DMA_SxCR_PSIZE_0 +#define STM32_DMA_CR_PSIZE_WORD DMA_SxCR_PSIZE_1 +#define STM32_DMA_CR_MSIZE_MASK DMA_SxCR_MSIZE +#define STM32_DMA_CR_MSIZE_BYTE 0 +#define STM32_DMA_CR_MSIZE_HWORD DMA_SxCR_MSIZE_0 +#define STM32_DMA_CR_MSIZE_WORD DMA_SxCR_MSIZE_1 +#define STM32_DMA_CR_SIZE_MASK (STM32_DMA_CR_PSIZE_MASK | \ + STM32_DMA_CR_MSIZE_MASK) +#define STM32_DMA_CR_PL_MASK DMA_SxCR_PL +#define STM32_DMA_CR_PL(n) ((n) << 16U) +/** @} */ + +/** + * @name CR register constants only found in DMAv2 + * @{ + */ +#define STM32_DMA_CR_DMEIE DMA_SxCR_DMEIE +#define STM32_DMA_CR_PFCTRL DMA_SxCR_PFCTRL +#define STM32_DMA_CR_PINCOS DMA_SxCR_PINCOS +#define STM32_DMA_CR_DBM DMA_SxCR_DBM +#define STM32_DMA_CR_CT DMA_SxCR_CT +#define STM32_DMA_CR_PBURST_MASK DMA_SxCR_PBURST +#define STM32_DMA_CR_PBURST_SINGLE 0U +#define STM32_DMA_CR_PBURST_INCR4 DMA_SxCR_PBURST_0 +#define STM32_DMA_CR_PBURST_INCR8 DMA_SxCR_PBURST_1 +#define STM32_DMA_CR_PBURST_INCR16 (DMA_SxCR_PBURST_0 | DMA_SxCR_PBURST_1) +#define STM32_DMA_CR_MBURST_MASK DMA_SxCR_MBURST +#define STM32_DMA_CR_MBURST_SINGLE 0U +#define STM32_DMA_CR_MBURST_INCR4 DMA_SxCR_MBURST_0 +#define STM32_DMA_CR_MBURST_INCR8 DMA_SxCR_MBURST_1 +#define STM32_DMA_CR_MBURST_INCR16 (DMA_SxCR_MBURST_0 | DMA_SxCR_MBURST_1) +#if (STM32_DMA_SUPPORTS_DMAMUX == FALSE) || defined(__DOXYGEN__) +#define STM32_DMA_CR_CHSEL_MASK DMA_SxCR_CHSEL +#define STM32_DMA_CR_CHSEL(n) ((n) << 25U) +#else +#define STM32_DMA_CR_CHSEL_MASK 0U +#define STM32_DMA_CR_CHSEL(n) 0U +#endif +/** @} */ + +/** + * @name FCR register constants only found in DMAv2 + * @{ + */ +#define STM32_DMA_FCR_RESET_VALUE 0x00000021U +#define STM32_DMA_FCR_FEIE DMA_SxFCR_FEIE +#define STM32_DMA_FCR_FS_MASK DMA_SxFCR_FS +#define STM32_DMA_FCR_DMDIS DMA_SxFCR_DMDIS +#define STM32_DMA_FCR_FTH_MASK DMA_SxFCR_FTH +#define STM32_DMA_FCR_FTH_1Q 0 +#define STM32_DMA_FCR_FTH_HALF DMA_SxFCR_FTH_0 +#define STM32_DMA_FCR_FTH_3Q DMA_SxFCR_FTH_1 +#define STM32_DMA_FCR_FTH_FULL (DMA_SxFCR_FTH_0 | DMA_SxFCR_FTH_1) +/** @} */ + +/** + * @name Status flags passed to the ISR callbacks + */ +#define STM32_DMA_ISR_FEIF DMA_LISR_FEIF0 +#define STM32_DMA_ISR_DMEIF DMA_LISR_DMEIF0 +#define STM32_DMA_ISR_TEIF DMA_LISR_TEIF0 +#define STM32_DMA_ISR_HTIF DMA_LISR_HTIF0 +#define STM32_DMA_ISR_TCIF DMA_LISR_TCIF0 +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_DMA_SUPPORTS_DMAMUX) +#error "STM32_DMA_SUPPORTS_DMAMUX not defined in registry" +#endif + +#if !defined(STM32_HAS_DMA1) +#error "STM32_HAS_DMA1 missing in registry" +#endif + +#if !defined(STM32_HAS_DMA2) +#error "STM32_HAS_DMA2 missing in registry" +#endif + +#if !defined(STM32_DMA1_CH0_HANDLER) +#error "STM32_DMA1_CH0_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH1_HANDLER) +#error "STM32_DMA1_CH1_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH2_HANDLER) +#error "STM32_DMA1_CH2_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH3_HANDLER) +#error "STM32_DMA1_CH3_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH4_HANDLER) +#error "STM32_DMA1_CH4_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH5_HANDLER) +#error "STM32_DMA1_CH5_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH6_HANDLER) +#error "STM32_DMA1_CH6_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH7_HANDLER) +#error "STM32_DMA1_CH7_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH0_HANDLER) +#error "STM32_DMA2_CH0_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH1_HANDLER) +#error "STM32_DMA2_CH1_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH2_HANDLER) +#error "STM32_DMA2_CH2_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH3_HANDLER) +#error "STM32_DMA2_CH3_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH4_HANDLER) +#error "STM32_DMA2_CH4_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH5_HANDLER) +#error "STM32_DMA2_CH5_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH6_HANDLER) +#error "STM32_DMA2_CH6_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH7_HANDLER) +#error "STM32_DMA2_CH7_HANDLER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH0_NUMBER) +#error "STM32_DMA1_CH0_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH1_NUMBER) +#error "STM32_DMA1_CH1_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH2_NUMBER) +#error "STM32_DMA1_CH2_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH3_NUMBER) +#error "STM32_DMA1_CH3_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH4_NUMBER) +#error "STM32_DMA1_CH4_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH5_NUMBER) +#error "STM32_DMA1_CH5_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH6_NUMBER) +#error "STM32_DMA1_CH6_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA1_CH7_NUMBER) +#error "STM32_DMA1_CH7_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH0_NUMBER) +#error "STM32_DMA2_CH0_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH1_NUMBER) +#error "STM32_DMA2_CH1_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH2_NUMBER) +#error "STM32_DMA2_CH2_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH3_NUMBER) +#error "STM32_DMA2_CH3_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH4_NUMBER) +#error "STM32_DMA2_CH4_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH5_NUMBER) +#error "STM32_DMA2_CH5_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH6_NUMBER) +#error "STM32_DMA2_CH6_NUMBER missing in registry" +#endif + +#if !defined(STM32_DMA2_CH7_NUMBER) +#error "STM32_DMA2_CH7_NUMBER missing in registry" +#endif + +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__) +#include "stm32_dmamux.h" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief STM32 DMA ISR function type. + * + * @param[in] p parameter for the registered function + * @param[in] flags pre-shifted content of the xISR register, the bits + * are aligned to bit zero + */ +typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags); + +/** + * @brief STM32 DMA stream descriptor structure. + */ +typedef struct { + DMA_Stream_TypeDef *stream; /**< @brief Associated DMA stream. */ + volatile uint32_t *ifcr; /**< @brief Associated IFCR reg. */ +#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__) + DMAMUX_Channel_TypeDef *mux; /**< @brief Associated DMA mux. */ +#else + uint8_t dummy; /**< @brief Filler. */ +#endif + uint8_t shift; /**< @brief Bits offset in xIFCR + register. */ + uint8_t selfindex; /**< @brief Index to self in array. */ + uint8_t vector; /**< @brief Associated IRQ vector. */ +} stm32_dma_stream_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Associates a peripheral data register to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the PAR register + * + * @special + */ +#define dmaStreamSetPeripheral(dmastp, addr) { \ + (dmastp)->stream->PAR = (uint32_t)(addr); \ +} + +/** + * @brief Associates a memory destination to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the M0AR register + * + * @special + */ +#define dmaStreamSetMemory0(dmastp, addr) { \ + (dmastp)->stream->M0AR = (uint32_t)(addr); \ +} + +/** + * @brief Associates an alternate memory destination to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the M1AR register + * + * @special + */ +#define dmaStreamSetMemory1(dmastp, addr) { \ + (dmastp)->stream->M1AR = (uint32_t)(addr); \ +} + +/** + * @brief Sets the number of transfers to be performed. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] size value to be written in the CNDTR register + * + * @special + */ +#define dmaStreamSetTransactionSize(dmastp, size) { \ + (dmastp)->stream->NDTR = (uint32_t)(size); \ +} + +/** + * @brief Returns the number of transfers to be performed. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @return The number of transfers to be performed. + * + * @special + */ +#define dmaStreamGetTransactionSize(dmastp) ((size_t)((dmastp)->stream->NDTR)) + +/** + * @brief Programs the stream mode settings. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] mode value to be written in the CR register + * + * @special + */ +#define dmaStreamSetMode(dmastp, mode) { \ + (dmastp)->stream->CR = (uint32_t)(mode); \ +} + +/** + * @brief Programs the stream FIFO settings. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] mode value to be written in the FCR register + * + * @special + */ +#define dmaStreamSetFIFO(dmastp, mode) { \ + (dmastp)->stream->FCR = (uint32_t)(mode); \ +} + +/** + * @brief DMA stream enable. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +#define dmaStreamEnable(dmastp) { \ + (dmastp)->stream->CR |= STM32_DMA_CR_EN; \ +} + +/** + * @brief DMA stream disable. + * @details The function disables the specified stream, waits for the disable + * operation to complete and then clears any pending interrupt. + * @note This function can be invoked in both ISR or thread context. + * @note Interrupts enabling flags are set to zero after this call, see + * bug 3607518. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +#define dmaStreamDisable(dmastp) { \ + (dmastp)->stream->CR &= ~(STM32_DMA_CR_TCIE | STM32_DMA_CR_HTIE | \ + STM32_DMA_CR_TEIE | STM32_DMA_CR_DMEIE | \ + STM32_DMA_CR_EN); \ + while (((dmastp)->stream->CR & STM32_DMA_CR_EN) != 0) \ + ; \ + dmaStreamClearInterrupt(dmastp); \ +} + +/** + * @brief DMA stream interrupt sources clear. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +#define dmaStreamClearInterrupt(dmastp) { \ + *(dmastp)->ifcr = STM32_DMA_ISR_MASK << (dmastp)->shift; \ +} + +/** + * @brief Starts a memory to memory operation using the specified stream. + * @note The default transfer data mode is "byte to byte" but it can be + * changed by specifying extra options in the @p mode parameter. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] mode value to be written in the CCR register, this value + * is implicitly ORed with: + * - @p STM32_DMA_CR_MINC + * - @p STM32_DMA_CR_PINC + * - @p STM32_DMA_CR_DIR_M2M + * - @p STM32_DMA_CR_EN + * . + * @param[in] src source address + * @param[in] dst destination address + * @param[in] n number of data units to copy + */ +#define dmaStartMemCopy(dmastp, mode, src, dst, n) { \ + dmaStreamSetPeripheral(dmastp, src); \ + dmaStreamSetMemory0(dmastp, dst); \ + dmaStreamSetTransactionSize(dmastp, n); \ + dmaStreamSetMode(dmastp, (mode) | \ + STM32_DMA_CR_MINC | STM32_DMA_CR_PINC | \ + STM32_DMA_CR_DIR_M2M); \ + dmaStreamEnable(dmastp); \ +} + +/** + * @brief Polled wait for DMA transfer end. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + */ +#define dmaWaitCompletion(dmastp) { \ + (dmastp)->stream->CR &= ~(STM32_DMA_CR_TCIE | STM32_DMA_CR_HTIE | \ + STM32_DMA_CR_TEIE | STM32_DMA_CR_DMEIE); \ + while ((dmastp)->stream->CR & STM32_DMA_CR_EN) \ + ; \ + dmaStreamClearInterrupt(dmastp); \ +} + +/** + * @brief DMA stream current target. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAlloc(). + * @post After use the stream can be released using @p dmaStreamFree(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @return Current memory target index. + * + * @special + */ +#define dmaStreamGetCurrentTarget(dmastp) \ + (((dmastp)->stream->CR >> DMA_SxCR_CT_Pos) & 1U) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS]; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void dmaInit(void); + const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id, + uint32_t priority, + stm32_dmaisr_t func, + void *param); + const stm32_dma_stream_t *dmaStreamAlloc(uint32_t id, + uint32_t priority, + stm32_dmaisr_t func, + void *param); + void dmaStreamFreeI(const stm32_dma_stream_t *dmastp); + void dmaStreamFree(const stm32_dma_stream_t *dmastp); +#if STM32_DMA_SUPPORTS_DMAMUX == TRUE + void dmaSetRequestSource(const stm32_dma_stream_t *dmastp, uint32_t per); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* STM32_DMA_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/driver.mk new file mode 100644 index 0000000..63016f9 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/notes.txt new file mode 100644 index 0000000..ac83cf5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/notes.txt @@ -0,0 +1,14 @@ +STM32 EXTIv1 driver. + +Driver capability: + +- Support for the EXTI peripheral. + +The file registry must export: + +STM32_EXTI_NUM_LINES - Number of EXTI lines, it can be between 0 and 63. +STM32_EXTI_IMR1_MASK - Mask of the fixed lines that must not be + handled by the driver (0..31). +STM32_EXTI_IMR2_MASK - Mask of the fixed lines that must not be + handled by the driver (32..63). Only required + if STM32_EXTI_NUM_LINES is greater than 32. diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c new file mode 100644 index 0000000..e2877cf --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c @@ -0,0 +1,216 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti.c + * @brief EXTI helper driver code. + * + * @addtogroup STM32_EXTI + * @details EXTI sharing helper driver. + * @{ + */ + +#include "hal.h" + +/* The following macro is only defined if some driver requiring EXTI services + has been enabled.*/ +#if defined(STM32_EXTI_REQUIRED) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief STM32 EXTI group 1 lines initialization. + * + * @param[in] mask mask of group 1 lines to be initialized + * @param[in] mode initialization mode + * + * @api + */ +void extiEnableGroup1(uint32_t mask, extimode_t mode) { + + /* Masked out lines must not be touched by this driver.*/ + osalDbgAssert((mask & STM32_EXTI_IMR1_MASK) == 0U, "fixed lines"); + + if ((mode & EXTI_MODE_EDGES_MASK) == 0U) { + /* Disabling channels.*/ + EXTI->IMR1 &= ~mask; + EXTI->EMR1 &= ~mask; + EXTI->RTSR1 &= ~mask; + EXTI->FTSR1 &= ~mask; +#if STM32_EXTI_SEPARATE_RF == FALSE + EXTI->PR1 = mask; +#else + EXTI->RPR1 = mask; + EXTI->FPR1 = mask; +#endif + } + else { + /* Programming edge registers.*/ + if (mode & EXTI_MODE_RISING_EDGE) { + EXTI->RTSR1 |= mask; + } + else { + EXTI->RTSR1 &= ~mask; + } + if (mode & EXTI_MODE_FALLING_EDGE) { + EXTI->FTSR1 |= mask; + } + else { + EXTI->FTSR1 &= ~mask; + } + + /* Programming interrupt and event registers.*/ + if ((mode & EXTI_MODE_ACTION_MASK) == EXTI_MODE_ACTION_INTERRUPT) { + EXTI->IMR1 |= mask; + EXTI->EMR1 &= ~mask; + } + else { + EXTI->EMR1 |= mask; + EXTI->IMR1 &= ~mask; + } + } +} + +#if (STM32_EXTI_HAS_GROUP2 == TRUE) || defined(__DOXYGEN__) +/** + * @brief STM32 EXTI group 2 lines initialization. + * + * @param[in] mask mask of group 2 lines to be initialized + * @param[in] mode initialization mode + * + * @api + */ +void extiEnableGroup2(uint32_t mask, extimode_t mode) { + + /* Masked out lines must not be touched by this driver.*/ + osalDbgAssert((mask & STM32_EXTI_IMR2_MASK) == 0U, "fixed lines"); + + if ((mode & EXTI_MODE_EDGES_MASK) == 0U) { + /* Disabling channels.*/ + EXTI->IMR2 &= ~mask; + EXTI->EMR2 &= ~mask; + EXTI->RTSR2 &= ~mask; + EXTI->FTSR2 &= ~mask; +#if STM32_EXTI_SEPARATE_RF == FALSE + EXTI->PR2 = mask; +#else + EXTI->RPR2 = mask; + EXTI->FPR2 = mask; +#endif + } + else { + /* Programming edge registers.*/ + if (mode & EXTI_MODE_RISING_EDGE) { + EXTI->RTSR2 |= mask; + } + else { + EXTI->RTSR2 &= ~mask; + } + if (mode & EXTI_MODE_FALLING_EDGE) { + EXTI->FTSR2 |= mask; + } + else { + EXTI->FTSR2 &= ~mask; + } + + /* Programming interrupt and event registers.*/ + if ((mode & EXTI_MODE_ACTION_MASK) == EXTI_MODE_ACTION_INTERRUPT) { + EXTI->IMR2 |= mask; + EXTI->EMR2 &= ~mask; + } + else { + EXTI->EMR2 |= mask; + EXTI->IMR2 &= ~mask; + } + } +} +#endif /* STM32_EXTI_HAS_GROUP2 == TRUE */ + +/** + * @brief STM32 EXTI line initialization. + * + * @param[in] line line to be initialized + * @param[in] mode initialization mode + * + * @api + */ +void extiEnableLine(extiline_t line, extimode_t mode) { + uint32_t mask = (1U << (line & 0x1FU)); + + osalDbgCheck(line < STM32_EXTI_NUM_LINES); + osalDbgCheck((mode & ~EXTI_MODE_MASK) == 0U); + +#if STM32_EXTI_HAS_GROUP2 == TRUE + if (line < 32) { +#endif + extiEnableGroup1(mask, mode); +#if STM32_EXTI_HAS_GROUP2 == TRUE + } + else { + extiEnableGroup2(mask, mode); + } +#endif +} + +/** + * @brief STM32 EXTI line IRQ status clearing. + * + * @param[in] line line to be initialized + * + * @api + */ +void extiClearLine(extiline_t line) { + uint32_t mask = (1U << (line & 0x1FU)); + + osalDbgCheck(line < STM32_EXTI_NUM_LINES); + +#if STM32_EXTI_HAS_GROUP2 == TRUE + if (line < 32) { +#endif + extiClearGroup1(mask); +#if STM32_EXTI_HAS_GROUP2 == TRUE + } + else { + extiClearGroup2(mask); + } +#endif +} + +#endif /* STM32_EXTI_REQUIRED */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.h new file mode 100644 index 0000000..dadc58c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.h @@ -0,0 +1,257 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti.h + * @brief EXTI helper driver header. + * + * @addtogroup STM32_EXTI + * @{ + */ + +#ifndef STM32_EXTI_H +#define STM32_EXTI_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name EXTI channel modes + * @{ + */ +#define EXTI_MODE_MASK 7U /**< @brief Mode parameter mask. */ +#define EXTI_MODE_EDGES_MASK 3U /**< @brief Edges field mask. */ +#define EXTI_MODE_DISABLED 0U /**< @brief Channel disabled. */ +#define EXTI_MODE_RISING_EDGE 1U /**< @brief Rising edge callback. */ +#define EXTI_MODE_FALLING_EDGE 2U /**< @brief Falling edge callback. */ +#define EXTI_MODE_BOTH_EDGES 3U /**< @brief Both edges callback. */ +#define EXTI_MODE_ACTION_MASK 4U /**< @brief Action field mask. */ +#define EXTI_MODE_ACTION_INTERRUPT 0U /**< @brief Interrupt mode. */ +#define EXTI_MODE_ACTION_EVENT 4U /**< @brief Event mode. */ +/** @} */ + +/* Handling differences in ST headers.*/ +#if !defined(STM32H7XX) && !defined(STM32L4XX) && !defined(STM32L4XXP) && \ + !defined(STM32G0XX) && !defined(STM32G4XX) +#define EMR1 EMR +#define IMR1 IMR +#define PR1 PR +#define RTSR1 RTSR +#define FTSR1 FTSR +#endif + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_EXTI_NUM_LINES) +#error "STM32_EXTI_NUM_LINES not defined in registry" +#endif + +/* Checking for presence of bank 2 registers. If the definition is not + present in registry then it is inferred by the number of channels (which + is not an always-good method, see G0.*/ +#if !defined(STM32_EXTI_HAS_GROUP2) +#if STM32_EXTI_NUM_LINES <= 32 +#define STM32_EXTI_HAS_GROUP2 FALSE +#else +#define STM32_EXTI_HAS_GROUP2 TRUE +#endif +#endif /* !defined(STM32_EXTI_HAS_GROUP2) */ + +/* Determines if EXTI has dedicated CR register or if it is done in + SYSCFG (old style).*/ +#if !defined(STM32_EXTI_HAS_CR) +#define STM32_EXTI_HAS_CR FALSE +#endif + +/* Determines if EXTI has dedicated separate registers for raising and + falling edges.*/ +#if !defined(STM32_EXTI_SEPARATE_RF) +#define STM32_EXTI_SEPARATE_RF FALSE +#endif + +#if (STM32_EXTI_NUM_LINES < 0) || (STM32_EXTI_NUM_LINES > 63) +#error "invalid STM32_EXTI_NUM_LINES value" +#endif + +#if !defined(STM32_EXTI_IMR1_MASK) +#error "STM32_EXTI_IMR1_MASK not defined in registry" +#endif + +#if STM32_EXTI_NUM_LINES > 32 +#if !defined(STM32_EXTI_IMR2_MASK) +#error "STM32_EXTI_IMR2_MASK not defined in registry" +#endif +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of an EXTI line identifier. + */ +typedef uint32_t extiline_t; + +/** + * @brief Type of an EXTI line mode. + */ +typedef uint32_t extimode_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief From group 1 line number to mask. + * + * @param[in] line line number in range 0..31 + */ +#define EXTI_MASK1(line) (uint32_t)(1U << (line)) + +/** + * @brief From group 2 line number to mask. + * + * @param[in] line line number in range 32..63 + */ +#define EXTI_MASK2(line) (uint32_t)(1U << ((line) - 32U)) + +/** + * @brief STM32 EXTI group 1 IRQ status clearing. + * + * @param[in] mask mask of group 1 lines to be initialized + * + * @special + */ +#if (STM32_EXTI_SEPARATE_RF == FALSE) || defined(__DOXYGEN__) +#define extiClearGroup1(mask) do { \ + osalDbgAssert(((mask) & STM32_EXTI_IMR1_MASK) == 0U, "fixed lines"); \ + EXTI->PR1 = (uint32_t)(mask); \ +} while (false) +#else +#define extiClearGroup1(mask) do { \ + osalDbgAssert(((mask) & STM32_EXTI_IMR1_MASK) == 0U, "fixed lines"); \ + EXTI->RPR1 = (uint32_t)(mask); \ + EXTI->FPR1 = (uint32_t)(mask); \ +} while (false) +#endif + +#if (STM32_EXTI_HAS_GROUP2 == TRUE) || defined(__DOXYGEN__) +/** + * @brief STM32 EXTI group 2 IRQ status clearing. + * + * @param[in] mask mask of group 2 lines to be initialized + * + * @special + */ +#if (STM32_EXTI_SEPARATE_RF == FALSE) || defined(__DOXYGEN__) +#define extiClearGroup2(mask) do { \ + osalDbgAssert(((mask) & STM32_EXTI_IMR2_MASK) == 0U, "fixed lines"); \ + EXTI->PR2 = (uint32_t)(mask); \ +} while (false) +#else +#define extiClearGroup2(mask) do { \ + osalDbgAssert(((mask) & STM32_EXTI_IMR2_MASK) == 0U, "fixed lines"); \ + EXTI->RPR2 = (uint32_t)(mask); \ + EXTI->FPR2 = (uint32_t)(mask); \ +} while (false) +#endif +#endif /* STM32_EXTI_HAS_GROUP2 == TRUE */ + +/** + * @brief Serves an EXTI interrupt in group 1. + * + * @param[in] mask mask of lines to be cleared + * @param[out] out mask of lines needing processing + * + * @special + */ +#if (STM32_EXTI_SEPARATE_RF == FALSE) || defined(__DOXYGEN__) +#define extiGetAndClearGroup1(mask, out) do { \ + uint32_t pr1; \ + \ + pr1 = EXTI->PR1 & (mask); \ + (out) = pr1; \ + EXTI->PR1 = pr1; \ +} while (false) +#else +#define extiGetAndClearGroup1(mask, out) do { \ + uint32_t rpr1, fpr1; \ + \ + rpr1 = EXTI->RPR1 & (mask); \ + fpr1 = EXTI->FPR1 & (mask); \ + (out) = rpr1 | fpr1; \ + EXTI->RPR1 = rpr1; \ + EXTI->FPR1 = fpr1; \ +} while (false) +#endif + +#if (STM32_EXTI_HAS_GROUP2 == TRUE) || defined(__DOXYGEN__) +/** + * @brief Serves an EXTI interrupt in group 2. + * + * @param[in] mask mask of lines to be cleared + * @param[out] out mask of lines needing processing + * + * @special + */ +#if (STM32_EXTI_SEPARATE_RF == FALSE) || defined(__DOXYGEN__) +#define extiGetAndClearGroup2(mask, out) do { \ + uint32_t pr2; \ + \ + pr2 = EXTI->PR2 & (mask); \ + (out) = pr2; \ + EXTI->PR2 = pr2; \ +} while (false) +#else +#define extiGetAndClearGroup2(mask, out) do { \ + uint32_t rpr2, fpr2; \ + \ + rpr2 = EXTI->RPR2 & (mask); \ + fpr2 = EXTI->FPR2 & (mask); \ + (out) = rpr2 | fpr2; \ + EXTI->RPR2 = rpr2; \ + EXTI->FPR2 = fpr2; \ +} while (false) +#endif +#endif /* STM32_EXTI_HAS_GROUP2 == TRUE */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void extiEnableGroup1(uint32_t mask, extimode_t mode); +#if (STM32_EXTI_HAS_GROUP2 == TRUE) || defined(__DOXYGEN__) + void extiEnableGroup2(uint32_t mask, extimode_t mode); +#endif /* STM32_EXTI_HAS_GROUP2 == TRUE */ + void extiEnableLine(extiline_t line, extimode_t mode); + void extiClearLine(extiline_t line); + #ifdef __cplusplus +} +#endif + +#endif /* STM32_EXTI_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0.inc new file mode 100644 index 0000000..e02707b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0.inc @@ -0,0 +1,95 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti0.inc + * @brief Shared EXTI0 handler. + * + * @addtogroup STM32_EXTI0_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI0_PRIORITY) +#error "STM32_IRQ_EXTI0_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI0_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI0_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti0_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI0_NUMBER, STM32_IRQ_EXTI0_PRIORITY); +#endif +} + +static inline void exti0_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI0_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI0_HANDLER) +/** + * @brief EXTI[0] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI0_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 0, pr); + + exti_serve_irq(pr, 0); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0_1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0_1.inc new file mode 100644 index 0000000..d20141b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0_1.inc @@ -0,0 +1,96 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti0_1.inc + * @brief Shared EXTI0_1 handler. + * + * @addtogroup STM32_EXTI0_1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI0_1_PRIORITY) +#error "STM32_IRQ_EXTI0_1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI0_1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI0_1_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti0_1_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI0_1_NUMBER, STM32_IRQ_EXTI0_1_PRIORITY); +#endif +} + +static inline void exti0_1_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI0_1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI0_1_HANDLER) +/** + * @brief EXTI[0], EXTI[1] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI0_1_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 0) | (1U << 1), pr); + + exti_serve_irq(pr, 0); + exti_serve_irq(pr, 1); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti1.inc new file mode 100644 index 0000000..c7a9de1 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti1.inc @@ -0,0 +1,95 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti1.inc + * @brief Shared EXTI1 handler. + * + * @addtogroup STM32_EXTI1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI1_PRIORITY) +#error "STM32_IRQ_EXTI1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI1_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti1_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI1_NUMBER, STM32_IRQ_EXTI1_PRIORITY); +#endif +} + +static inline void exti1_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI1_HANDLER) +/** + * @brief EXTI[1] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI1_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 1, pr); + + exti_serve_irq(pr, 1); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti10_15.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti10_15.inc new file mode 100644 index 0000000..3288dc9 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti10_15.inc @@ -0,0 +1,101 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti10_15.inc + * @brief Shared EXTI10_15 handler. + * + * @addtogroup STM32_EXTI10_15_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI10_15_PRIORITY) +#error "STM32_IRQ_EXTI10_15_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI10_15_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI10_15_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti10_15_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI10_15_NUMBER, STM32_IRQ_EXTI10_15_PRIORITY); +#endif +} + +static inline void exti10_15_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI10_15_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI10_15_HANDLER) +/** + * @brief EXTI[10]..EXTI[15] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI10_15_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 10) | (1U << 11) | (1U << 12) | (1U << 13) | + (1U << 14) | (1U << 15), pr); + + exti_serve_irq(pr, 10); + exti_serve_irq(pr, 11); + exti_serve_irq(pr, 12); + exti_serve_irq(pr, 13); + exti_serve_irq(pr, 14); + exti_serve_irq(pr, 15); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-35_38.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-35_38.inc new file mode 100644 index 0000000..aa21235 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-35_38.inc @@ -0,0 +1,130 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti16-35_38.inc + * @brief Shared EXTI16-35_38 handler. + * + * @addtogroup STM32_EXTI1635_38_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI1635_38_PRIORITY) +#error "STM32_IRQ_EXTI1635_38_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI1635_38_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI1635_38_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti16_exti35_38_irq_init(void) { +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI35_IS_USED) || \ + defined(STM32_EXTI36_IS_USED) || defined(STM32_EXTI37_IS_USED) || \ + defined(STM32_EXTI38_IS_USED) + nvicEnableVector(STM32_EXTI1635_38_NUMBER, STM32_IRQ_EXTI1635_38_PRIORITY); +#endif +} + +static inline void exti16_exti35_38_irq_deinit(void) { +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI35_IS_USED) || \ + defined(STM32_EXTI36_IS_USED) || defined(STM32_EXTI37_IS_USED) || \ + defined(STM32_EXTI38_IS_USED) + nvicDisableVector(STM32_EXTI1635_38_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI35_IS_USED) || \ + defined(STM32_EXTI36_IS_USED) || defined(STM32_EXTI37_IS_USED) || \ + defined(STM32_EXTI38_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI1635_38_HANDLER) +/** + * @brief EXTI[16], EXTI[35], EXTI[38] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI163538_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + +#if defined(STM32_EXTI16_IS_USED) + extiGetAndClearGroup1(1U << 16, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI16_ISR) + STM32_EXTI16_ISR(pr, 16); +#endif +#endif + +#if defined(STM32_EXTI35_IS_USED) || defined(STM32_EXTI36_IS_USED) || \ + defined(STM32_EXTI37_IS_USED) || defined(STM32_EXTI38_IS_USED) + extiGetAndClearGroup2((1U << (35 - 32)) | (1U << (36 - 32)) | + (1U << (37 - 32)) | (1U << (38 - 32)), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI35_ISR) + STM32_EXTI35_ISR(pr, 35); +#endif +#if defined(STM32_EXTI36_ISR) + STM32_EXTI35_ISR(pr, 36); +#endif +#if defined(STM32_EXTI37_ISR) + STM32_EXTI35_ISR(pr, 37); +#endif +#if defined(STM32_EXTI38_ISR) + STM32_EXTI38_ISR(pr, 38); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-40_41.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-40_41.inc new file mode 100644 index 0000000..b8aebe4 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-40_41.inc @@ -0,0 +1,119 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti16-40_41.inc + * @brief Shared EXTI16-40_41 handler. + * + * @addtogroup STM32_EXTI164041_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI164041_PRIORITY) +#error "STM32_IRQ_EXTI164041_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI164041_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI164041_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti16_exti40_exti41_irq_init(void) { +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI40_IS_USED) || \ + defined(STM32_EXTI41_IS_USED) + nvicEnableVector(STM32_EXTI164041_NUMBER, STM32_IRQ_EXTI164041_PRIORITY); +#endif +} + +static inline void exti16_exti40_exti41_irq_deinit(void) { +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI40_IS_USED) || \ + defined(STM32_EXTI41_IS_USED) + nvicDisableVector(STM32_EXTI164041_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI40_IS_USED) || \ + defined(STM32_EXTI41_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI164041_HANDLER) +/** + * @brief EXTI[16], EXTI[40], EXTI[41] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI164041_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + +#if defined(STM32_EXTI16_IS_USED) + extiGetAndClearGroup1(1U << 16, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI16_ISR) + STM32_EXTI16_ISR(pr, 16); +#endif +#endif + +#if defined(STM32_EXTI40_IS_USED) || defined(STM32_EXTI41_IS_USED) + extiGetAndClearGroup2((1U << (40 - 32)) | (1U << (41 - 32)), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI40_ISR) + STM32_EXTI40_ISR(pr, 40); +#endif +#if defined(STM32_EXTI41_ISR) + STM32_EXTI41_ISR(pr, 41); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16.inc new file mode 100644 index 0000000..d09ef3a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti16.inc + * @brief Shared EXTI16 handler. + * + * @addtogroup STM32_EXTI16_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI16_PRIORITY) +#error "STM32_IRQ_EXTI16_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI16_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI16_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti16_irq_init(void) { +#if defined(STM32_EXTI16_IS_USED) + nvicEnableVector(STM32_EXTI16_NUMBER, STM32_IRQ_EXTI16_PRIORITY); +#endif +} + +static inline void exti16_irq_deinit(void) { +#if defined(STM32_EXTI16_IS_USED) + nvicDisableVector(STM32_EXTI16_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI16_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI16_HANDLER) +/** + * @brief EXTI[16] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI16_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 16, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI16_ISR) + STM32_EXTI16_ISR(pr, 16); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti17.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti17.inc new file mode 100644 index 0000000..c2bbe0d --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti17.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti17.inc + * @brief Shared EXTI17 handler. + * + * @addtogroup STM32_EXTI17_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI17_PRIORITY) +#error "STM32_IRQ_EXTI17_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI17_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI17_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti17_irq_init(void) { +#if defined(STM32_EXTI17_IS_USED) + nvicEnableVector(STM32_EXTI17_NUMBER, STM32_IRQ_EXTI17_PRIORITY); +#endif +} + +static inline void exti17_irq_deinit(void) { +#if defined(STM32_EXTI17_IS_USED) + nvicDisableVector(STM32_EXTI17_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI17_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI17_HANDLER) +/** + * @brief EXTI[17] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI17_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 17, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI17_ISR) + STM32_EXTI17_ISR(pr, 17); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti18.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti18.inc new file mode 100644 index 0000000..81e8290 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti18.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti18.inc + * @brief Shared EXTI18 handler. + * + * @addtogroup STM32_EXTI18_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI18_PRIORITY) +#error "STM32_IRQ_EXTI18_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI18_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI18_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti18_irq_init(void) { +#if defined(STM32_EXTI18_IS_USED) + nvicEnableVector(STM32_EXTI18_NUMBER, STM32_IRQ_EXTI18_PRIORITY); +#endif +} + +static inline void exti18_irq_deinit(void) { +#if defined(STM32_EXTI18_IS_USED) + nvicDisableVector(STM32_EXTI18_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI18_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI18_HANDLER) +/** + * @brief EXTI[18] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI18_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 18, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI18_ISR) + STM32_EXTI18_ISR(pr, 18); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19-21.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19-21.inc new file mode 100644 index 0000000..670fbdf --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19-21.inc @@ -0,0 +1,104 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti19-21.inc + * @brief Shared EXTI19-21 handler. + * + * @addtogroup STM32_EXTI1921_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI1921_PRIORITY) +#error "STM32_IRQ_EXTI1921_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI1921_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI1921_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti19_exti21_irq_init(void) { +#if defined(STM32_EXTI19_IS_USED) || defined(STM32_EXTI21_IS_USED) + nvicEnableVector(STM32_EXTI1921_NUMBER, STM32_IRQ_EXTI1921_PRIORITY); +#endif +} + +static inline void exti19_exti21_irq_deinit(void) { +#if defined(STM32_EXTI19_IS_USED) || defined(STM32_EXTI21_IS_USED) + nvicDisableVector(STM32_EXTI1921_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI19_IS_USED) || defined(STM32_EXTI21_IS_USED) || \ + defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI1921_HANDLER) +/** + * @brief EXTI[0], EXTI[1] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI1921_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 19) | (1U << 21), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI19_ISR) + STM32_EXTI16_ISR(pr, 19); +#endif +#if defined(STM32_EXTI21_ISR) + STM32_EXTI16_ISR(pr, 21); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19.inc new file mode 100644 index 0000000..ef4b8f8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti19.inc + * @brief Shared EXTI19 handler. + * + * @addtogroup STM32_EXTI19_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI19_PRIORITY) +#error "STM32_IRQ_EXTI19_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI19_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI19_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti19_irq_init(void) { +#if defined(STM32_EXTI19_IS_USED) + nvicEnableVector(STM32_EXTI19_NUMBER, STM32_IRQ_EXTI19_PRIORITY); +#endif +} + +static inline void exti19_irq_deinit(void) { +#if defined(STM32_EXTI19_IS_USED) + nvicDisableVector(STM32_EXTI19_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI19_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI19_HANDLER) +/** + * @brief EXTI[19] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI19_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 19, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI19_ISR) + STM32_EXTI19_ISR(pr, 19); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2.inc new file mode 100644 index 0000000..d5ddc40 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2.inc @@ -0,0 +1,95 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti2.inc + * @brief Shared EXTI2 handler. + * + * @addtogroup STM32_EXTI2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI2_PRIORITY) +#error "STM32_IRQ_EXTI2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI2_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti2_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI2_NUMBER, STM32_IRQ_EXTI2_PRIORITY); +#endif +} + +static inline void exti2_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI2_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI2_HANDLER) +/** + * @brief EXTI[2] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI2_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 2, pr); + + exti_serve_irq(pr, 2); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20.inc new file mode 100644 index 0000000..1d1b6af --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti20.inc + * @brief Shared EXTI20 handler. + * + * @addtogroup STM32_EXTI20_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI20_PRIORITY) +#error "STM32_IRQ_EXTI20_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI20_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI20_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti20_irq_init(void) { +#if defined(STM32_EXTI20_IS_USED) + nvicEnableVector(STM32_EXTI20_NUMBER, STM32_IRQ_EXTI20_PRIORITY); +#endif +} + +static inline void exti20_irq_deinit(void) { +#if defined(STM32_EXTI20_IS_USED) + nvicDisableVector(STM32_EXTI20_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI20_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI20_HANDLER) +/** + * @brief EXTI[20] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI20_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 20, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI20_ISR) + STM32_EXTI20_ISR(pr, 20); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20_21.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20_21.inc new file mode 100644 index 0000000..500f533 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20_21.inc @@ -0,0 +1,104 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti20_21.inc + * @brief Shared EXTI20_21 handler. + * + * @addtogroup STM32_EXTI20_21_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI20_21_PRIORITY) +#error "STM32_IRQ_EXTI20_21_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI20_21_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI20_21_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti20_exti21_irq_init(void) { +#if defined(STM32_EXTI20_IS_USED) || defined(STM32_EXTI21_IS_USED) + nvicEnableVector(STM32_EXTI20_21_NUMBER, STM32_IRQ_EXTI20_21_PRIORITY); +#endif +} + +static inline void exti20_exti21_irq_deinit(void) { +#if defined(STM32_EXTI20_IS_USED) || defined(STM32_EXTI21_IS_USED) + nvicDisableVector(STM32_EXTI20_21_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI20_IS_USED) || defined(STM32_EXTI21_IS_USED) || \ + defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI20_21_HANDLER) +/** + * @brief EXTI[20], EXTI[21] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI20_21_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 20) | (1U << 21), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI20_ISR) + STM32_EXTI20_ISR(pr, 20); +#endif +#if defined(STM32_EXTI21_ISR) + STM32_EXTI21_ISR(pr, 21); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21.inc new file mode 100644 index 0000000..350091b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti21.inc + * @brief Shared EXTI21 handler. + * + * @addtogroup STM32_EXTI21_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI21_PRIORITY) +#error "STM32_IRQ_EXTI21_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI21_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI21_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti21_irq_init(void) { +#if defined(STM32_EXTI21_IS_USED) + nvicEnableVector(STM32_EXTI21_NUMBER, STM32_IRQ_EXTI21_PRIORITY); +#endif +} + +static inline void exti21_irq_deinit(void) { +#if defined(STM32_EXTI21_IS_USED) + nvicDisableVector(STM32_EXTI21_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI21_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI21_HANDLER) +/** + * @brief EXTI[21] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI21_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 21, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI21_ISR) + STM32_EXTI21_ISR(pr, 21); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22-29.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22-29.inc new file mode 100644 index 0000000..95ea587 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22-29.inc @@ -0,0 +1,109 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti21_22-29.inc + * @brief Shared EXTI21_22-29 handler. + * + * @addtogroup STM32_EXTI212229_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI212229_PRIORITY) +#error "STM32_IRQ_EXTI212229_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI212229_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI212229_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti21_exti22_exti29_irq_init(void) { +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) || \ + defined(STM32_EXTI29_IS_USED) + nvicEnableVector(STM32_EXTI212229_NUMBER, STM32_IRQ_EXTI212229_PRIORITY); +#endif +} + +static inline void exti21_exti22_exti29_irq_deinit(void) { +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) || \ + defined(STM32_EXTI29_IS_USED) + nvicDisableVector(STM32_EXTI212229_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) || \ + defined(STM32_EXTI29_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI212229_HANDLER) +/** + * @brief EXTI[21], EXTI[22], EXTI[29] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI212229_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 21) | (1U << 22) | (1U << 29), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI21_ISR) + STM32_EXTI21_ISR(pr, 21); +#endif +#if defined(STM32_EXTI22_ISR) + STM32_EXTI22_ISR(pr, 22); +#endif +#if defined(STM32_EXTI29_ISR) + STM32_EXTI29_ISR(pr, 29); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22.inc new file mode 100644 index 0000000..973efd5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22.inc @@ -0,0 +1,104 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti21_22.inc + * @brief Shared EXTI21_22 handler. + * + * @addtogroup STM32_EXTI21_22_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI21_22_PRIORITY) +#error "STM32_IRQ_EXTI21_22_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI21_22_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI21_22_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti21_22_irq_init(void) { +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) + nvicEnableVector(STM32_EXTI21_22_NUMBER, STM32_IRQ_EXTI21_22_PRIORITY); +#endif +} + +static inline void exti21_22_irq_deinit(void) { +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) + nvicDisableVector(STM32_EXTI21_22_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) || \ + defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI21_22_HANDLER) +/** + * @brief EXTI[21], EXTI[22] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI21_22_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 21) | (1U << 22), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI21_ISR) + STM32_EXTI21_ISR(pr, 21); +#endif +#if defined(STM32_EXTI22_ISR) + STM32_EXTI22_ISR(pr, 22); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti22.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti22.inc new file mode 100644 index 0000000..e958615 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti22.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti22.inc + * @brief Shared EXTI22 handler. + * + * @addtogroup STM32_EXTI22_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI22_PRIORITY) +#error "STM32_IRQ_EXTI22_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI22_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI22_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti22_irq_init(void) { +#if defined(STM32_EXTI22_IS_USED) + nvicEnableVector(STM32_EXTI22_NUMBER, STM32_IRQ_EXTI22_PRIORITY); +#endif +} + +static inline void exti22_irq_deinit(void) { +#if defined(STM32_EXTI22_IS_USED) + nvicDisableVector(STM32_EXTI22_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI22_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI22_HANDLER) +/** + * @brief EXTI[22] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI22_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 22, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI22_ISR) + STM32_EXTI22_ISR(pr, 22); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti23.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti23.inc new file mode 100644 index 0000000..3180234 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti23.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti23.inc + * @brief Shared EXTI23 handler. + * + * @addtogroup STM32_EXTI23_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI23_PRIORITY) +#error "STM32_IRQ_EXTI23_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI23_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI23_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti23_irq_init(void) { +#if defined(STM32_EXTI23_IS_USED) + nvicEnableVector(STM32_EXTI23_NUMBER, STM32_IRQ_EXTI23_PRIORITY); +#endif +} + +static inline void exti23_irq_deinit(void) { +#if defined(STM32_EXTI23_IS_USED) + nvicDisableVector(STM32_EXTI23_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI23_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI23_HANDLER) +/** + * @brief EXTI[23] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI23_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 23, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI23_ISR) + STM32_EXTI23_ISR(pr, 23); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2_3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2_3.inc new file mode 100644 index 0000000..5c8ed9a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2_3.inc @@ -0,0 +1,96 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti2_3.inc + * @brief Shared EXTI2_3 handler. + * + * @addtogroup STM32_EXTI2_3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI2_3_PRIORITY) +#error "STM32_IRQ_EXTI2_3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI2_3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI2_3_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti2_3_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI2_3_NUMBER, STM32_IRQ_EXTI2_3_PRIORITY); +#endif +} + +static inline void exti2_3_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI2_3_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI2_3_HANDLER) +/** + * @brief EXTI[2], EXTI[3] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI2_3_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 2) | (1U << 3), pr); + + exti_serve_irq(pr, 2); + exti_serve_irq(pr, 3); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti3.inc new file mode 100644 index 0000000..9c9be73 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti3.inc @@ -0,0 +1,95 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti3.inc + * @brief Shared EXTI3 handler. + * + * @addtogroup STM32_EXTI3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI3_PRIORITY) +#error "STM32_IRQ_EXTI3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI3_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti3_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI3_NUMBER, STM32_IRQ_EXTI3_PRIORITY); +#endif +} + +static inline void exti3_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI3_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI3_HANDLER) +/** + * @brief EXTI[3] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI3_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 3, pr); + + exti_serve_irq(pr, 3); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti30_32.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti30_32.inc new file mode 100644 index 0000000..b8c1f41 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti30_32.inc @@ -0,0 +1,119 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti30_32.inc + * @brief Shared EXTI30_32 handler. + * + * @addtogroup STM32_EXTI30_32_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI30_32_PRIORITY) +#error "STM32_IRQ_EXTI30_32_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI30_32_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI30_32_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti30_32_irq_init(void) { +#if defined(STM32_EXTI30_IS_USED) || defined(STM32_EXTI31_IS_USED) || \ + defined(STM32_EXTI32_IS_USED) + nvicEnableVector(STM32_EXTI30_32_NUMBER, STM32_IRQ_EXTI30_32_PRIORITY); +#endif +} + +static inline void exti30_32_irq_deinit(void) { +#if defined(STM32_EXTI30_IS_USED) || defined(STM32_EXTI31_IS_USED) || \ + defined(STM32_EXTI32_IS_USED) + nvicDisableVector(STM32_EXTI30_32_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI30_IS_USED) || defined(STM32_EXTI31_IS_USED) || \ + defined(STM32_EXTI32_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI30_32_HANDLER) +/** + * @brief EXTI[16], EXTI[40], EXTI[41] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI164041_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + +#if defined(STM32_EXTI30_IS_USED) || defined(STM32_EXTI31_IS_USED) + extiGetAndClearGroup1((1U << 30) | (1U << 31), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI30_ISR) + STM32_EXTI30_ISR(pr, 30); +#endif +#if defined(STM32_EXTI31_ISR) + STM32_EXTI31_ISR(pr, 31); +#endif +#endif + +#if defined(STM32_EXTI32_IS_USED) + extiGetAndClearGroup2(1U << (32 - 32), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI32_ISR) + STM32_EXTI32_ISR(pr, 32); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti33.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti33.inc new file mode 100644 index 0000000..3ad874f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti33.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti33.inc + * @brief Shared EXTI33 handler. + * + * @addtogroup STM32_EXTI33_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI33_PRIORITY) +#error "STM32_IRQ_EXTI33_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI33_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI33_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti33_irq_init(void) { +#if defined(STM32_EXTI33_IS_USED) + nvicEnableVector(STM32_EXTI33_NUMBER, STM32_IRQ_EXTI33_PRIORITY); +#endif +} + +static inline void exti33_irq_deinit(void) { +#if defined(STM32_EXTI33_IS_USED) + nvicDisableVector(STM32_EXTI33_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI33_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI33_HANDLER) +/** + * @brief EXTI[33] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI33_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup2(1U << (33 - 32), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI33_ISR) + STM32_EXTI33_ISR(pr, (33 - 32)); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4.inc new file mode 100644 index 0000000..a39e83d --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4.inc @@ -0,0 +1,95 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti4.inc + * @brief Shared EXTI4 handler. + * + * @addtogroup STM32_EXTI4_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI4_PRIORITY) +#error "STM32_IRQ_EXTI4_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI4_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI4_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti4_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI4_NUMBER, STM32_IRQ_EXTI4_PRIORITY); +#endif +} + +static inline void exti4_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI4_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI4_HANDLER) +/** + * @brief EXTI[4] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI4_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 4, pr); + + exti_serve_irq(pr, 4); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4_15.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4_15.inc new file mode 100644 index 0000000..ddb6663 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4_15.inc @@ -0,0 +1,108 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti4_15.inc + * @brief Shared EXTI4_15 handler. + * + * @addtogroup STM32_EXTI4_15_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI4_15_PRIORITY) +#error "STM32_IRQ_EXTI4_15_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI4_15_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI4_15_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti4_15_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI4_15_NUMBER, STM32_IRQ_EXTI4_15_PRIORITY); +#endif +} + +static inline void exti4_15_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI4_15_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI4_15_HANDLER) +/** + * @brief EXTI[4]..EXTI[15] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI4_15_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 4) | (1U << 5) | (1U << 6) | (1U << 7) | + (1U << 8) | (1U << 9) | (1U << 10) | (1U << 11) | + (1U << 12) | (1U << 13) | (1U << 14) | (1U << 15), pr); + + exti_serve_irq(pr, 4); + exti_serve_irq(pr, 5); + exti_serve_irq(pr, 6); + exti_serve_irq(pr, 7); + exti_serve_irq(pr, 8); + exti_serve_irq(pr, 9); + exti_serve_irq(pr, 10); + exti_serve_irq(pr, 11); + exti_serve_irq(pr, 12); + exti_serve_irq(pr, 13); + exti_serve_irq(pr, 14); + exti_serve_irq(pr, 15); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti5_9.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti5_9.inc new file mode 100644 index 0000000..9a52fa6 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti5_9.inc @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file EXTIv1/stm32_exti5_9.inc + * @brief Shared EXTI5_9 handler. + * + * @addtogroup STM32_EXTI5_9_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI5_9_PRIORITY) +#error "STM32_IRQ_EXTI5_9_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI5_9_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI5_9_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti5_9_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI5_9_NUMBER, STM32_IRQ_EXTI5_9_PRIORITY); +#endif +} + +static inline void exti5_9_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI5_9_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI5_9_HANDLER) +/** + * @brief EXTI[5]..EXTI[9] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI5_9_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 5) | (1U << 6) | (1U << 7) | (1U << 8) | + (1U << 9), pr); + + exti_serve_irq(pr, 5); + exti_serve_irq(pr, 6); + exti_serve_irq(pr, 7); + exti_serve_irq(pr, 8); + exti_serve_irq(pr, 9); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/driver.mk new file mode 100644 index 0000000..734c3a0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/FDCANv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c new file mode 100644 index 0000000..38e5ff6 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c @@ -0,0 +1,566 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file FDCANv1/hal_can_lld.c + * @brief STM32 CAN subsystem low level driver source. + * + * @addtogroup CAN + * @{ + */ + +#include "hal.h" + +#if HAL_USE_CAN || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* Filter Standard Element Size in bytes.*/ +#define SRAMCAN_FLS_SIZE (1U * 4U) + +/* Filter Extended Element Size in bytes.*/ +#define SRAMCAN_FLE_SIZE (2U * 4U) + +/* RX FIFO 0 Elements Size in bytes.*/ +#define SRAMCAN_RF0_SIZE (18U * 4U) + +/* RX FIFO 1 Elements Size in bytes.*/ +#define SRAMCAN_RF1_SIZE (18U * 4U) + +/* RX Buffer Size in bytes.*/ +#define SRAMCAN_RB_SIZE (18U * 4U) + +/* TX Event FIFO Elements Size in bytes.*/ +#define SRAMCAN_TEF_SIZE (2U * 4U) + +/* TX FIFO/Queue Elements Size in bytes.*/ +#define SRAMCAN_TB_SIZE (18U * 4U) + +/* Trigger Memory Size in bytes.*/ +#define SRAMCAN_TM_SIZE (2U * 4U) + +/* Filter List Standard Start Address.*/ +#define SRAMCAN_FLSSA ((uint32_t)0) + +/* Filter List Extended Start Address.*/ +#define SRAMCAN_FLESA ((uint32_t)(SRAMCAN_FLSSA + \ + (STM32_FDCAN_FLS_NBR * SRAMCAN_FLS_SIZE))) + +/* RX FIFO 0 Start Address.*/ +#define SRAMCAN_RF0SA ((uint32_t)(SRAMCAN_FLESA + \ + (STM32_FDCAN_FLE_NBR * SRAMCAN_FLE_SIZE))) + +/* RX FIFO 1 Start Address.*/ +#define SRAMCAN_RF1SA ((uint32_t)(SRAMCAN_RF0SA + \ + (STM32_FDCAN_RF0_NBR * SRAMCAN_RF0_SIZE))) + +/* RX Buffer Start Address.*/ +#define SRAMCAN_RBSA ((uint32_t)(SRAMCAN_RF1SA + \ + (STM32_FDCAN_RF1_NBR * SRAMCAN_RF1_SIZE))) + +/* TX Event FIFO Start Address.*/ +#define SRAMCAN_TEFSA ((uint32_t)(SRAMCAN_RBSA + \ + (STM32_FDCAN_RB_NBR * SRAMCAN_RB_SIZE))) + +/* TX Buffers Start Address.*/ +#define SRAMCAN_TBSA ((uint32_t)(SRAMCAN_TEFSA + \ + (STM32_FDCAN_TEF_NBR * SRAMCAN_TEF_SIZE))) + +/* Trigger Memory Start Address.*/ +#define SRAMCAN_TMSA ((uint32_t)(SRAMCAN_TBSA + \ + (STM32_FDCAN_TB_NBR * SRAMCAN_TB_SIZE))) + +/* Message RAM size.*/ +#define SRAMCAN_SIZE ((uint32_t)(SRAMCAN_TMSA + \ + (STM32_FDCAN_TM_NBR * SRAMCAN_TM_SIZE))) + + +#define TIMEOUT_INIT_MS 250U +#define TIMEOUT_CSA_MS 250U + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief CAN1 driver identifier.*/ +#if STM32_CAN_USE_FDCAN1 || defined(__DOXYGEN__) +CANDriver CAND1; +#endif + +/** @brief CAN2 driver identifier.*/ +#if STM32_CAN_USE_FDCAN2 || defined(__DOXYGEN__) +CANDriver CAND2; +#endif + +/** @brief CAN3 driver identifier.*/ +#if STM32_CAN_USE_FDCAN3 || defined(__DOXYGEN__) +CANDriver CAND3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const uint8_t dlc_to_bytes[] = { + 0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, + 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U +}; + +static uint32_t canclk; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static bool fdcan_clock_stop(CANDriver *canp) { + systime_t start, end; + + /* Requesting clock stop then waiting for it to happen.*/ + canp->fdcan->CCCR |= FDCAN_CCCR_CSR; + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, TIME_MS2I(TIMEOUT_INIT_MS)); + while ((canp->fdcan->CCCR & FDCAN_CCCR_CSA) != 0U) { + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + return true; + } + osalThreadSleepS(1); + } + + return false; +} + +static bool fdcan_init_mode(CANDriver *canp) { + systime_t start, end; + + /* Going in initialization mode then waiting for it to happen.*/ + canp->fdcan->CCCR |= FDCAN_CCCR_INIT; + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, TIME_MS2I(TIMEOUT_INIT_MS)); + while ((canp->fdcan->CCCR & FDCAN_CCCR_INIT) == 0U) { + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + return true; + } + osalThreadSleepS(1); + } + + return false; +} + +static bool fdcan_active_mode(CANDriver *canp) { + systime_t start, end; + + /* Going in initialization mode then waiting for it to happen.*/ + canp->fdcan->CCCR &= ~FDCAN_CCCR_INIT; + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, TIME_MS2I(TIMEOUT_INIT_MS)); + while ((canp->fdcan->CCCR & FDCAN_CCCR_INIT) != 0U) { + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + return true; + } + osalThreadSleepS(1); + } + + return false; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level CAN driver initialization. + * + * @notapi + */ +void can_lld_init(void) { + + canclk = 0U; + + /* Unit reset.*/ + rccResetFDCAN(); + +#if STM32_CAN_USE_FDCAN1 + /* Driver initialization.*/ + canObjectInit(&CAND1); + CAND1.fdcan = FDCAN1; + CAND1.ram_base = (uint32_t *) (SRAMCAN_BASE + 0U * SRAMCAN_SIZE); +#endif + +#if STM32_CAN_USE_FDCAN2 + /* Driver initialization.*/ + canObjectInit(&CAND2); + CAND2.fdcan = FDCAN2; + CAND2.ram_base = (uint32_t *) (SRAMCAN_BASE + 1U * SRAMCAN_SIZE); +#endif + +#if STM32_CAN_USE_FDCAN3 + /* Driver initialization.*/ + canObjectInit(&CAND3); + CAND3.fdcan = FDCAN3; + CAND3.ram_base = (uint32_t *) (SRAMCAN_BASE + 2U * SRAMCAN_SIZE); +#endif +} + +/** + * @brief Configures and activates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + * @return The operation result. + * @retval false if the operation succeeded. + * @retval true if the operation failed. + * + * @notapi + */ +bool can_lld_start(CANDriver *canp) { + + /* Clock activation.*/ + rccEnableFDCAN(true); + + /* If it is the first activation then performing some extra + initializations.*/ + if (canclk == 0U) { + for (uint32_t *wp = canp->ram_base; + wp < canp->ram_base + SRAMCAN_SIZE; + wp += 1U) { + *wp = (uint32_t)0U; + } + } + +#if STM32_CAN_USE_FDCAN1 + if (&CAND1 == canp) { + canclk |= 1U; + } +#endif + +#if STM32_CAN_USE_FDCAN2 + if (&CAND2 == canp) { + canclk |= 2U; + } +#endif + +#if STM32_CAN_USE_FDCAN3 + if (&CAND3 == canp) { + canclk |= 4U; + } +#endif + + /* Requesting clock stop.*/ + if (fdcan_clock_stop(canp)) { + osalDbgAssert(false, "CAN clock stop failed, check clocks and pin config"); + return true; + } + + /* Going in initialization mode.*/ + if (fdcan_init_mode(canp)) { + osalDbgAssert(false, "CAN initialization failed, check clocks and pin config"); + return true; + } + + /* Configuration can be performed now.*/ + canp->fdcan->CCCR |= FDCAN_CCCR_CCE; + + /* Setting up operation mode except driver-controlled bits.*/ + canp->fdcan->DBTP = canp->config->DBTP; + canp->fdcan->CCCR = canp->config->CCCR & ~(FDCAN_CCCR_CSR | FDCAN_CCCR_CSA | + FDCAN_CCCR_CCE | FDCAN_CCCR_INIT); + canp->fdcan->TEST = canp->config->TEST; + + /* Enabling interrupts, only using interrupt zero.*/ + canp->fdcan->IR = (uint32_t)-1; + canp->fdcan->IE = FDCAN_IE_RF1NE | FDCAN_IE_RF1LE | + FDCAN_IE_RF0NE | FDCAN_IE_RF0LE | + FDCAN_IE_TCE; + canp->fdcan->ILE = FDCAN_ILE_EINT0; + + /* Going in active mode.*/ + if (fdcan_active_mode(canp)) { + osalDbgAssert(false, "CAN initialization failed, check clocks and pin config"); + return true; + } + + return false; +} + +/** + * @brief Deactivates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_stop(CANDriver *canp) { + + /* If in ready state then disables the CAN peripheral.*/ + if (canp->state == CAN_READY) { + /* Disabling and clearing interrupts.*/ + canp->fdcan->IE = 0U; + canp->fdcan->IR = (uint32_t)-1; + canp->fdcan->ILE = 0U; + + /* Disables the peripheral.*/ + (void) fdcan_clock_stop(canp); + +#if STM32_CAN_USE_FDCAN1 + if (&CAND1 == canp) { + canclk &= ~1U; + } +#endif + +#if STM32_CAN_USE_FDCAN2 + if (&CAND2 == canp) { + canclk &= ~2U; + } +#endif + +#if STM32_CAN_USE_FDCAN3 + if (&CAND3 == canp) { + canclk &= ~4U; + } +#endif + + if (canclk == 0U) { + rccDisableFDCAN(); + } + } +} + +/** + * @brief Determines whether a frame can be transmitted. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @return The queue space availability. + * @retval false no space in the transmit queue. + * @retval true transmit slot available. + * + * @notapi + */ +bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) { + + (void)mailbox; + + return (bool)((canp->fdcan->TXFQS & FDCAN_TXFQS_TFQF) == 0U); +} + +/** + * @brief Inserts a frame into the transmit queue. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] ctfp pointer to the CAN frame to be transmitted + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @notapi + */ +void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *ctfp) { + uint32_t *tx_address; + + (void)mailbox; + + osalDbgCheck(dlc_to_bytes[ctfp->DLC] <= CAN_MAX_DLC_BYTES); + + /* Writing frame.*/ + tx_address = canp->ram_base + (SRAMCAN_TBSA / sizeof (uint32_t)); + *tx_address++ = ctfp->header32[0]; + *tx_address++ = ctfp->header32[1]; + for (unsigned i = 0U; i < dlc_to_bytes[ctfp->DLC]; i += 4U) { + *tx_address++ = ctfp->data32[i / 4U]; + } +} + +/** + * @brief Determines whether a frame has been received. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @return The queue space availability. + * @retval false no space in the transmit queue. + * @retval true transmit slot available. + * + * @notapi + */ +bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) { + + switch (mailbox) { + case CAN_ANY_MAILBOX: + return can_lld_is_rx_nonempty(canp, 1U) || + can_lld_is_rx_nonempty(canp, 2U); + case 1: + return (bool)((canp->fdcan->RXF0S & FDCAN_RXF0S_F0FL) != 0U); + case 2: + return (bool)((canp->fdcan->RXF1S & FDCAN_RXF1S_F1FL) != 0U); + default: + return false; + } +} + +/** + * @brief Receives a frame from the input queue. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * @param[out] crfp pointer to the buffer where the CAN frame is copied + * + * @notapi + */ +void can_lld_receive(CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp) { + uint32_t get_index; + uint32_t *rx_address; + + if (mailbox == CAN_ANY_MAILBOX) { + if (can_lld_is_rx_nonempty(canp, 1U)) { + mailbox = 1U; + } + else if (can_lld_is_rx_nonempty(canp, 2U)) { + mailbox = 2U; + } + else { + return; + } + } + + /* GET index, add it and the length to the rx_address.*/ + get_index = (canp->fdcan->RXF0S & FDCAN_RXF0S_F0GI_Msk) >> FDCAN_RXF0S_F0GI_Pos; + rx_address = canp->ram_base + (SRAMCAN_RF0SA + + (get_index * SRAMCAN_RF0_SIZE)) / sizeof (uint32_t); + crfp->header32[0] = *rx_address++; + crfp->header32[1] = *rx_address++; + + /* Copy message from FDCAN peripheral's SRAM to structure. RAM is restricted + to word aligned accesses, so up to 3 extra bytes may be copied.*/ + for (unsigned i = 0U; i < dlc_to_bytes[crfp->DLC]; i += 4U) { + crfp->data32[i / 4U] = *rx_address++; + } + + /* Acknowledge receipt by writing the get-index to the acknowledge + register RXFxA then re-enable RX FIFO message arrived interrupt once + the FIFO is emptied.*/ + if (mailbox == 1U) { + uint32_t rxf0a = canp->fdcan->RXF0A; + rxf0a &= ~FDCAN_RXF0A_F0AI_Msk; + rxf0a |= get_index << FDCAN_RXF0A_F0AI_Pos; + canp->fdcan->RXF0A = rxf0a; + + if (!can_lld_is_rx_nonempty(canp, mailbox)) { +// canp->fdcan->IR = FDCAN_IR_RF0N; + canp->fdcan->IE |= FDCAN_IE_RF0NE; + } + } + else { + uint32_t rxf1a = canp->fdcan->RXF1A; + rxf1a &= ~FDCAN_RXF1A_F1AI_Msk; + rxf1a |= get_index << FDCAN_RXF1A_F1AI_Pos; + canp->fdcan->RXF1A = rxf1a; + + if (!can_lld_is_rx_nonempty(canp, mailbox)) { +// canp->fdcan->IR = FDCAN_IR_RF1N; + canp->fdcan->IE |= FDCAN_IE_RF1NE; + } + } +} + +/** + * @brief Tries to abort an ongoing transmission. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number + * + * @notapi + */ +void can_lld_abort(CANDriver *canp, canmbx_t mailbox) { + + (void)canp; + (void)mailbox; +} + +#if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) +/** + * @brief Enters the sleep mode. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_sleep(CANDriver *canp) { + + (void)canp; +} + +/** + * @brief Enforces leaving the sleep mode. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_wakeup(CANDriver *canp) { + + (void)canp; +} +#endif /* CAN_USE_SLEEP_MODE */ + +/** + * @brief FDCAN IRQ0 service routine. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_serve_interrupt(CANDriver *canp) { + uint32_t ir; + + /* Getting and clearing active IRQs.*/ + ir = canp->fdcan->IR; + canp->fdcan->IR = ir; + + /* RX events.*/ + if ((ir & FDCAN_IR_RF0N) != 0U) { + /* Disabling this source until the queue is emptied.*/ + canp->fdcan->IE &= ~FDCAN_IE_RF0NE; + _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(1U)); + } + if ((ir & FDCAN_IR_RF1N) != 0U) { + /* Disabling this source until the queue is emptied.*/ + canp->fdcan->IE &= ~FDCAN_IE_RF1NE; + _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(2U)); + } + + /* Overflow events.*/ + if ((ir & FDCAN_IR_RF0N) != 0U) { + _can_error_isr(canp, CAN_OVERFLOW_ERROR); + } + + /* TX events.*/ + if ((ir & FDCAN_IR_TC) != 0U) { + eventflags_t flags = 0U; + + flags |= 1U; + _can_tx_empty_isr(canp, flags); + } +} + +#endif /* HAL_USE_CAN */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h new file mode 100644 index 0000000..eb02c34 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h @@ -0,0 +1,470 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file FDCANv1/hal_can_lld.h + * @brief STM32 CAN subsystem low level driver header. + * + * @addtogroup CAN + * @{ + */ + +#ifndef HAL_CAN_LLD_H +#define HAL_CAN_LLD_H + +#if HAL_USE_CAN || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Maximum number of bytes in data of CAN packets. + */ +#define CAN_MAX_DLC_BYTES 64 + +/** + * @brief Number of transmit mailboxes. + */ +#define CAN_TX_MAILBOXES 1 + +/** + * @brief Number of receive mailboxes. + */ +#define CAN_RX_MAILBOXES 2 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief CAN1 driver enable switch. + * @details If set to @p TRUE the support for FDCAN1 is included. + */ +#if !defined(STM32_CAN_USE_FDCAN1) || defined(__DOXYGEN__) +#define STM32_CAN_USE_FDCAN1 FALSE +#endif + +/** + * @brief CAN2 driver enable switch. + * @details If set to @p TRUE the support for FDCAN2 is included. + */ +#if !defined(STM32_CAN_USE_FDCAN2) || defined(__DOXYGEN__) +#define STM32_CAN_USE_FDCAN2 FALSE +#endif + +/** + * @brief CAN3 driver enable switch. + * @details If set to @p TRUE the support for FDCAN3 is included. + */ +#if !defined(STM32_CAN_USE_FDCAN3) || defined(__DOXYGEN__) +#define STM32_CAN_USE_FDCAN3 FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_FDCAN1) +#error "STM32_HAS_FDCAN1 not defined in registry" +#endif + +#if !defined(STM32_HAS_FDCAN2) +#error "STM32_HAS_FDCAN2 not defined in registry" +#endif + +#if !defined(STM32_HAS_FDCAN3) +#error "STM32_HAS_FDCAN3 not defined in registry" +#endif + +#if STM32_CAN_USE_FDCAN1 && !STM32_HAS_FDCAN1 +#error "FDCAN1 not present in the selected device" +#endif + +#if STM32_CAN_USE_FDCAN2 && !STM32_HAS_FDCAN2 +#error "FDCAN2 not present in the selected device" +#endif + +#if STM32_CAN_USE_FDCAN3 && !STM32_HAS_FDCAN3 +#error "FDCAN3 not present in the selected device" +#endif + +#if !STM32_CAN_USE_FDCAN1 && !STM32_CAN_USE_FDCAN2 && !STM32_CAN_USE_FDCAN3 +#error "CAN driver activated but no FDCAN peripheral assigned" +#endif + +#if !defined(STM32_FDCAN_FLS_NBR) +#error "STM32_FDCAN_FLS_NBR not defined in registry" +#endif + +#if !defined(STM32_FDCAN_FLE_NBR) +#error "STM32_FDCAN_FLE_NBR not defined in registry" +#endif + +#if !defined(STM32_FDCAN_RF0_NBR) +#error "STM32_FDCAN_RF0_NBR not defined in registry" +#endif + +#if !defined(STM32_FDCAN_RF1_NBR) +#error "STM32_FDCAN_RF1_NBR not defined in registry" +#endif + +#if !defined(STM32_FDCAN_RB_NBR) +#error "STM32_FDCAN_RB_NBR not defined in registry" +#endif + +#if !defined(STM32_FDCAN_TEF_NBR) +#error "STM32_FDCAN_TEF_NBR not defined in registry" +#endif + +#if !defined(STM32_FDCAN_TB_NBR) +#error "STM32_FDCAN_TB_NBR not defined in registry" +#endif + +#if !defined(STM32_FDCAN_TM_NBR) +#error "STM32_FDCAN_TM_NBR not defined in registry" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an CAN driver. + */ +typedef struct CANDriver CANDriver; + +/** + * @brief Type of a transmission mailbox index. + */ +typedef uint32_t canmbx_t; + +#if (CAN_ENFORCE_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) +/** + * @brief Type of a CAN notification callback. + * + * @param[in] canp pointer to the @p CANDriver object triggering the + * callback + * @param[in] flags flags associated to the mailbox callback + */ +typedef void (*can_callback_t)(CANDriver *canp, uint32_t flags); +#endif + +/** + * @brief CAN transmission frame. + * @note Accessing the frame data as word16 or word32 is not portable + * because machine data endianness, it can be still useful for a + * quick filling. + */ +typedef struct { + /** + * @brief Frame header. + */ + union { + struct { + union { + uint32_t EID:29; /**< @brief Extended identifier. */ + struct { + uint32_t _R1:18; /**< @brief Reserved for offset. */ + uint32_t SID:11; /**< @brief Standard identifier. */ + uint32_t RTR:1; /**< @brief Remote transmit request.*/ + uint32_t XTD:1; /**< @brief Extended identifier. */ + uint32_t ESI:1; /**< @brief Error state indicator. */ + }; + }; + uint32_t _R2:16; + uint32_t DLC:4; /**< @brief Data length code. */ + uint32_t BPS:1; /**< @brief Accepted non-matching + frame. */ + uint32_t FDF:1; /**< @brief FDCAN frame format. */ + uint32_t _R3:1; + uint32_t EFC:1; /**< @brief Event FIFO control. */ + uint32_t MM:8; /**< @brief Message event marker. */ + }; + uint32_t header32[2]; + }; + /** + * @brief Frame data. + */ + union { + uint8_t data8[CAN_MAX_DLC_BYTES]; + uint16_t data16[CAN_MAX_DLC_BYTES / 2]; + uint32_t data32[CAN_MAX_DLC_BYTES / 4]; + }; +} CANTxFrame; + +/** + * @brief CAN received frame. + * @note Accessing the frame data as word16 or word32 is not portable + * because machine data endianness, it can be still useful for a + * quick filling. + */ +typedef struct { + /** + * @brief Frame header. + */ + struct { + union { + uint32_t EID:29; /**< @brief Extended Identifier. */ + struct { + uint32_t _R1:18; + uint32_t SID:11; /**< @brief Standard identifier. */ + uint32_t RTR:1; /**< @brief Remote transmit request.*/ + uint32_t XTD:1; /**< @brief Extended identifier. */ + uint32_t ESI:1; /**< @brief Error state indicator. */ + }; + }; + uint16_t RXTS:16; /**< @brief TX time stamp. */ + uint8_t DLC:4; /**< @brief Data length code. */ + uint8_t BRS:1; /**< @brief Bit rate switch. */ + uint8_t FDF:1; /**< @brief FDCAN frame format. */ + uint8_t _R2:2; + uint8_t FIDX:7; /**< @brief Filter index. */ + uint8_t ANMF:1; /**< @brief Accepted non-matching + frame. */ + }; + uint32_t header32[2]; + /** + * @brief Frame data. + */ + union { + uint8_t data8[CAN_MAX_DLC_BYTES]; + uint16_t data16[CAN_MAX_DLC_BYTES / 2]; + uint32_t data32[CAN_MAX_DLC_BYTES / 4]; + }; +} CANRxFrame; + +/** + * @brief CAN standard filter. + * @note Accessing the frame data as word16 or word32 is not portable + * because machine data endianness, it can be still useful for a + * quick filling. + */ +typedef struct { + union { + struct { + uint16_t SFID2:11; + uint8_t _R1:5; + uint16_t SFID1:11; + uint8_t SFEC:3; + uint8_t SFT:2; + }; + union { + uint32_t data32; + uint16_t data16[2]; + uint8_t data8[4]; + }; + }; +} CANRxStandardFilter; + + +/** + * @brief CAN extended filter. + * @note Accessing the frame data as word16 or word32 is not portable + * because machine data endianness, it can be still useful for a + * quick filling. +*/ +typedef struct { + union { + struct { + uint32_t EFID1:29; + uint8_t EFEC:3; + uint32_t EFID2:29; + uint8_t _R1:1; + uint8_t EFT:2; + }; + union { + uint32_t data32[2]; + uint16_t data16[4]; + uint8_t data8[8]; + }; + }; +} CANRxExtendedFilter; + + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief Data bit timing and prescaler register. + */ + uint32_t DBTP; + /** + * @brief CC control register. + */ + uint32_t CCCR; + /** + * @brief Test configuration register. + */ + uint32_t TEST; +} CANConfig; + +/** + * @brief Structure representing an CAN driver. + */ +struct CANDriver { + /** + * @brief Driver state. + */ + canstate_t state; + /** + * @brief Current configuration data. + */ + const CANConfig *config; + /** + * @brief Transmission threads queue. + */ + threads_queue_t txqueue; + /** + * @brief Receive threads queue. + */ + threads_queue_t rxqueue; +#if (CAN_ENFORCE_USE_CALLBACKS == FALSE) || defined(__DOXYGEN__) + /** + * @brief One or more frames become available. + * @note After broadcasting this event it will not be broadcasted again + * until the received frames queue has been completely emptied. It + * is not broadcasted for each received frame. It is + * responsibility of the application to empty the queue by + * repeatedly invoking @p canReceive() when listening to this event. + * This behavior minimizes the interrupt served by the system + * because CAN traffic. + * @note The flags associated to the listeners will indicate which + * receive mailboxes become non-empty. + */ + event_source_t rxfull_event; + /** + * @brief One or more transmission mailbox become available. + * @note The flags associated to the listeners will indicate which + * transmit mailboxes become empty. + * @note The upper 16 bits are transmission error flags associated + * to the transmit mailboxes. + */ + event_source_t txempty_event; + /** + * @brief A CAN bus error happened. + * @note The flags associated to the listeners will indicate that + * receive error(s) have occurred. + * @note In this implementation the upper 16 bits are filled with the + * unprocessed content of the ESR register. + */ + event_source_t error_event; +#if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__) + /** + * @brief Entering sleep state event. + */ + event_source_t sleep_event; + /** + * @brief Exiting sleep state event. + */ + event_source_t wakeup_event; +#endif /* CAN_USE_SLEEP_MODE */ +#else /* CAN_ENFORCE_USE_CALLBACKS == TRUE */ + /** + * @brief One or more frames become available. + * @note After calling this function it will not be called again + * until the received frames queue has been completely emptied. It + * is not called for each received frame. It is + * responsibility of the application to empty the queue by + * repeatedly invoking @p chTryReceiveI(). + * This behavior minimizes the interrupt served by the system + * because CAN traffic. + */ + can_callback_t rxfull_cb; + /** + * @brief One or more transmission mailbox become available. + * @note The flags associated to the callback will indicate which + * transmit mailboxes become empty. + */ + can_callback_t txempty_cb; + /** + * @brief A CAN bus error happened. + */ + can_callback_t error_cb; +#if (CAN_USE_SLEEP_MODE == TRUE) || defined (__DOXYGEN__) + /** + * @brief Exiting sleep state. + */ + can_callback_t wakeup_cb; +#endif +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the CAN registers. + */ + FDCAN_GlobalTypeDef *fdcan; + /** + * @brief Pointer to FDCAN RAM base. + */ + uint32_t *ram_base; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_CAN_USE_FDCAN1 && !defined(__DOXYGEN__) +extern CANDriver CAND1; +#endif + +#if STM32_CAN_USE_FDCAN2 && !defined(__DOXYGEN__) +extern CANDriver CAND2; +#endif + +#if STM32_CAN_USE_FDCAN3 && !defined(__DOXYGEN__) +extern CANDriver CAND3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void can_lld_init(void); + bool can_lld_start(CANDriver *canp); + void can_lld_stop(CANDriver *canp); + bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox); + void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *crfp); + bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox); + void can_lld_receive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *ctfp); + void can_lld_abort(CANDriver *canp, + canmbx_t mailbox); +#if CAN_USE_SLEEP_MODE + void can_lld_sleep(CANDriver *canp); + void can_lld_wakeup(CANDriver *canp); +#endif /* CAN_USE_SLEEP_MODE */ + void can_lld_serve_interrupt(CANDriver *canp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_CAN */ + +#endif /* HAL_CAN_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan1.inc new file mode 100644 index 0000000..4f6fd37 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan1.inc @@ -0,0 +1,106 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file FDCANv1/stm32_fdcan1.inc + * @brief Shared FDCAN1 handler. + * + * @addtogroup STM32_FDCAN1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_FDCAN1) +#error "STM32_HAS_FDCAN1 not defined in registry" +#endif + +#if STM32_HAS_FDCAN1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_FDCAN1_PRIORITY) +#error "STM32_IRQ_FDCAN1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_FDCAN1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_FDCAN1_PRIORITY" +#endif + +#endif /* STM32_HAS_FDCAN1 */ + +/* Other checks.*/ +#if HAL_USE_CAN && STM32_CAN_USE_FDCAN1 +#define STM32_FDCAN1_IS_USED TRUE +#else +#define STM32_FDCAN1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void fdcan1_irq_init(void) { +#if STM32_FDCAN1_IS_USED + nvicEnableVector(STM32_FDCAN1_IT0_NUMBER, STM32_IRQ_FDCAN1_PRIORITY); +#endif +} + +static inline void fdcan1_irq_deinit(void) { +#if STM32_FDCAN1_IS_USED + nvicDisableVector(STM32_FDCAN1_IT0_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_FDCAN1_IS_USED|| defined(__DOXYGEN__) +/** + * @brief FDCAN1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_FDCAN1_IT0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_serve_interrupt(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan2.inc new file mode 100644 index 0000000..2226260 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan2.inc @@ -0,0 +1,106 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file FDCANv1/stm32_fdcan2.inc + * @brief Shared FDCAN2 handler. + * + * @addtogroup STM32_FDCAN2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_FDCAN2) +#error "STM32_HAS_FDCAN2 not defined in registry" +#endif + +#if STM32_HAS_FDCAN2 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_FDCAN2_PRIORITY) +#error "STM32_IRQ_FDCAN2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_FDCAN2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_FDCAN2_PRIORITY" +#endif + +#endif /* STM32_HAS_FDCAN2 */ + +/* Other checks.*/ +#if HAL_USE_CAN && STM32_CAN_USE_FDCAN2 +#define STM32_FDCAN2_IS_USED TRUE +#else +#define STM32_FDCAN2_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void fdcan2_irq_init(void) { +#if STM32_FDCAN2_IS_USED + nvicEnableVector(STM32_FDCAN2_IT0_NUMBER, STM32_IRQ_FDCAN2_PRIORITY); +#endif +} + +static inline void fdcan2_irq_deinit(void) { +#if STM32_FDCAN2_IS_USED + nvicDisableVector(STM32_FDCAN2_IT0_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_FDCAN2_IS_USED|| defined(__DOXYGEN__) +/** + * @brief FDCAN2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_FDCAN2_IT0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_serve_interrupt(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan3.inc new file mode 100644 index 0000000..153a29f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan3.inc @@ -0,0 +1,106 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file FDCANv1/stm32_fdcan3.inc + * @brief Shared FDCAN3 handler. + * + * @addtogroup STM32_FDCAN3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_FDCAN3) +#error "STM32_HAS_FDCAN3 not defined in registry" +#endif + +#if STM32_HAS_FDCAN3 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_FDCAN3_PRIORITY) +#error "STM32_IRQ_FDCAN3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_FDCAN3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_FDCAN3_PRIORITY" +#endif + +#endif /* STM32_HAS_FDCAN3 */ + +/* Other checks.*/ +#if HAL_USE_CAN && STM32_CAN_USE_FDCAN3 +#define STM32_FDCAN3_IS_USED TRUE +#else +#define STM32_FDCAN3_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void fdcan3_irq_init(void) { +#if STM32_FDCAN3_IS_USED + nvicEnableVector(STM32_FDCAN3_IT0_NUMBER, STM32_IRQ_FDCAN3_PRIORITY); +#endif +} + +static inline void fdcan3_irq_deinit(void) { +#if STM32_FDCAN3_IS_USED + nvicDisableVector(STM32_FDCAN3_IT0_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_FDCAN3_IS_USED|| defined(__DOXYGEN__) +/** + * @brief FDCAN3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_FDCAN3_IT0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_serve_interrupt(&CAND3); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/driver.mk new file mode 100644 index 0000000..5e428a7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c new file mode 100644 index 0000000..99106bc --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c @@ -0,0 +1,300 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file GPIOv1/hal_pal_lld.c + * @brief STM32 PAL low level driver code. + * + * @addtogroup PAL + * @{ + */ + +#include "hal.h" + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if STM32_HAS_GPIOG +#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \ + RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \ + RCC_APB2ENR_IOPEEN | RCC_APB2ENR_IOPFEN | \ + RCC_APB2ENR_IOPGEN | RCC_APB2ENR_AFIOEN) +#elif STM32_HAS_GPIOE +#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \ + RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \ + RCC_APB2ENR_IOPEEN | RCC_APB2ENR_AFIOEN) +#else +#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \ + RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \ + RCC_APB2ENR_AFIOEN) +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) +/** + * @brief Event records for the 16 GPIO EXTI channels. + */ +palevent_t _pal_events[16]; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief STM32 I/O ports configuration. + * @details Ports A-D(E, F, G) clocks enabled, AFIO clock enabled. + * + * @param[in] config the STM32 ports configuration + * + * @notapi + */ +void _pal_lld_init(const PALConfig *config) { + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) + unsigned i; + + for (i = 0; i < 16; i++) { + _pal_init_event(i); + } +#endif + + /* + * Enables the GPIO related clocks. + */ + rccEnableAPB2(APB2_EN_MASK, true); + + /* + * Initial GPIO setup. + */ + GPIOA->ODR = config->PAData.odr; + GPIOA->CRH = config->PAData.crh; + GPIOA->CRL = config->PAData.crl; + GPIOB->ODR = config->PBData.odr; + GPIOB->CRH = config->PBData.crh; + GPIOB->CRL = config->PBData.crl; + GPIOC->ODR = config->PCData.odr; + GPIOC->CRH = config->PCData.crh; + GPIOC->CRL = config->PCData.crl; + GPIOD->ODR = config->PDData.odr; + GPIOD->CRH = config->PDData.crh; + GPIOD->CRL = config->PDData.crl; +#if STM32_HAS_GPIOE || defined(__DOXYGEN__) + GPIOE->ODR = config->PEData.odr; + GPIOE->CRH = config->PEData.crh; + GPIOE->CRL = config->PEData.crl; +#if STM32_HAS_GPIOF || defined(__DOXYGEN__) + GPIOF->ODR = config->PFData.odr; + GPIOF->CRH = config->PFData.crh; + GPIOF->CRL = config->PFData.crl; +#if STM32_HAS_GPIOG || defined(__DOXYGEN__) + GPIOG->ODR = config->PGData.odr; + GPIOG->CRH = config->PGData.crh; + GPIOG->CRL = config->PGData.crl; +#endif +#endif +#endif +} + +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note @p PAL_MODE_UNCONNECTED is implemented as push pull output at 2MHz. + * @note Writing on pads programmed as pull-up or pull-down has the side + * effect to modify the resistor setting because the output latched + * data is used for the resistor selection. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the mode + * + * @notapi + */ +void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode) { + static const uint8_t cfgtab[] = { + 4, /* PAL_MODE_RESET, implemented as input.*/ + 2, /* PAL_MODE_UNCONNECTED, implemented as push pull output 2MHz.*/ + 4, /* PAL_MODE_INPUT */ + 8, /* PAL_MODE_INPUT_PULLUP */ + 8, /* PAL_MODE_INPUT_PULLDOWN */ + 0, /* PAL_MODE_INPUT_ANALOG */ + 3, /* PAL_MODE_OUTPUT_PUSHPULL, 50MHz.*/ + 7, /* PAL_MODE_OUTPUT_OPENDRAIN, 50MHz.*/ + 8, /* Reserved.*/ + 8, /* Reserved.*/ + 8, /* Reserved.*/ + 8, /* Reserved.*/ + 8, /* Reserved.*/ + 8, /* Reserved.*/ + 8, /* Reserved.*/ + 8, /* Reserved.*/ + 0xB, /* PAL_MODE_STM32_ALTERNATE_PUSHPULL, 50MHz.*/ + 0xF, /* PAL_MODE_STM32_ALTERNATE_OPENDRAIN, 50MHz.*/ + }; + uint32_t mh, ml, crh, crl, cfg; + unsigned i; + + if (mode == PAL_MODE_INPUT_PULLUP) + port->BSRR = mask; + else if (mode == PAL_MODE_INPUT_PULLDOWN) + port->BRR = mask; + cfg = cfgtab[mode]; + mh = ml = crh = crl = 0; + for (i = 0; i < 8; i++) { + ml <<= 4; + mh <<= 4; + crl <<= 4; + crh <<= 4; + if ((mask & 0x0080) == 0) + ml |= 0xf; + else + crl |= cfg; + if ((mask & 0x8000) == 0) + mh |= 0xf; + else + crh |= cfg; + mask <<= 1; + } + port->CRH = (port->CRH & mh) | crh; + port->CRL = (port->CRL & ml) | crl; +} + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) +/** + * @brief Pad event enable. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] mode pad event mode + * + * @notapi + */ +void _pal_lld_enablepadevent(ioportid_t port, + iopadid_t pad, + ioeventmode_t mode) { + + uint32_t padmask, cridx, croff, crmask, portidx; + + /* Mask of the pad.*/ + padmask = 1U << (uint32_t)pad; + + /* Multiple channel setting of the same channel not allowed, first disable + it. This is done because on STM32 the same channel cannot be mapped on + multiple ports.*/ + osalDbgAssert(((EXTI->RTSR & padmask) == 0U) && + ((EXTI->FTSR & padmask) == 0U), "channel already in use"); + + /* Index and mask of the SYSCFG CR register to be used.*/ + cridx = (uint32_t)pad >> 2U; + croff = ((uint32_t)pad & 3U) * 4U; + crmask = ~(0xFU << croff); + + /* Port index is obtained assuming that GPIO ports are placed at regular + 0x400 intervals in memory space. So far this is true for all devices.*/ + portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU; + + /* Port selection in SYSCFG.*/ + AFIO->EXTICR[cridx] = (AFIO->EXTICR[cridx] & crmask) | (portidx << croff); + + /* Programming edge registers.*/ + if (mode & PAL_EVENT_MODE_RISING_EDGE) + EXTI->RTSR |= padmask; + else + EXTI->RTSR &= ~padmask; + if (mode & PAL_EVENT_MODE_FALLING_EDGE) + EXTI->FTSR |= padmask; + else + EXTI->FTSR &= ~padmask; + + /* Programming interrupt and event registers.*/ + EXTI->IMR |= padmask; + EXTI->EMR &= ~padmask; +} + +/** + * @brief Pad event disable. + * @details This function disables previously programmed event callbacks. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad) { + uint32_t padmask, rtsr1, ftsr1; + + rtsr1 = EXTI->RTSR; + ftsr1 = EXTI->FTSR; + + /* Mask of the pad.*/ + padmask = 1U << (uint32_t)pad; + + /* If either RTRS1 or FTSR1 is enabled then the channel is in use.*/ + if (((rtsr1 | ftsr1) & padmask) != 0U) { + uint32_t cridx, croff, crport, portidx; + + /* Index and mask of the SYSCFG CR register to be used.*/ + cridx = (uint32_t)pad >> 2U; + croff = ((uint32_t)pad & 3U) * 4U; + + /* Port index is obtained assuming that GPIO ports are placed at regular + 0x400 intervals in memory space. So far this is true for all devices.*/ + portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU; + + crport = (AFIO->EXTICR[cridx] >> croff) & 0xFU; + + osalDbgAssert(crport == portidx, "channel mapped on different port"); + + /* Disabling channel.*/ + EXTI->IMR &= ~padmask; + EXTI->EMR &= ~padmask; + EXTI->RTSR = rtsr1 & ~padmask; + EXTI->FTSR = ftsr1 & ~padmask; + EXTI->PR = padmask; + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT + /* Callback cleared and/or thread reset.*/ + _pal_clear_event(pad); +#endif + } +} +#endif /* PAL_USE_CALLBACKS || PAL_USE_WAIT */ + +#endif /* HAL_USE_PAL */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.h new file mode 100644 index 0000000..63bc006 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.h @@ -0,0 +1,459 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file GPIOv1/hal_pal_lld.h + * @brief STM32 PAL low level driver header. + * + * @addtogroup PAL + * @{ + */ + +#ifndef HAL_PAL_LLD_H +#define HAL_PAL_LLD_H + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Unsupported modes and specific modes */ +/*===========================================================================*/ + +/** + * @name STM32-specific I/O mode flags + * @{ + */ +/** + * @brief STM32 specific alternate push-pull output mode. + */ +#define PAL_MODE_STM32_ALTERNATE_PUSHPULL 16 + +/** + * @brief STM32 specific alternate open-drain output mode. + */ +#define PAL_MODE_STM32_ALTERNATE_OPENDRAIN 17 +/** @} */ + +/*===========================================================================*/ +/* I/O Ports Types and constants. */ +/*===========================================================================*/ + +/** + * @name Port related definitions + * @{ + */ +/** + * @brief Width, in bits, of an I/O port. + */ +#define PAL_IOPORTS_WIDTH 16 + +/** + * @brief Whole port mask. + * @details This macro specifies all the valid bits into a port. + */ +#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF) +/** @} */ + +/** + * @name Line handling macros + * @{ + */ +/** + * @brief Forms a line identifier. + * @details A port/pad pair are encoded into an @p ioline_t type. The encoding + * of this type is platform-dependent. + * @note In this driver the pad number is encoded in the lower 4 bits of + * the GPIO address which are guaranteed to be zero. + */ +#define PAL_LINE(port, pad) \ + ((ioline_t)((uint32_t)(port)) | ((uint32_t)(pad))) + +/** + * @brief Decodes a port identifier from a line identifier. + */ +#define PAL_PORT(line) \ + ((GPIO_TypeDef *)(((uint32_t)(line)) & 0xFFFFFFF0U)) + +/** + * @brief Decodes a pad identifier from a line identifier. + */ +#define PAL_PAD(line) \ + ((uint32_t)((uint32_t)(line) & 0x0000000FU)) + +/** + * @brief Value identifying an invalid line. + */ +#define PAL_NOLINE 0U +/** @} */ + +/** + * @brief GPIO port setup info. + */ +typedef struct { + /** Initial value for ODR register.*/ + uint32_t odr; + /** Initial value for CRL register.*/ + uint32_t crl; + /** Initial value for CRH register.*/ + uint32_t crh; +} stm32_gpio_setup_t; + +/** + * @brief STM32 GPIO static initializer. + * @details An instance of this structure must be passed to @p palInit() at + * system startup time in order to initialize the digital I/O + * subsystem. This represents only the initial setup, specific pads + * or whole ports can be reprogrammed at later time. + */ +typedef struct { + /** @brief Port A setup data.*/ + stm32_gpio_setup_t PAData; + /** @brief Port B setup data.*/ + stm32_gpio_setup_t PBData; + /** @brief Port C setup data.*/ + stm32_gpio_setup_t PCData; + /** @brief Port D setup data.*/ + stm32_gpio_setup_t PDData; +#if STM32_HAS_GPIOE || defined(__DOXYGEN__) + /** @brief Port E setup data.*/ + stm32_gpio_setup_t PEData; +#if STM32_HAS_GPIOF || defined(__DOXYGEN__) + /** @brief Port F setup data.*/ + stm32_gpio_setup_t PFData; +#if STM32_HAS_GPIOG || defined(__DOXYGEN__) + /** @brief Port G setup data.*/ + stm32_gpio_setup_t PGData; +#endif +#endif +#endif +} PALConfig; + +/** + * @brief Digital I/O port sized unsigned type. + */ +typedef uint32_t ioportmask_t; + +/** + * @brief Digital I/O modes. + */ +typedef uint32_t iomode_t; + +/** + * @brief Type of an I/O line. + */ +typedef uint32_t ioline_t; + +/** + * @brief Type of an event mode. + */ +typedef uint32_t ioeventmode_t; + +/** + * @brief Port Identifier. + * @details This type can be a scalar or some kind of pointer, do not make + * any assumption about it, use the provided macros when populating + * variables of this type. + */ +typedef GPIO_TypeDef * ioportid_t; + +/** + * @brief Type of an pad identifier. + */ +typedef uint32_t iopadid_t; + +/*===========================================================================*/ +/* I/O Ports Identifiers. */ +/* The low level driver wraps the definitions already present in the STM32 */ +/* firmware library. */ +/*===========================================================================*/ + +/** + * @brief GPIO port A identifier. + */ +#if STM32_HAS_GPIOA || defined(__DOXYGEN__) +#define IOPORT1 GPIOA +#endif + +/** + * @brief GPIO port B identifier. + */ +#if STM32_HAS_GPIOB || defined(__DOXYGEN__) +#define IOPORT2 GPIOB +#endif + +/** + * @brief GPIO port C identifier. + */ +#if STM32_HAS_GPIOC || defined(__DOXYGEN__) +#define IOPORT3 GPIOC +#endif + +/** + * @brief GPIO port D identifier. + */ +#if STM32_HAS_GPIOD || defined(__DOXYGEN__) +#define IOPORT4 GPIOD +#endif + +/** + * @brief GPIO port E identifier. + */ +#if STM32_HAS_GPIOE || defined(__DOXYGEN__) +#define IOPORT5 GPIOE +#endif + +/** + * @brief GPIO port F identifier. + */ +#if STM32_HAS_GPIOF || defined(__DOXYGEN__) +#define IOPORT6 GPIOF +#endif + +/** + * @brief GPIO port G identifier. + */ +#if STM32_HAS_GPIOG || defined(__DOXYGEN__) +#define IOPORT7 GPIOG +#endif + +/*===========================================================================*/ +/* Implementation, some of the following macros could be implemented as */ +/* functions, if so please put them in pal_lld.c. */ +/*===========================================================================*/ + +/** + * @brief GPIO ports subsystem initialization. + * + * @notapi + */ +#define pal_lld_init(config) _pal_lld_init(config) + +/** + * @brief Reads an I/O port. + * @details This function is implemented by reading the GPIO IDR register, the + * implementation has no side effects. + * @note This function is not meant to be invoked directly by the application + * code. + * + * @param[in] port port identifier + * @return The port bits. + * + * @notapi + */ +#define pal_lld_readport(port) ((ioportmask_t)((port)->IDR)) + +/** + * @brief Reads the output latch. + * @details This function is implemented by reading the GPIO ODR register, the + * implementation has no side effects. + * @note This function is not meant to be invoked directly by the application + * code. + * + * @param[in] port port identifier + * @return The latched logical states. + * + * @notapi + */ +#define pal_lld_readlatch(port) ((ioportmask_t)((port)->ODR)) + +/** + * @brief Writes on a I/O port. + * @details This function is implemented by writing the GPIO ODR register, the + * implementation has no side effects. + * @note Writing on pads programmed as pull-up or pull-down has the side + * effect to modify the resistor setting because the output latched + * data is used for the resistor selection. + * + * @param[in] port port identifier + * @param[in] bits bits to be written on the specified port + * + * @notapi + */ +#define pal_lld_writeport(port, bits) ((port)->ODR = (uint32_t)(bits)) + +/** + * @brief Sets a bits mask on a I/O port. + * @details This function is implemented by writing the GPIO BSRR register, the + * implementation has no side effects. + * @note Writing on pads programmed as pull-up or pull-down has the side + * effect to modify the resistor setting because the output latched + * data is used for the resistor selection. + * + * @param[in] port port identifier + * @param[in] bits bits to be ORed on the specified port + * + * @notapi + */ +#define pal_lld_setport(port, bits) ((port)->BSRR = (uint32_t)(bits)) + +/** + * @brief Clears a bits mask on a I/O port. + * @details This function is implemented by writing the GPIO BRR register, the + * implementation has no side effects. + * @note Writing on pads programmed as pull-up or pull-down has the side + * effect to modify the resistor setting because the output latched + * data is used for the resistor selection. + * + * @param[in] port port identifier + * @param[in] bits bits to be cleared on the specified port + * + * @notapi + */ +#define pal_lld_clearport(port, bits) ((port)->BRR = (uint32_t)(bits)) + +/** + * @brief Writes a group of bits. + * @details This function is implemented by writing the GPIO BSRR register, the + * implementation has no side effects. + * @note Writing on pads programmed as pull-up or pull-down has the side + * effect to modify the resistor setting because the output latched + * data is used for the resistor selection. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset the group bit offset within the port + * @param[in] bits bits to be written. Values exceeding the group + * width are masked. + * + * @notapi + */ +#define pal_lld_writegroup(port, mask, offset, bits) { \ + uint32_t w = ((~(uint32_t)(bits) & (uint32_t)(mask)) << (16U + (offset))) | \ + ((uint32_t)(bits) & (uint32_t)(mask)) << (offset); \ + (port)->BSRR = w; \ +} + +/** + * @brief Pads group mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note Writing on pads programmed as pull-up or pull-down has the side + * effect to modify the resistor setting because the output latched + * data is used for the resistor selection. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @param[in] mode group mode + * + * @notapi + */ +#define pal_lld_setgroupmode(port, mask, offset, mode) \ + _pal_lld_setgroupmode(port, mask << offset, mode) + +/** + * @brief Writes a logical state on an output pad. + * @note Writing on pads programmed as pull-up or pull-down has the side + * effect to modify the resistor setting because the output latched + * data is used for the resistor selection. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] bit logical value, the value must be @p PAL_LOW or + * @p PAL_HIGH + * + * @notapi + */ +#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit) + +/** + * @brief Pad event enable. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] mode pad event mode + * + * @notapi + */ +#define pal_lld_enablepadevent(port, pad, mode) \ + _pal_lld_enablepadevent(port, pad, mode) + +/** + * @brief Pad event disable. + * @details This function disables previously programmed event callbacks. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_disablepadevent(port, pad) \ + _pal_lld_disablepadevent(port, pad) + +/** + * @brief Returns a PAL event structure associated to a pad. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_get_pad_event(port, pad) \ + &_pal_events[pad]; (void)(port) + +/** + * @brief Returns a PAL event structure associated to a line. + * + * @param[in] line line identifier + * + * @notapi + */ +#define pal_lld_get_line_event(line) \ + &_pal_events[PAL_PAD(line)] + +/** + * @brief Pad event enable check. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @return Pad event status. + * @retval false if the pad event is disabled. + * @retval true if the pad event is enabled. + * + * @notapi + */ +#define pal_lld_ispadeventenabled(port, pad) \ + (bool)((EXTI->IMR & (1U << (uint32_t)pad)) != 0U) + +#if !defined(__DOXYGEN__) +extern const PALConfig pal_default_config; +#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) +extern palevent_t _pal_events[16]; +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void _pal_lld_init(const PALConfig *config); + void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode); +#if PAL_USE_CALLBACKS || PAL_USE_WAIT + void _pal_lld_enablepadevent(ioportid_t port, + iopadid_t pad, + ioeventmode_t mode); + void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_PAL */ + +#endif /* HAL_PAL_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/driver.mk new file mode 100644 index 0000000..387ed83 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c new file mode 100644 index 0000000..ef2fb9a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c @@ -0,0 +1,271 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file GPIOv2/hal_pal_lld.c + * @brief STM32 PAL low level driver code. + * + * @addtogroup PAL + * @{ + */ + +#include "hal.h" + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) +/** + * @brief Event records for the 16 GPIO EXTI channels. + */ +palevent_t _pal_events[16]; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief PAL driver initialization. + * + * @notapi + */ +void _pal_lld_init(void) { + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) + unsigned i; + + for (i = 0; i < 16; i++) { + _pal_init_event(i); + } +#endif +} + +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note @p PAL_MODE_UNCONNECTED is implemented as push pull at minimum + * speed. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the mode + * + * @notapi + */ +void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode) { + + uint32_t moder = (mode & PAL_STM32_MODE_MASK) >> 0; + uint32_t otyper = (mode & PAL_STM32_OTYPE_MASK) >> 2; + uint32_t ospeedr = (mode & PAL_STM32_OSPEED_MASK) >> 3; + uint32_t pupdr = (mode & PAL_STM32_PUPDR_MASK) >> 5; + uint32_t altr = (mode & PAL_STM32_ALTERNATE_MASK) >> 7; + uint32_t bit = 0; + while (true) { + if ((mask & 1) != 0) { + uint32_t altrmask, m1, m2, m4; + + altrmask = altr << ((bit & 7) * 4); + m1 = 1 << bit; + m2 = 3 << (bit * 2); + m4 = 15 << ((bit & 7) * 4); + port->OTYPER = (port->OTYPER & ~m1) | otyper; + port->OSPEEDR = (port->OSPEEDR & ~m2) | ospeedr; + port->PUPDR = (port->PUPDR & ~m2) | pupdr; + if ((mode & PAL_STM32_MODE_MASK) == PAL_STM32_MODE_ALTERNATE) { + /* If going in alternate mode then the alternate number is set + before switching mode in order to avoid glitches.*/ + if (bit < 8) + port->AFRL = (port->AFRL & ~m4) | altrmask; + else + port->AFRH = (port->AFRH & ~m4) | altrmask; + port->MODER = (port->MODER & ~m2) | moder; + } + else { + /* If going into a non-alternate mode then the mode is switched + before setting the alternate mode in order to avoid glitches.*/ + port->MODER = (port->MODER & ~m2) | moder; + if (bit < 8) + port->AFRL = (port->AFRL & ~m4) | altrmask; + else + port->AFRH = (port->AFRH & ~m4) | altrmask; + } + } + mask >>= 1; + if (!mask) + return; + otyper <<= 1; + ospeedr <<= 2; + pupdr <<= 2; + moder <<= 2; + bit++; + } +} + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) +/** + * @brief Pad event enable. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] mode pad event mode + * + * @notapi + */ +void _pal_lld_enablepadevent(ioportid_t port, + iopadid_t pad, + ioeventmode_t mode) { + + uint32_t padmask, cridx, croff, crmask, portidx; + + /* Mask of the pad.*/ + padmask = 1U << (uint32_t)pad; + + /* Multiple channel setting of the same channel not allowed, first disable + it. This is done because on STM32 the same channel cannot be mapped on + multiple ports.*/ + osalDbgAssert(((EXTI->RTSR1 & padmask) == 0U) && + ((EXTI->FTSR1 & padmask) == 0U), "channel already in use"); + + /* Port index is obtained assuming that GPIO ports are placed at regular + 0x400 intervals in memory space. So far this is true for all devices.*/ + portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU; + + /* Index and mask of the CR register to be used.*/ + cridx = (uint32_t)pad >> 2U; +#if STM32_EXTI_HAS_CR == FALSE + croff = ((uint32_t)pad & 3U) * 4U; + crmask = ~(0xFU << croff); + SYSCFG->EXTICR[cridx] = (SYSCFG->EXTICR[cridx] & crmask) | (portidx << croff); +#else + croff = ((uint32_t)pad & 3U) * 8U; + crmask = ~(0xFFU << croff); + EXTI->EXTICR[cridx] = (EXTI->EXTICR[cridx] & crmask) | (portidx << croff); +#endif + + /* Programming edge registers.*/ + if (mode & PAL_EVENT_MODE_RISING_EDGE) + EXTI->RTSR1 |= padmask; + else + EXTI->RTSR1 &= ~padmask; + if (mode & PAL_EVENT_MODE_FALLING_EDGE) + EXTI->FTSR1 |= padmask; + else + EXTI->FTSR1 &= ~padmask; + + /* Programming interrupt and event registers.*/ +#if defined(STM32_EXTI_ENHANCED) + EXTI_D1->IMR1 |= padmask; + EXTI_D1->EMR1 &= ~padmask; +#else + EXTI->IMR1 |= padmask; + EXTI->EMR1 &= ~padmask; +#endif +} + +/** + * @brief Pad event disable. + * @details This function disables previously programmed event callbacks. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad) { + uint32_t padmask, rtsr1, ftsr1; + + rtsr1 = EXTI->RTSR1; + ftsr1 = EXTI->FTSR1; + + /* Mask of the pad.*/ + padmask = 1U << (uint32_t)pad; + + /* If either RTRS1 or FTSR1 is enabled then the channel is in use.*/ + if (((rtsr1 | ftsr1) & padmask) != 0U) { + uint32_t cridx, croff, crport, portidx; + + /* Port index is obtained assuming that GPIO ports are placed at regular + 0x400 intervals in memory space. So far this is true for all devices.*/ + portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU; + + /* Index and mask of the CR register to be used.*/ + cridx = (uint32_t)pad >> 2U; +#if STM32_EXTI_HAS_CR == FALSE + croff = ((uint32_t)pad & 3U) * 4U; + crport = (SYSCFG->EXTICR[cridx] >> croff) & 0xFU; +#else + croff = ((uint32_t)pad & 3U) * 8U; + crport = (EXTI->EXTICR[cridx] >> croff) & 0xFFU; +#endif + + osalDbgAssert(crport == portidx, "channel mapped on different port"); + +#if defined(STM32_EXTI_ENHANCED) + /* Disabling channel.*/ + EXTI_D1->IMR1 &= ~padmask; + EXTI_D1->EMR1 &= ~padmask; + EXTI->RTSR1 = rtsr1 & ~padmask; + EXTI->FTSR1 = ftsr1 & ~padmask; + EXTI_D1->PR1 = padmask; +#else + /* Disabling channel.*/ + EXTI->IMR1 &= ~padmask; + EXTI->EMR1 &= ~padmask; + EXTI->RTSR1 = rtsr1 & ~padmask; + EXTI->FTSR1 = ftsr1 & ~padmask; +#if STM32_EXTI_SEPARATE_RF == FALSE + EXTI->PR1 = padmask; +#else + EXTI->RPR1 = padmask; + EXTI->FPR1 = padmask; +#endif +#endif + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT + /* Callback cleared and/or thread reset.*/ + _pal_clear_event(pad); +#endif + } +} +#endif /* PAL_USE_CALLBACKS || PAL_USE_WAIT */ + +#endif /* HAL_USE_PAL */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.h new file mode 100644 index 0000000..15b541b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.h @@ -0,0 +1,514 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file GPIOv2/hal_pal_lld.h + * @brief STM32 PAL low level driver header. + * + * @addtogroup PAL + * @{ + */ + +#ifndef HAL_PAL_LLD_H +#define HAL_PAL_LLD_H + +#include "stm32_gpio.h" + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Unsupported modes and specific modes */ +/*===========================================================================*/ + +/* Specifies palInit() without parameter, required until all platforms will + be updated to the new style.*/ +#define PAL_NEW_INIT + +#undef PAL_MODE_RESET +#undef PAL_MODE_UNCONNECTED +#undef PAL_MODE_INPUT +#undef PAL_MODE_INPUT_PULLUP +#undef PAL_MODE_INPUT_PULLDOWN +#undef PAL_MODE_INPUT_ANALOG +#undef PAL_MODE_OUTPUT_PUSHPULL +#undef PAL_MODE_OUTPUT_OPENDRAIN + +/** + * @name STM32-specific I/O mode flags + * @{ + */ +#define PAL_STM32_MODE_MASK (3U << 0U) +#define PAL_STM32_MODE_INPUT (0U << 0U) +#define PAL_STM32_MODE_OUTPUT (1U << 0U) +#define PAL_STM32_MODE_ALTERNATE (2U << 0U) +#define PAL_STM32_MODE_ANALOG (3U << 0U) + +#define PAL_STM32_OTYPE_MASK (1U << 2U) +#define PAL_STM32_OTYPE_PUSHPULL (0U << 2U) +#define PAL_STM32_OTYPE_OPENDRAIN (1U << 2U) + +#define PAL_STM32_OSPEED_MASK (3U << 3U) +#define PAL_STM32_OSPEED_LOWEST (0U << 3U) +#if defined(STM32F0XX) || defined(STM32F30X) || defined(STM32F37X) +#define PAL_STM32_OSPEED_MID (1U << 3U) +#else +#define PAL_STM32_OSPEED_MID1 (1U << 3U) +#define PAL_STM32_OSPEED_MID2 (2U << 3U) +#endif +#define PAL_STM32_OSPEED_HIGHEST (3U << 3U) + +#define PAL_STM32_PUPDR_MASK (3U << 5U) +#define PAL_STM32_PUPDR_FLOATING (0U << 5U) +#define PAL_STM32_PUPDR_PULLUP (1U << 5U) +#define PAL_STM32_PUPDR_PULLDOWN (2U << 5U) + +#define PAL_STM32_ALTERNATE_MASK (15U << 7U) +#define PAL_STM32_ALTERNATE(n) ((n) << 7U) + +/** + * @brief Alternate function. + * + * @param[in] n alternate function selector + */ +#define PAL_MODE_ALTERNATE(n) (PAL_STM32_MODE_ALTERNATE | \ + PAL_STM32_ALTERNATE(n)) +/** @} */ + +/** + * @name Standard I/O mode flags + * @{ + */ +/** + * @brief Implemented as input. + */ +#define PAL_MODE_RESET PAL_STM32_MODE_INPUT + +/** + * @brief Implemented as input with pull-up. + */ +#define PAL_MODE_UNCONNECTED PAL_MODE_INPUT_PULLUP + +/** + * @brief Regular input high-Z pad. + */ +#define PAL_MODE_INPUT PAL_STM32_MODE_INPUT + +/** + * @brief Input pad with weak pull up resistor. + */ +#define PAL_MODE_INPUT_PULLUP (PAL_STM32_MODE_INPUT | \ + PAL_STM32_PUPDR_PULLUP) + +/** + * @brief Input pad with weak pull down resistor. + */ +#define PAL_MODE_INPUT_PULLDOWN (PAL_STM32_MODE_INPUT | \ + PAL_STM32_PUPDR_PULLDOWN) + +/** + * @brief Analog input mode. + */ +#define PAL_MODE_INPUT_ANALOG PAL_STM32_MODE_ANALOG + +/** + * @brief Push-pull output pad. + */ +#define PAL_MODE_OUTPUT_PUSHPULL (PAL_STM32_MODE_OUTPUT | \ + PAL_STM32_OTYPE_PUSHPULL) + +/** + * @brief Open-drain output pad. + */ +#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_STM32_MODE_OUTPUT | \ + PAL_STM32_OTYPE_OPENDRAIN) +/** @} */ + +/*===========================================================================*/ +/* I/O Ports Types and constants. */ +/*===========================================================================*/ + +/** + * @name Port related definitions + * @{ + */ +/** + * @brief Width, in bits, of an I/O port. + */ +#define PAL_IOPORTS_WIDTH 16 + +/** + * @brief Whole port mask. + * @details This macro specifies all the valid bits into a port. + */ +#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF) +/** @} */ + +/** + * @name Line handling macros + * @{ + */ +/** + * @brief Forms a line identifier. + * @details A port/pad pair are encoded into an @p ioline_t type. The encoding + * of this type is platform-dependent. + * @note In this driver the pad number is encoded in the lower 4 bits of + * the GPIO address which are guaranteed to be zero. + */ +#define PAL_LINE(port, pad) \ + ((ioline_t)((uint32_t)(port)) | ((uint32_t)(pad))) + +/** + * @brief Decodes a port identifier from a line identifier. + */ +#define PAL_PORT(line) \ + ((stm32_gpio_t *)(((uint32_t)(line)) & 0xFFFFFFF0U)) + +/** + * @brief Decodes a pad identifier from a line identifier. + */ +#define PAL_PAD(line) \ + ((uint32_t)((uint32_t)(line) & 0x0000000FU)) + +/** + * @brief Value identifying an invalid line. + */ +#define PAL_NOLINE 0U +/** @} */ + +/** + * @brief Type of digital I/O port sized unsigned integer. + */ +typedef uint32_t ioportmask_t; + +/** + * @brief Type of digital I/O modes. + */ +typedef uint32_t iomode_t; + +/** + * @brief Type of an I/O line. + */ +typedef uint32_t ioline_t; + +/** + * @brief Type of an event mode. + */ +typedef uint32_t ioeventmode_t; + +/** + * @brief Type of a port Identifier. + * @details This type can be a scalar or some kind of pointer, do not make + * any assumption about it, use the provided macros when populating + * variables of this type. + */ +typedef stm32_gpio_t * ioportid_t; + +/** + * @brief Type of an pad identifier. + */ +typedef uint32_t iopadid_t; + +/*===========================================================================*/ +/* I/O Ports Identifiers. */ +/* The low level driver wraps the definitions already present in the STM32 */ +/* firmware library. */ +/*===========================================================================*/ + +/** + * @brief GPIO port A identifier. + */ +#if STM32_HAS_GPIOA || defined(__DOXYGEN__) +#define IOPORT1 GPIOA +#endif + +/** + * @brief GPIO port B identifier. + */ +#if STM32_HAS_GPIOB || defined(__DOXYGEN__) +#define IOPORT2 GPIOB +#endif + +/** + * @brief GPIO port C identifier. + */ +#if STM32_HAS_GPIOC || defined(__DOXYGEN__) +#define IOPORT3 GPIOC +#endif + +/** + * @brief GPIO port D identifier. + */ +#if STM32_HAS_GPIOD || defined(__DOXYGEN__) +#define IOPORT4 GPIOD +#endif + +/** + * @brief GPIO port E identifier. + */ +#if STM32_HAS_GPIOE || defined(__DOXYGEN__) +#define IOPORT5 GPIOE +#endif + +/** + * @brief GPIO port F identifier. + */ +#if STM32_HAS_GPIOF || defined(__DOXYGEN__) +#define IOPORT6 GPIOF +#endif + +/** + * @brief GPIO port G identifier. + */ +#if STM32_HAS_GPIOG || defined(__DOXYGEN__) +#define IOPORT7 GPIOG +#endif + +/** + * @brief GPIO port H identifier. + */ +#if STM32_HAS_GPIOH || defined(__DOXYGEN__) +#define IOPORT8 GPIOH +#endif + +/** + * @brief GPIO port I identifier. + */ +#if STM32_HAS_GPIOI || defined(__DOXYGEN__) +#define IOPORT9 GPIOI +#endif + +/** + * @brief GPIO port J identifier. + */ +#if STM32_HAS_GPIOJ || defined(__DOXYGEN__) +#define IOPORT10 GPIOJ +#endif + +/** + * @brief GPIO port K identifier. + */ +#if STM32_HAS_GPIOK || defined(__DOXYGEN__) +#define IOPORT11 GPIOK +#endif + +/*===========================================================================*/ +/* Implementation, some of the following macros could be implemented as */ +/* functions, if so please put them in pal_lld.c. */ +/*===========================================================================*/ + +/** + * @brief GPIO ports subsystem initialization. + * + * @notapi + */ +#define pal_lld_init() _pal_lld_init() + +/** + * @brief Reads an I/O port. + * @details This function is implemented by reading the GPIO IDR register, the + * implementation has no side effects. + * @note This function is not meant to be invoked directly by the application + * code. + * + * @param[in] port port identifier + * @return The port bits. + * + * @notapi + */ +#define pal_lld_readport(port) ((ioportmask_t)((port)->IDR)) + +/** + * @brief Reads the output latch. + * @details This function is implemented by reading the GPIO ODR register, the + * implementation has no side effects. + * @note This function is not meant to be invoked directly by the application + * code. + * + * @param[in] port port identifier + * @return The latched logical states. + * + * @notapi + */ +#define pal_lld_readlatch(port) ((ioportmask_t)((port)->ODR)) + +/** + * @brief Writes on a I/O port. + * @details This function is implemented by writing the GPIO ODR register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] bits bits to be written on the specified port + * + * @notapi + */ +#define pal_lld_writeport(port, bits) ((port)->ODR = (uint32_t)(bits)) + +/** + * @brief Sets a bits mask on a I/O port. + * @details This function is implemented by writing the GPIO BSRR register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] bits bits to be ORed on the specified port + * + * @notapi + */ +#define pal_lld_setport(port, bits) ((port)->BSRR.H.set = (uint16_t)(bits)) + +/** + * @brief Clears a bits mask on a I/O port. + * @details This function is implemented by writing the GPIO BSRR register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] bits bits to be cleared on the specified port + * + * @notapi + */ +#define pal_lld_clearport(port, bits) ((port)->BSRR.H.clear = (uint16_t)(bits)) + +/** + * @brief Writes a group of bits. + * @details This function is implemented by writing the GPIO BSRR register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset the group bit offset within the port + * @param[in] bits bits to be written. Values exceeding the group + * width are masked. + * + * @notapi + */ +#define pal_lld_writegroup(port, mask, offset, bits) { \ + uint32_t w = ((~(uint32_t)(bits) & (uint32_t)(mask)) << (16U + (offset))) | \ + ((uint32_t)(bits) & (uint32_t)(mask)) << (offset); \ + (port)->BSRR.W = w; \ +} + +/** + * @brief Pads group mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @param[in] mode group mode + * + * @notapi + */ +#define pal_lld_setgroupmode(port, mask, offset, mode) \ + _pal_lld_setgroupmode(port, mask << offset, mode) + +/** + * @brief Writes a logical state on an output pad. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] bit logical value, the value must be @p PAL_LOW or + * @p PAL_HIGH + * + * @notapi + */ +#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit) + +/** + * @brief Pad event enable. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] mode pad event mode + * + * @notapi + */ +#define pal_lld_enablepadevent(port, pad, mode) \ + _pal_lld_enablepadevent(port, pad, mode) + +/** + * @brief Pad event disable. + * @details This function disables previously programmed event callbacks. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_disablepadevent(port, pad) \ + _pal_lld_disablepadevent(port, pad) + +/** + * @brief Returns a PAL event structure associated to a pad. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_get_pad_event(port, pad) \ + &_pal_events[pad]; (void)(port) + +/** + * @brief Returns a PAL event structure associated to a line. + * + * @param[in] line line identifier + * + * @notapi + */ +#define pal_lld_get_line_event(line) \ + &_pal_events[PAL_PAD(line)] + +/** + * @brief Pad event enable check. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @return Pad event status. + * @retval false if the pad event is disabled. + * @retval true if the pad event is enabled. + * + * @notapi + */ +#define pal_lld_ispadeventenabled(port, pad) \ + (bool)((EXTI->IMR1 & (1U << (uint32_t)pad)) != 0U) + +#if !defined(__DOXYGEN__) +#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) +extern palevent_t _pal_events[16]; +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void _pal_lld_init(void); + void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode); + void _pal_lld_enablepadevent(ioportid_t port, + iopadid_t pad, + ioeventmode_t mode); + void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_PAL */ + +#endif /* HAL_PAL_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/stm32_gpio.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/stm32_gpio.h new file mode 100644 index 0000000..83fd51e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/stm32_gpio.h @@ -0,0 +1,111 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file GPIOv2/stm32_gpio.h + * @brief STM32 GPIO units common header. + * @note This file requires definitions from the ST STM32 header file. + * + * @addtogroup STM32_GPIOv2 + * @{ + */ + +#ifndef STM32_GPIO_H +#define STM32_GPIO_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* Discarded definitions from the ST headers, the PAL driver uses its own + definitions in order to have an unified handling for all devices. + Unfortunately the ST headers have no uniform definitions for the same + objects across the various sub-families.*/ +#undef GPIOA +#undef GPIOB +#undef GPIOC +#undef GPIOD +#undef GPIOE +#undef GPIOF +#undef GPIOG +#undef GPIOH +#undef GPIOI +#undef GPIOJ +#undef GPIOK + +/** + * @name GPIO ports definitions + * @{ + */ +#define GPIOA ((stm32_gpio_t *)GPIOA_BASE) +#define GPIOB ((stm32_gpio_t *)GPIOB_BASE) +#define GPIOC ((stm32_gpio_t *)GPIOC_BASE) +#define GPIOD ((stm32_gpio_t *)GPIOD_BASE) +#define GPIOE ((stm32_gpio_t *)GPIOE_BASE) +#define GPIOF ((stm32_gpio_t *)GPIOF_BASE) +#define GPIOG ((stm32_gpio_t *)GPIOG_BASE) +#define GPIOH ((stm32_gpio_t *)GPIOH_BASE) +#define GPIOI ((stm32_gpio_t *)GPIOI_BASE) +#define GPIOJ ((stm32_gpio_t *)GPIOJ_BASE) +#define GPIOK ((stm32_gpio_t *)GPIOK_BASE) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief STM32 GPIO registers block. + */ +typedef struct { + + volatile uint32_t MODER; + volatile uint32_t OTYPER; + volatile uint32_t OSPEEDR; + volatile uint32_t PUPDR; + volatile uint32_t IDR; + volatile uint32_t ODR; + volatile union { + uint32_t W; + struct { + uint16_t set; + uint16_t clear; + } H; + } BSRR; + volatile uint32_t LOCKR; + volatile uint32_t AFRL; + volatile uint32_t AFRH; +} stm32_gpio_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#endif /* STM32_GPIO_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/driver.mk new file mode 100644 index 0000000..b2db0f3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv3 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c new file mode 100644 index 0000000..92b61b5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c @@ -0,0 +1,249 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file GPIOv3/hal_pal_lld.c + * @brief STM32 PAL low level driver code. + * + * @addtogroup PAL + * @{ + */ + +#include "hal.h" + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) +/** + * @brief Event records for the 16 GPIO EXTI channels. + */ +palevent_t _pal_events[16]; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief PAL driver initialization. + * + * @notapi + */ +void _pal_lld_init(void) { + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) + unsigned i; + + for (i = 0; i < 16; i++) { + _pal_init_event(i); + } +#endif +} + +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note @p PAL_MODE_UNCONNECTED is implemented as push pull at minimum + * speed. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the mode + * + * @notapi + */ +void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode) { + + uint32_t moder = (mode & PAL_STM32_MODE_MASK) >> 0; + uint32_t otyper = (mode & PAL_STM32_OTYPE_MASK) >> 2; + uint32_t ospeedr = (mode & PAL_STM32_OSPEED_MASK) >> 3; + uint32_t pupdr = (mode & PAL_STM32_PUPDR_MASK) >> 5; + uint32_t altr = (mode & PAL_STM32_ALTERNATE_MASK) >> 7; + uint32_t ascr = (mode & PAL_STM32_ASCR_MASK) >> 11; + uint32_t lockr = (mode & PAL_STM32_LOCKR_MASK) >> 12; + uint32_t bit = 0; + while (true) { + if ((mask & 1) != 0) { + uint32_t altrmask, m1, m2, m4; + + altrmask = altr << ((bit & 7) * 4); + m1 = 1 << bit; + m2 = 3 << (bit * 2); + m4 = 15 << ((bit & 7) * 4); + port->OTYPER = (port->OTYPER & ~m1) | otyper; + port->ASCR = (port->ASCR & ~m1) | ascr; + port->OSPEEDR = (port->OSPEEDR & ~m2) | ospeedr; + port->PUPDR = (port->PUPDR & ~m2) | pupdr; + if ((mode & PAL_STM32_MODE_MASK) == PAL_STM32_MODE_ALTERNATE) { + /* If going in alternate mode then the alternate number is set + before switching mode in order to avoid glitches.*/ + if (bit < 8) + port->AFRL = (port->AFRL & ~m4) | altrmask; + else + port->AFRH = (port->AFRH & ~m4) | altrmask; + port->MODER = (port->MODER & ~m2) | moder; + } + else { + /* If going into a non-alternate mode then the mode is switched + before setting the alternate mode in order to avoid glitches.*/ + port->MODER = (port->MODER & ~m2) | moder; + if (bit < 8) + port->AFRL = (port->AFRL & ~m4) | altrmask; + else + port->AFRH = (port->AFRH & ~m4) | altrmask; + } + port->LOCKR = (port->LOCKR & ~m1) | lockr; + } + mask >>= 1; + if (!mask) + return; + otyper <<= 1; + ascr <<= 1; + ospeedr <<= 2; + pupdr <<= 2; + moder <<= 2; + bit++; + } +} + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) +/** + * @brief Pad event enable. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] mode pad event mode + * + * @notapi + */ +void _pal_lld_enablepadevent(ioportid_t port, + iopadid_t pad, + ioeventmode_t mode) { + + uint32_t padmask, cridx, croff, crmask, portidx; + + /* Mask of the pad.*/ + padmask = 1U << (uint32_t)pad; + + /* Multiple channel setting of the same channel not allowed, first disable + it. This is done because on STM32 the same channel cannot be mapped on + multiple ports.*/ + osalDbgAssert(((EXTI->RTSR1 & padmask) == 0U) && + ((EXTI->FTSR1 & padmask) == 0U), "channel already in use"); + + /* Index and mask of the SYSCFG CR register to be used.*/ + cridx = (uint32_t)pad >> 2U; + croff = ((uint32_t)pad & 3U) * 4U; + crmask = ~(0xFU << croff); + + /* Port index is obtained assuming that GPIO ports are placed at regular + 0x400 intervals in memory space. So far this is true for all devices.*/ + portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU; + + /* Port selection in SYSCFG.*/ + SYSCFG->EXTICR[cridx] = (SYSCFG->EXTICR[cridx] & crmask) | (portidx << croff); + + /* Programming edge registers.*/ + if (mode & PAL_EVENT_MODE_RISING_EDGE) + EXTI->RTSR1 |= padmask; + else + EXTI->RTSR1 &= ~padmask; + if (mode & PAL_EVENT_MODE_FALLING_EDGE) + EXTI->FTSR1 |= padmask; + else + EXTI->FTSR1 &= ~padmask; + + /* Programming interrupt and event registers.*/ + EXTI->IMR1 |= padmask; + EXTI->EMR1 &= ~padmask; +} + +/** + * @brief Pad event disable. + * @details This function disables previously programmed event callbacks. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad) { + uint32_t padmask, rtsr1, ftsr1; + + rtsr1 = EXTI->RTSR1; + ftsr1 = EXTI->FTSR1; + + /* Mask of the pad.*/ + padmask = 1U << (uint32_t)pad; + + /* If either RTRS1 or FTSR1 is enabled then the channel is in use.*/ + if (((rtsr1 | ftsr1) & padmask) != 0U) { + uint32_t cridx, croff, crport, portidx; + + /* Index and mask of the SYSCFG CR register to be used.*/ + cridx = (uint32_t)pad >> 2U; + croff = ((uint32_t)pad & 3U) * 4U; + + /* Port index is obtained assuming that GPIO ports are placed at regular + 0x400 intervals in memory space. So far this is true for all devices.*/ + portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU; + + crport = (SYSCFG->EXTICR[cridx] >> croff) & 0xFU; + + osalDbgAssert(crport == portidx, "channel mapped on different port"); + + /* Disabling channel.*/ + EXTI->IMR1 &= ~padmask; + EXTI->EMR1 &= ~padmask; + EXTI->RTSR1 = rtsr1 & ~padmask; + EXTI->FTSR1 = ftsr1 & ~padmask; + EXTI->PR1 = padmask; + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT + /* Callback cleared and/or thread reset.*/ + _pal_clear_event(pad); +#endif + } +} +#endif /* PAL_USE_CALLBACKS || PAL_USE_WAIT */ + +#endif /* HAL_USE_PAL */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.h new file mode 100644 index 0000000..9824257 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.h @@ -0,0 +1,554 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file GPIOv3/hal_pal_lld.h + * @brief STM32 PAL low level driver header. + * + * @addtogroup PAL + * @{ + */ + +#ifndef HAL_PAL_LLD_H +#define HAL_PAL_LLD_H + +#include "stm32_gpio.h" + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Unsupported modes and specific modes */ +/*===========================================================================*/ + +/* Specifies palInit() without parameter, required until all platforms will + be updated to the new style.*/ +#define PAL_NEW_INIT + +#undef PAL_MODE_RESET +#undef PAL_MODE_UNCONNECTED +#undef PAL_MODE_INPUT +#undef PAL_MODE_INPUT_PULLUP +#undef PAL_MODE_INPUT_PULLDOWN +#undef PAL_MODE_INPUT_ANALOG +#undef PAL_MODE_OUTPUT_PUSHPULL +#undef PAL_MODE_OUTPUT_OPENDRAIN + +/** + * @name STM32-specific I/O mode flags + * @{ + */ +#define PAL_STM32_MODE_MASK (3U << 0U) +#define PAL_STM32_MODE_INPUT (0U << 0U) +#define PAL_STM32_MODE_OUTPUT (1U << 0U) +#define PAL_STM32_MODE_ALTERNATE (2U << 0U) +#define PAL_STM32_MODE_ANALOG (3U << 0U) + +#define PAL_STM32_OTYPE_MASK (1U << 2U) +#define PAL_STM32_OTYPE_PUSHPULL (0U << 2U) +#define PAL_STM32_OTYPE_OPENDRAIN (1U << 2U) + +#define PAL_STM32_OSPEED_MASK (3U << 3U) +#define PAL_STM32_OSPEED_LOW (0U << 3U) +#define PAL_STM32_OSPEED_MEDIUM (1U << 3U) +#define PAL_STM32_OSPEED_FAST (2U << 3U) +#define PAL_STM32_OSPEED_HIGH (3U << 3U) + +#define PAL_STM32_PUPDR_MASK (3U << 5U) +#define PAL_STM32_PUPDR_FLOATING (0U << 5U) +#define PAL_STM32_PUPDR_PULLUP (1U << 5U) +#define PAL_STM32_PUPDR_PULLDOWN (2U << 5U) + +#define PAL_STM32_ALTERNATE_MASK (15U << 7U) +#define PAL_STM32_ALTERNATE(n) ((n) << 7U) + +#define PAL_STM32_ASCR_MASK (1U << 11U) +#define PAL_STM32_ASCR_OFF (0U << 11U) +#define PAL_STM32_ASCR_ON (1U << 11U) + +#define PAL_STM32_LOCKR_MASK (1U << 12U) +#define PAL_STM32_LOCKR_OFF (0U << 12U) +#define PAL_STM32_LOCKR_ON (1U << 12U) + +/** + * @brief Alternate function. + * + * @param[in] n alternate function selector + */ +#define PAL_MODE_ALTERNATE(n) (PAL_STM32_MODE_ALTERNATE | \ + PAL_STM32_ALTERNATE(n)) +/** @} */ + +/** + * @name Standard I/O mode flags + * @{ + */ +/** + * @brief Implemented as input. + */ +#define PAL_MODE_RESET PAL_STM32_MODE_INPUT + +/** + * @brief Implemented as analog with analog switch disabled and lock. + */ +#define PAL_MODE_UNCONNECTED (PAL_STM32_MODE_ANALOG | \ + PAL_STM32_ASCR_OFF | \ + PAL_STM32_LOCKR_ON) + +/** + * @brief Regular input high-Z pad. + */ +#define PAL_MODE_INPUT PAL_STM32_MODE_INPUT + +/** + * @brief Input pad with weak pull up resistor. + */ +#define PAL_MODE_INPUT_PULLUP (PAL_STM32_MODE_INPUT | \ + PAL_STM32_PUPDR_PULLUP) + +/** + * @brief Input pad with weak pull down resistor. + */ +#define PAL_MODE_INPUT_PULLDOWN (PAL_STM32_MODE_INPUT | \ + PAL_STM32_PUPDR_PULLDOWN) + +/** + * @brief Analog input mode. + */ +#define PAL_MODE_INPUT_ANALOG (PAL_STM32_MODE_ANALOG | \ + PAL_STM32_ASCR_ON) + +/** + * @brief Push-pull output pad. + */ +#define PAL_MODE_OUTPUT_PUSHPULL (PAL_STM32_MODE_OUTPUT | \ + PAL_STM32_OTYPE_PUSHPULL) + +/** + * @brief Open-drain output pad. + */ +#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_STM32_MODE_OUTPUT | \ + PAL_STM32_OTYPE_OPENDRAIN) +/** @} */ + +/* Discarded definitions from the ST headers, the PAL driver uses its own + definitions in order to have an unified handling for all devices. + Unfortunately the ST headers have no uniform definitions for the same + objects across the various sub-families.*/ +#undef GPIOA +#undef GPIOB +#undef GPIOC +#undef GPIOD +#undef GPIOE +#undef GPIOF +#undef GPIOG +#undef GPIOH +#undef GPIOI +#undef GPIOJ +#undef GPIOK + +/** + * @name GPIO ports definitions + * @{ + */ +#define GPIOA ((stm32_gpio_t *)GPIOA_BASE) +#define GPIOB ((stm32_gpio_t *)GPIOB_BASE) +#define GPIOC ((stm32_gpio_t *)GPIOC_BASE) +#define GPIOD ((stm32_gpio_t *)GPIOD_BASE) +#define GPIOE ((stm32_gpio_t *)GPIOE_BASE) +#define GPIOF ((stm32_gpio_t *)GPIOF_BASE) +#define GPIOG ((stm32_gpio_t *)GPIOG_BASE) +#define GPIOH ((stm32_gpio_t *)GPIOH_BASE) +#define GPIOI ((stm32_gpio_t *)GPIOI_BASE) +#define GPIOJ ((stm32_gpio_t *)GPIOJ_BASE) +#define GPIOK ((stm32_gpio_t *)GPIOK_BASE) +/** @} */ + +/*===========================================================================*/ +/* I/O Ports Types and constants. */ +/*===========================================================================*/ + +/** + * @name Port related definitions + * @{ + */ +/** + * @brief Width, in bits, of an I/O port. + */ +#define PAL_IOPORTS_WIDTH 16 + +/** + * @brief Whole port mask. + * @details This macro specifies all the valid bits into a port. + */ +#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF) +/** @} */ + +/** + * @name Line handling macros + * @{ + */ +/** + * @brief Forms a line identifier. + * @details A port/pad pair are encoded into an @p ioline_t type. The encoding + * of this type is platform-dependent. + * @note In this driver the pad number is encoded in the lower 4 bits of + * the GPIO address which are guaranteed to be zero. + */ +#define PAL_LINE(port, pad) \ + ((ioline_t)((uint32_t)(port)) | ((uint32_t)(pad))) + +/** + * @brief Decodes a port identifier from a line identifier. + */ +#define PAL_PORT(line) \ + ((stm32_gpio_t *)(((uint32_t)(line)) & 0xFFFFFFF0U)) + +/** + * @brief Decodes a pad identifier from a line identifier. + */ +#define PAL_PAD(line) \ + ((uint32_t)((uint32_t)(line) & 0x0000000FU)) + +/** + * @brief Value identifying an invalid line. + */ +#define PAL_NOLINE 0U +/** @} */ + +/** + * @brief Type of digital I/O port sized unsigned integer. + */ +typedef uint32_t ioportmask_t; + +/** + * @brief Type of digital I/O modes. + */ +typedef uint32_t iomode_t; + +/** + * @brief Type of an I/O line. + */ +typedef uint32_t ioline_t; + +/** + * @brief Type of an event mode. + */ +typedef uint32_t ioeventmode_t; + +/** + * @brief Type of a port Identifier. + * @details This type can be a scalar or some kind of pointer, do not make + * any assumption about it, use the provided macros when populating + * variables of this type. + */ +typedef stm32_gpio_t * ioportid_t; + +/** + * @brief Type of an pad identifier. + */ +typedef uint32_t iopadid_t; + +/*===========================================================================*/ +/* I/O Ports Identifiers. */ +/* The low level driver wraps the definitions already present in the STM32 */ +/* firmware library. */ +/*===========================================================================*/ + +/** + * @brief GPIO port A identifier. + */ +#if STM32_HAS_GPIOA || defined(__DOXYGEN__) +#define IOPORT1 GPIOA +#endif + +/** + * @brief GPIO port B identifier. + */ +#if STM32_HAS_GPIOB || defined(__DOXYGEN__) +#define IOPORT2 GPIOB +#endif + +/** + * @brief GPIO port C identifier. + */ +#if STM32_HAS_GPIOC || defined(__DOXYGEN__) +#define IOPORT3 GPIOC +#endif + +/** + * @brief GPIO port D identifier. + */ +#if STM32_HAS_GPIOD || defined(__DOXYGEN__) +#define IOPORT4 GPIOD +#endif + +/** + * @brief GPIO port E identifier. + */ +#if STM32_HAS_GPIOE || defined(__DOXYGEN__) +#define IOPORT5 GPIOE +#endif + +/** + * @brief GPIO port F identifier. + */ +#if STM32_HAS_GPIOF || defined(__DOXYGEN__) +#define IOPORT6 GPIOF +#endif + +/** + * @brief GPIO port G identifier. + */ +#if STM32_HAS_GPIOG || defined(__DOXYGEN__) +#define IOPORT7 GPIOG +#endif + +/** + * @brief GPIO port H identifier. + */ +#if STM32_HAS_GPIOH || defined(__DOXYGEN__) +#define IOPORT8 GPIOH +#endif + +/** + * @brief GPIO port I identifier. + */ +#if STM32_HAS_GPIOI || defined(__DOXYGEN__) +#define IOPORT9 GPIOI +#endif + +/** + * @brief GPIO port J identifier. + */ +#if STM32_HAS_GPIOJ || defined(__DOXYGEN__) +#define IOPORT10 GPIOJ +#endif + +/** + * @brief GPIO port K identifier. + */ +#if STM32_HAS_GPIOK || defined(__DOXYGEN__) +#define IOPORT11 GPIOK +#endif + +/*===========================================================================*/ +/* Implementation, some of the following macros could be implemented as */ +/* functions, if so please put them in pal_lld.c. */ +/*===========================================================================*/ + +/** + * @brief GPIO ports subsystem initialization. + * + * @notapi + */ +#define pal_lld_init() _pal_lld_init() + +/** + * @brief Reads an I/O port. + * @details This function is implemented by reading the GPIO IDR register, the + * implementation has no side effects. + * @note This function is not meant to be invoked directly by the application + * code. + * + * @param[in] port port identifier + * @return The port bits. + * + * @notapi + */ +#define pal_lld_readport(port) ((ioportmask_t)((port)->IDR)) + +/** + * @brief Reads the output latch. + * @details This function is implemented by reading the GPIO ODR register, the + * implementation has no side effects. + * @note This function is not meant to be invoked directly by the application + * code. + * + * @param[in] port port identifier + * @return The latched logical states. + * + * @notapi + */ +#define pal_lld_readlatch(port) ((ioportmask_t)((port)->ODR)) + +/** + * @brief Writes on a I/O port. + * @details This function is implemented by writing the GPIO ODR register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] bits bits to be written on the specified port + * + * @notapi + */ +#define pal_lld_writeport(port, bits) ((port)->ODR = (uint32_t)(bits)) + +/** + * @brief Sets a bits mask on a I/O port. + * @details This function is implemented by writing the GPIO BSRR register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] bits bits to be ORed on the specified port + * + * @notapi + */ +#define pal_lld_setport(port, bits) ((port)->BSRR.H.set = (uint16_t)(bits)) + +/** + * @brief Clears a bits mask on a I/O port. + * @details This function is implemented by writing the GPIO BSRR register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] bits bits to be cleared on the specified port + * + * @notapi + */ +#define pal_lld_clearport(port, bits) ((port)->BSRR.H.clear = (uint16_t)(bits)) + +/** + * @brief Writes a group of bits. + * @details This function is implemented by writing the GPIO BSRR register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset the group bit offset within the port + * @param[in] bits bits to be written. Values exceeding the group + * width are masked. + * + * @notapi + */ +#define pal_lld_writegroup(port, mask, offset, bits) { \ + uint32_t w = ((~(uint32_t)(bits) & (uint32_t)(mask)) << (16U + (offset))) | \ + ((uint32_t)(bits) & (uint32_t)(mask)) << (offset); \ + (port)->BSRR.W = w; \ +} + +/** + * @brief Pads group mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @param[in] mode group mode + * + * @notapi + */ +#define pal_lld_setgroupmode(port, mask, offset, mode) \ + _pal_lld_setgroupmode(port, mask << offset, mode) + +/** + * @brief Writes a logical state on an output pad. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] bit logical value, the value must be @p PAL_LOW or + * @p PAL_HIGH + * + * @notapi + */ +#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit) + +/** + * @brief Pad event enable. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] mode pad event mode + * + * @notapi + */ +#define pal_lld_enablepadevent(port, pad, mode) \ + _pal_lld_enablepadevent(port, pad, mode) + +/** + * @brief Pad event disable. + * @details This function disables previously programmed event callbacks. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_disablepadevent(port, pad) \ + _pal_lld_disablepadevent(port, pad) + +/** + * @brief Returns a PAL event structure associated to a pad. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_get_pad_event(port, pad) \ + &_pal_events[pad]; (void)(port) + +/** + * @brief Returns a PAL event structure associated to a line. + * + * @param[in] line line identifier + * + * @notapi + */ +#define pal_lld_get_line_event(line) \ + &_pal_events[PAL_PAD(line)] + +/** + * @brief Pad event enable check. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @return Pad event status. + * @retval false if the pad event is disabled. + * @retval true if the pad event is enabled. + * + * @notapi + */ +#define pal_lld_ispadeventenabled(port, pad) \ + (bool)((EXTI->IMR1 & (1U << (uint32_t)pad)) != 0U) + +#if !defined(__DOXYGEN__) +#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) +extern palevent_t _pal_events[16]; +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void _pal_lld_init(void); + void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode); + void _pal_lld_enablepadevent(ioportid_t port, + iopadid_t pad, + ioeventmode_t mode); + void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_PAL */ + +#endif /* HAL_PAL_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/stm32_gpio.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/stm32_gpio.h new file mode 100644 index 0000000..c8ce1df --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/stm32_gpio.h @@ -0,0 +1,113 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file GPIOv3/stm32_gpio.h + * @brief STM32 GPIO units common header. + * @note This file requires definitions from the ST STM32 header file. + * + * @addtogroup STM32_GPIOv3 + * @{ + */ + +#ifndef STM32_GPIO_H +#define STM32_GPIO_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* Discarded definitions from the ST headers, the PAL driver uses its own + definitions in order to have an unified handling for all devices. + Unfortunately the ST headers have no uniform definitions for the same + objects across the various sub-families.*/ +#undef GPIOA +#undef GPIOB +#undef GPIOC +#undef GPIOD +#undef GPIOE +#undef GPIOF +#undef GPIOG +#undef GPIOH +#undef GPIOI +#undef GPIOJ +#undef GPIOK + +/** + * @name GPIO ports definitions + * @{ + */ +#define GPIOA ((stm32_gpio_t *)GPIOA_BASE) +#define GPIOB ((stm32_gpio_t *)GPIOB_BASE) +#define GPIOC ((stm32_gpio_t *)GPIOC_BASE) +#define GPIOD ((stm32_gpio_t *)GPIOD_BASE) +#define GPIOE ((stm32_gpio_t *)GPIOE_BASE) +#define GPIOF ((stm32_gpio_t *)GPIOF_BASE) +#define GPIOG ((stm32_gpio_t *)GPIOG_BASE) +#define GPIOH ((stm32_gpio_t *)GPIOH_BASE) +#define GPIOI ((stm32_gpio_t *)GPIOI_BASE) +#define GPIOJ ((stm32_gpio_t *)GPIOJ_BASE) +#define GPIOK ((stm32_gpio_t *)GPIOK_BASE) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief STM32 GPIO registers block. + */ +typedef struct { + + volatile uint32_t MODER; + volatile uint32_t OTYPER; + volatile uint32_t OSPEEDR; + volatile uint32_t PUPDR; + volatile uint32_t IDR; + volatile uint32_t ODR; + volatile union { + uint32_t W; + struct { + uint16_t set; + uint16_t clear; + } H; + } BSRR; + volatile uint32_t LOCKR; + volatile uint32_t AFRL; + volatile uint32_t AFRH; + volatile uint32_t BRR; + volatile uint32_t ASCR; +} stm32_gpio_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#endif /* STM32_GPIO_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/driver.mk new file mode 100644 index 0000000..476dcb8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/driver.mk @@ -0,0 +1,21 @@ +ifeq ($(USE_HAL_I2C_FALLBACK),yes) + # Fallback SW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + else + PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C +else + # Default HW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c + endif + else + PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c + endif + PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1 +endif diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c new file mode 100644 index 0000000..3fc2289 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c @@ -0,0 +1,889 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file I2Cv1/hal_i2c_lld.c + * @brief STM32 I2C subsystem low level driver source. + * + * @addtogroup I2C + * @{ + */ + +#include "hal.h" + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define I2C1_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM, \ + STM32_I2C1_RX_DMA_CHN) + +#define I2C1_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM, \ + STM32_I2C1_TX_DMA_CHN) + +#define I2C2_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM, \ + STM32_I2C2_RX_DMA_CHN) + +#define I2C2_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM, \ + STM32_I2C2_TX_DMA_CHN) + +#define I2C3_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM, \ + STM32_I2C3_RX_DMA_CHN) + +#define I2C3_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM, \ + STM32_I2C3_TX_DMA_CHN) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define I2C_EV5_MASTER_MODE_SELECT \ + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_SB)) + +#define I2C_EV5_MASTER_MODE_SELECT_NO_BUSY \ + ((uint32_t)((I2C_SR2_MSL << 16) | I2C_SR1_SB)) + +#define I2C_EV6_MASTER_TRA_MODE_SELECTED \ + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \ + I2C_SR1_ADDR | I2C_SR1_TXE)) + +#define I2C_EV6_MASTER_REC_MODE_SELECTED \ + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR)) + +#define I2C_EV8_2_MASTER_BYTE_TRANSMITTED \ + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \ + I2C_SR1_BTF | I2C_SR1_TXE)) + +#define I2C_EV9_MASTER_ADD10 \ + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_ADD10)) + +#define I2C_EV_MASK 0x00FFFFFF + +#define I2C_ERROR_MASK \ + ((uint16_t)(I2C_SR1_BERR | I2C_SR1_ARLO | I2C_SR1_AF | I2C_SR1_OVR | \ + I2C_SR1_PECERR | I2C_SR1_TIMEOUT | I2C_SR1_SMBALERT)) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief I2C1 driver identifier.*/ +#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) +I2CDriver I2CD1; +#endif + +/** @brief I2C2 driver identifier.*/ +#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) +I2CDriver I2CD2; +#endif + +/** @brief I2C3 driver identifier.*/ +#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) +I2CDriver I2CD3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Aborts an I2C transaction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_abort_operation(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + + /* Stops the I2C peripheral.*/ + dp->CR1 = I2C_CR1_SWRST; + dp->CR1 = 0; + dp->CR2 = 0; + dp->SR1 = 0; + + /* Stops the associated DMA streams.*/ + dmaStreamDisable(i2cp->dmatx); + dmaStreamDisable(i2cp->dmarx); +} + +/** + * @brief Set clock speed. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_set_clock(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + uint16_t regCCR, clock_div; + int32_t clock_speed = i2cp->config->clock_speed; + i2cdutycycle_t duty = i2cp->config->duty_cycle; + + osalDbgCheck((i2cp != NULL) && + (clock_speed > 0) && + (clock_speed <= 400000)); + + /* CR2 Configuration.*/ + dp->CR2 &= (uint16_t)~I2C_CR2_FREQ; + dp->CR2 |= (uint16_t)I2C_CLK_FREQ; + + /* CCR Configuration.*/ + regCCR = 0; + clock_div = I2C_CCR_CCR; + + if (clock_speed <= 100000) { + /* Configure clock_div in standard mode.*/ + osalDbgAssert(duty == STD_DUTY_CYCLE, "invalid standard mode duty cycle"); + + /* Standard mode clock_div calculate: Tlow/Thigh = 1/1.*/ + osalDbgAssert((STM32_PCLK1 % (clock_speed * 2)) == 0, + "PCLK1 must be divisible without remainder"); + clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 2)); + + osalDbgAssert(clock_div >= 0x04, + "clock divider less then 0x04 not allowed"); + regCCR |= (clock_div & I2C_CCR_CCR); + + /* Sets the Maximum Rise Time for standard mode.*/ + dp->TRISE = I2C_CLK_FREQ + 1; + } + else if (clock_speed <= 400000) { + /* Configure clock_div in fast mode.*/ + osalDbgAssert((duty == FAST_DUTY_CYCLE_2) || + (duty == FAST_DUTY_CYCLE_16_9), + "invalid fast mode duty cycle"); + + if (duty == FAST_DUTY_CYCLE_2) { + /* Fast mode clock_div calculate: Tlow/Thigh = 2/1.*/ + osalDbgAssert((STM32_PCLK1 % (clock_speed * 3)) == 0, + "PCLK1 must be divided without remainder"); + clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 3)); + } + else if (duty == FAST_DUTY_CYCLE_16_9) { + /* Fast mode clock_div calculate: Tlow/Thigh = 16/9.*/ + osalDbgAssert((STM32_PCLK1 % (clock_speed * 25)) == 0, + "PCLK1 must be divided without remainder"); + clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 25)); + regCCR |= I2C_CCR_DUTY; + } + + osalDbgAssert(clock_div >= 0x01, + "clock divider less then 0x04 not allowed"); + regCCR |= (I2C_CCR_FS | (clock_div & I2C_CCR_CCR)); + + /* Sets the Maximum Rise Time for fast mode.*/ + dp->TRISE = (I2C_CLK_FREQ * 300 / 1000) + 1; + } + + osalDbgAssert((clock_div <= I2C_CCR_CCR), "the selected clock is too low"); + + dp->CCR = regCCR; +} + +/** + * @brief Set operation mode of I2C hardware. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_set_opmode(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + i2copmode_t opmode = i2cp->config->op_mode; + uint16_t regCR1; + + regCR1 = dp->CR1; + switch (opmode) { + case OPMODE_I2C: + regCR1 &= (uint16_t)~(I2C_CR1_SMBUS|I2C_CR1_SMBTYPE); + break; + case OPMODE_SMBUS_DEVICE: + regCR1 |= I2C_CR1_SMBUS; + regCR1 &= (uint16_t)~(I2C_CR1_SMBTYPE); + break; + case OPMODE_SMBUS_HOST: + regCR1 |= (I2C_CR1_SMBUS|I2C_CR1_SMBTYPE); + break; + } + dp->CR1 = regCR1; +} + +/** + * @brief I2C shared ISR code. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + uint32_t regSR2 = dp->SR2; + uint32_t event = dp->SR1; + + /* Interrupts are disabled just before dmaStreamEnable() because there + is no need of interrupts until next transaction begin. All the work is + done by the DMA.*/ + switch (I2C_EV_MASK & (event | (regSR2 << 16))) { + case I2C_EV5_MASTER_MODE_SELECT: + case I2C_EV5_MASTER_MODE_SELECT_NO_BUSY: + if ((i2cp->addr >> 8) > 0) { + /* 10-bit address: 1 1 1 1 0 X X R/W */ + dp->DR = 0xF0 | (0x6 & (i2cp->addr >> 8)) | (0x1 & i2cp->addr); + } else { + dp->DR = i2cp->addr; + } + break; + case I2C_EV9_MASTER_ADD10: + /* Set second addr byte (10-bit addressing)*/ + dp->DR = (0xFF & (i2cp->addr >> 1)); + break; + case I2C_EV6_MASTER_REC_MODE_SELECTED: + dp->CR2 &= ~I2C_CR2_ITEVTEN; + dmaStreamEnable(i2cp->dmarx); + dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */ + if (dmaStreamGetTransactionSize(i2cp->dmarx) < 2) + dp->CR1 &= ~I2C_CR1_ACK; + break; + case I2C_EV6_MASTER_TRA_MODE_SELECTED: + dp->CR2 &= ~I2C_CR2_ITEVTEN; + dmaStreamEnable(i2cp->dmatx); + break; + case I2C_EV8_2_MASTER_BYTE_TRANSMITTED: + /* Catches BTF event after the end of transmission.*/ + (void)dp->DR; /* clear BTF.*/ + if (dmaStreamGetTransactionSize(i2cp->dmarx) > 0) { + /* Starts "read after write" operation, LSB = 1 -> receive.*/ + i2cp->addr |= 0x01; + dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK; + return; + } + dp->CR2 &= ~I2C_CR2_ITEVTEN; + dp->CR1 |= I2C_CR1_STOP; + _i2c_wakeup_isr(i2cp); + break; + default: + break; + } + /* Clear ADDR flag. */ + if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10)) + (void)dp->SR2; + + /* Errata 2.4.6 for STM32F40x, Spurious Bus Error detection in Master mode.*/ + if (event & I2C_SR1_BERR) { + dp->SR1 &= ~I2C_SR1_BERR; + } +} + +/** + * @brief DMA RX end IRQ handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] flags pre-shifted content of the ISR register + * + * @notapi + */ +static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp, uint32_t flags) { + I2C_TypeDef *dp = i2cp->i2c; + + /* DMA errors handling.*/ +#if defined(STM32_I2C_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_I2C_DMA_ERROR_HOOK(i2cp); + } +#else + (void)flags; +#endif + + dmaStreamDisable(i2cp->dmarx); + + dp->CR2 &= ~I2C_CR2_LAST; + dp->CR1 &= ~I2C_CR1_ACK; + dp->CR1 |= I2C_CR1_STOP; + _i2c_wakeup_isr(i2cp); +} + +/** + * @brief DMA TX end IRQ handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) { + I2C_TypeDef *dp = i2cp->i2c; + + /* DMA errors handling.*/ +#if defined(STM32_I2C_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_I2C_DMA_ERROR_HOOK(i2cp); + } +#else + (void)flags; +#endif + + dmaStreamDisable(i2cp->dmatx); + /* Enables interrupts to catch BTF event meaning transmission part complete. + Interrupt handler will decide to generate STOP or to begin receiving part + of R/W transaction itself.*/ + dp->CR2 |= I2C_CR2_ITEVTEN; +} + +/** + * @brief I2C error handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] sr content of the SR1 register to be decoded + * + * @notapi + */ +static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) { + + /* Clears interrupt flags just to be safe.*/ + dmaStreamDisable(i2cp->dmatx); + dmaStreamDisable(i2cp->dmarx); + + i2cp->errors = I2C_NO_ERROR; + + if (sr & I2C_SR1_BERR) { /* Bus error. */ + i2cp->errors |= I2C_BUS_ERROR; + /* Errata 2.4.6 for STM32F40x, Spurious Bus Error detection in + Master mode.*/ + i2cp->i2c->SR1 &= ~I2C_SR1_BERR; + } + + if (sr & I2C_SR1_ARLO) /* Arbitration lost. */ + i2cp->errors |= I2C_ARBITRATION_LOST; + + if (sr & I2C_SR1_AF) { /* Acknowledge fail. */ + i2cp->i2c->CR2 &= ~I2C_CR2_ITEVTEN; + i2cp->i2c->CR1 |= I2C_CR1_STOP; /* Setting stop bit. */ + i2cp->errors |= I2C_ACK_FAILURE; + } + + if (sr & I2C_SR1_OVR) /* Overrun. */ + i2cp->errors |= I2C_OVERRUN; + + if (sr & I2C_SR1_TIMEOUT) /* SMBus Timeout. */ + i2cp->errors |= I2C_TIMEOUT; + + if (sr & I2C_SR1_PECERR) /* PEC error. */ + i2cp->errors |= I2C_PEC_ERROR; + + if (sr & I2C_SR1_SMBALERT) /* SMBus alert. */ + i2cp->errors |= I2C_SMB_ALERT; + + /* If some error has been identified then sends wakes the waiting thread.*/ + if (i2cp->errors != I2C_NO_ERROR) + _i2c_wakeup_error_isr(i2cp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) +/** + * @brief I2C1 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + i2c_lld_serve_event_interrupt(&I2CD1); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief I2C1 error interrupt handler. + */ +OSAL_IRQ_HANDLER(STM32_I2C1_ERROR_HANDLER) { + uint16_t sr = I2CD1.i2c->SR1; + + OSAL_IRQ_PROLOGUE(); + + I2CD1.i2c->SR1 = ~(sr & I2C_ERROR_MASK); + i2c_lld_serve_error_interrupt(&I2CD1, sr); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_I2C_USE_I2C1 */ + +#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) +/** + * @brief I2C2 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + i2c_lld_serve_event_interrupt(&I2CD2); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief I2C2 error interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C2_ERROR_HANDLER) { + uint16_t sr = I2CD2.i2c->SR1; + + OSAL_IRQ_PROLOGUE(); + + I2CD2.i2c->SR1 = ~(sr & I2C_ERROR_MASK); + i2c_lld_serve_error_interrupt(&I2CD2, sr); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_I2C_USE_I2C2 */ + +#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) +/** + * @brief I2C3 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + i2c_lld_serve_event_interrupt(&I2CD3); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief I2C3 error interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C3_ERROR_HANDLER) { + uint16_t sr = I2CD3.i2c->SR1; + + OSAL_IRQ_PROLOGUE(); + + I2CD3.i2c->SR1 = ~(sr & I2C_ERROR_MASK); + i2c_lld_serve_error_interrupt(&I2CD3, sr); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_I2C_USE_I2C3 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2C driver initialization. + * + * @notapi + */ +void i2c_lld_init(void) { + +#if STM32_I2C_USE_I2C1 + i2cObjectInit(&I2CD1); + I2CD1.thread = NULL; + I2CD1.i2c = I2C1; + I2CD1.dmarx = NULL; + I2CD1.dmatx = NULL; +#endif /* STM32_I2C_USE_I2C1 */ + +#if STM32_I2C_USE_I2C2 + i2cObjectInit(&I2CD2); + I2CD2.thread = NULL; + I2CD2.i2c = I2C2; + I2CD2.dmarx = NULL; + I2CD2.dmatx = NULL; +#endif /* STM32_I2C_USE_I2C2 */ + +#if STM32_I2C_USE_I2C3 + i2cObjectInit(&I2CD3); + I2CD3.thread = NULL; + I2CD3.i2c = I2C3; + I2CD3.dmarx = NULL; + I2CD3.dmatx = NULL; +#endif /* STM32_I2C_USE_I2C3 */ +} + +/** + * @brief Configures and activates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_start(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + + /* If in stopped state then enables the I2C and DMA clocks.*/ + if (i2cp->state == I2C_STOP) { + + i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | + STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DIR_M2P; + i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | + STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DIR_P2M; + +#if STM32_I2C_USE_I2C1 + if (&I2CD1 == i2cp) { + rccResetI2C1(); + + i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C1_RX_DMA_STREAM, + STM32_I2C_I2C1_IRQ_PRIORITY, + (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq, + (void *)i2cp); + osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream"); + i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C1_TX_DMA_STREAM, + STM32_I2C_I2C1_IRQ_PRIORITY, + (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq, + (void *)i2cp); + osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); + + rccEnableI2C1(true); + nvicEnableVector(I2C1_EV_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY); + nvicEnableVector(I2C1_ER_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY); + + i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); + } +#endif /* STM32_I2C_USE_I2C1 */ + +#if STM32_I2C_USE_I2C2 + if (&I2CD2 == i2cp) { + rccResetI2C2(); + + i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C2_RX_DMA_STREAM, + STM32_I2C_I2C2_IRQ_PRIORITY, + (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq, + (void *)i2cp); + osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream"); + i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C2_TX_DMA_STREAM, + STM32_I2C_I2C2_IRQ_PRIORITY, + (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq, + (void *)i2cp); + osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); + + rccEnableI2C2(true); + nvicEnableVector(I2C2_EV_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY); + nvicEnableVector(I2C2_ER_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY); + + i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); + } +#endif /* STM32_I2C_USE_I2C2 */ + +#if STM32_I2C_USE_I2C3 + if (&I2CD3 == i2cp) { + rccResetI2C3(); + + i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C3_RX_DMA_STREAM, + STM32_I2C_I2C3_IRQ_PRIORITY, + (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq, + (void *)i2cp); + osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream"); + i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C3_TX_DMA_STREAM, + STM32_I2C_I2C3_IRQ_PRIORITY, + (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq, + (void *)i2cp); + osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); + + rccEnableI2C3(true); + nvicEnableVector(I2C3_EV_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY); + nvicEnableVector(I2C3_ER_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY); + + i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); + } +#endif /* STM32_I2C_USE_I2C3 */ + } + + /* I2C registers pointed by the DMA.*/ + dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR); + dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR); + + /* Reset i2c peripheral.*/ + dp->CR1 = I2C_CR1_SWRST; + dp->CR1 = 0; + dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN; + + /* Setup I2C parameters.*/ + i2c_lld_set_clock(i2cp); + i2c_lld_set_opmode(i2cp); + + /* Ready to go.*/ + dp->CR1 |= I2C_CR1_PE; +} + +/** + * @brief Deactivates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_stop(I2CDriver *i2cp) { + + /* If not in stopped state then disables the I2C clock.*/ + if (i2cp->state != I2C_STOP) { + + /* I2C disable.*/ + i2c_lld_abort_operation(i2cp); + dmaStreamFreeI(i2cp->dmatx); + dmaStreamFreeI(i2cp->dmarx); + i2cp->dmatx = NULL; + i2cp->dmarx = NULL; + +#if STM32_I2C_USE_I2C1 + if (&I2CD1 == i2cp) { + nvicDisableVector(I2C1_EV_IRQn); + nvicDisableVector(I2C1_ER_IRQn); + rccDisableI2C1(); + } +#endif + +#if STM32_I2C_USE_I2C2 + if (&I2CD2 == i2cp) { + nvicDisableVector(I2C2_EV_IRQn); + nvicDisableVector(I2C2_ER_IRQn); + rccDisableI2C2(); + } +#endif + +#if STM32_I2C_USE_I2C3 + if (&I2CD3 == i2cp) { + nvicDisableVector(I2C3_EV_IRQn); + nvicDisableVector(I2C3_ER_IRQn); + rccDisableI2C3(); + } +#endif + } +} + +/** + * @brief Receives data via the I2C bus as master. + * @details Number of receiving bytes must be more than 1 on STM32F1x. This is + * hardware restriction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + I2C_TypeDef *dp = i2cp->i2c; + systime_t start, end; + msg_t msg; + +#if defined(STM32F1XX_I2C) + osalDbgCheck(rxbytes > 1); +#endif + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Initializes driver fields, LSB = 1 -> receive.*/ + i2cp->addr = (addr << 1) | 0x01; + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + + /* RX DMA setup.*/ + dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); + dmaStreamSetMemory0(i2cp->dmarx, rxbuf); + dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT)); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { + osalSysLock(); + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if (!(dp->SR2 & I2C_SR2_BUSY) && !(dp->CR1 & I2C_CR1_STOP)) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + dmaStreamDisable(i2cp->dmarx); + return MSG_TIMEOUT; + } + + osalSysUnlock(); + } + + /* Starts the operation.*/ + dp->CR2 |= I2C_CR2_ITEVTEN; + dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK; + + /* Waits for the operation completion or a timeout.*/ + msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + if (msg != MSG_OK) { + dmaStreamDisable(i2cp->dmarx); + } + + return msg; +} + +/** + * @brief Transmits data via the I2C bus as master. + * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x. + * This is hardware restriction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[in] txbuf pointer to the transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + I2C_TypeDef *dp = i2cp->i2c; + systime_t start, end; + msg_t msg; + +#if defined(STM32F1XX_I2C) + osalDbgCheck((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))); +#endif + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Initializes driver fields, LSB = 0 -> transmit.*/ + i2cp->addr = (addr << 1); + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + + /* TX DMA setup.*/ + dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); + dmaStreamSetMemory0(i2cp->dmatx, txbuf); + dmaStreamSetTransactionSize(i2cp->dmatx, txbytes); + + /* RX DMA setup.*/ + dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); + dmaStreamSetMemory0(i2cp->dmarx, rxbuf); + dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT)); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { + osalSysLock(); + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if (!(dp->SR2 & I2C_SR2_BUSY) && !(dp->CR1 & I2C_CR1_STOP)) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + dmaStreamDisable(i2cp->dmatx); + dmaStreamDisable(i2cp->dmarx); + return MSG_TIMEOUT; + } + + osalSysUnlock(); + } + + /* Starts the operation.*/ + dp->CR2 |= I2C_CR2_ITEVTEN; + dp->CR1 |= I2C_CR1_START; + + /* Waits for the operation completion or a timeout.*/ + msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + if (msg != MSG_OK) { + dmaStreamDisable(i2cp->dmatx); + dmaStreamDisable(i2cp->dmarx); + } + + return msg; +} + +#endif /* HAL_USE_I2C */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h new file mode 100644 index 0000000..1328d47 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h @@ -0,0 +1,513 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file I2Cv1/hal_i2c_lld.h + * @brief STM32 I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#ifndef HAL_I2C_LLD_H +#define HAL_I2C_LLD_H + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Peripheral clock frequency. + */ +#define I2C_CLK_FREQ ((STM32_PCLK1) / 1000000) + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief I2C1 driver enable switch. + * @details If set to @p TRUE the support for I2C1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C1 FALSE +#endif + +/** + * @brief I2C2 driver enable switch. + * @details If set to @p TRUE the support for I2C2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C2 FALSE +#endif + +/** + * @brief I2C3 driver enable switch. + * @details If set to @p TRUE the support for I2C3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C3) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C3 FALSE +#endif + +/** + * @brief I2C timeout on busy condition in milliseconds. + */ +#if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_I2C_BUSY_TIMEOUT 50 +#endif + +/** + * @brief I2C1 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C1_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2C2 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C2_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2C3 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C3_IRQ_PRIORITY 10 +#endif + +/** +* @brief I2C1 DMA priority (0..3|lowest..highest). +* @note The priority level is used for both the TX and RX DMA streams but +* because of the streams ordering the RX stream has always priority +* over the TX stream. +*/ +#if !defined(STM32_I2C_I2C1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C1_DMA_PRIORITY 1 +#endif + +/** +* @brief I2C2 DMA priority (0..3|lowest..highest). +* @note The priority level is used for both the TX and RX DMA streams but +* because of the streams ordering the RX stream has always priority +* over the TX stream. +*/ +#if !defined(STM32_I2C_I2C2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C2_DMA_PRIORITY 1 +#endif + +/** +* @brief I2C3 DMA priority (0..3|lowest..highest). +* @note The priority level is used for both the TX and RX DMA streams but +* because of the streams ordering the RX stream has always priority +* over the TX stream. +*/ +#if !defined(STM32_I2C_I2C3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C3_DMA_PRIORITY 1 +#endif + +/** + * @brief I2C DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(STM32_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") +#endif + +#if STM32_ADVANCED_DMA || defined(__DOXYGEN__) + +/** + * @brief DMA stream used for I2C1 RX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_I2C_I2C1_RX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#endif + +/** + * @brief DMA stream used for I2C1 TX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_I2C_I2C1_TX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) +#endif + +/** + * @brief DMA stream used for I2C2 RX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_I2C_I2C2_RX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#endif + +/** + * @brief DMA stream used for I2C2 TX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_I2C_I2C2_TX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#endif + +/** + * @brief DMA stream used for I2C3 RX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_I2C_I2C3_RX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#endif + +/** + * @brief DMA stream used for I2C3 TX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_I2C_I2C3_TX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#endif + +#else /* !STM32_ADVANCED_DMA */ + +/* Fixed streams for platforms using the old DMA peripheral, the values are + valid for both STM32F1xx and STM32L1xx.*/ +#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) +#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) +#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) + +#endif /* !STM32_ADVANCED_DMA*/ + +/* Flag for the whole STM32F1XX family. */ +#if defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \ + defined(STM32F10X_HD_VL) || defined(STM32F10X_LD) || \ + defined(STM32F10X_MD) || defined(STM32F10X_HD) || \ + defined(STM32F10X_XL) || defined(STM32F10X_CL) +#define STM32F1XX_I2C +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/** @brief error checks */ +#if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1 +#error "I2C1 not present in the selected device" +#endif + +#if STM32_I2C_USE_I2C2 && !STM32_HAS_I2C2 +#error "I2C2 not present in the selected device" +#endif + +#if STM32_I2C_USE_I2C3 && !STM32_HAS_I2C3 +#error "I2C3 not present in the selected device" +#endif + +#if !STM32_I2C_USE_I2C1 && !STM32_I2C_USE_I2C2 && \ + !STM32_I2C_USE_I2C3 +#error "I2C driver activated but no I2C peripheral assigned" +#endif + +#if STM32_I2C_USE_I2C1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C1" +#endif + +#if STM32_I2C_USE_I2C2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C2" +#endif + +#if STM32_I2C_USE_I2C3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C3" +#endif + +#if STM32_I2C_USE_I2C1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C1" +#endif + +#if STM32_I2C_USE_I2C2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C2" +#endif + +#if STM32_I2C_USE_I2C3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C3" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_I2C_USE_I2C1 && (!defined(STM32_I2C_I2C1_RX_DMA_STREAM) || \ + !defined(STM32_I2C_I2C1_TX_DMA_STREAM)) +#error "I2C1 DMA streams not defined" +#endif + +#if STM32_I2C_USE_I2C2 && (!defined(STM32_I2C_I2C2_RX_DMA_STREAM) || \ + !defined(STM32_I2C_I2C2_TX_DMA_STREAM)) +#error "I2C2 DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_I2C_USE_I2C1 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_RX_DMA_STREAM, \ + STM32_I2C1_RX_DMA_MSK) +#error "invalid DMA stream associated to I2C1 RX" +#endif + +#if STM32_I2C_USE_I2C1 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_TX_DMA_STREAM, \ + STM32_I2C1_TX_DMA_MSK) +#error "invalid DMA stream associated to I2C1 TX" +#endif + +#if STM32_I2C_USE_I2C2 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_RX_DMA_STREAM, \ + STM32_I2C2_RX_DMA_MSK) +#error "invalid DMA stream associated to I2C2 RX" +#endif + +#if STM32_I2C_USE_I2C2 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_TX_DMA_STREAM, \ + STM32_I2C2_TX_DMA_MSK) +#error "invalid DMA stream associated to I2C2 TX" +#endif + +#if STM32_I2C_USE_I2C3 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_RX_DMA_STREAM, \ + STM32_I2C3_RX_DMA_MSK) +#error "invalid DMA stream associated to I2C3 RX" +#endif + +#if STM32_I2C_USE_I2C3 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_TX_DMA_STREAM, \ + STM32_I2C3_TX_DMA_MSK) +#error "invalid DMA stream associated to I2C3 TX" +#endif +#endif /* STM32_ADVANCED_DMA */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/* Check clock range. */ +#if defined(STM32F4XX) +#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 42) +#error "I2C peripheral clock frequency out of range." +#endif + +#elif defined(STM32L1XX) +#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 32) +#error "I2C peripheral clock frequency out of range." +#endif + +#elif defined(STM32F2XX) +#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 30) +#error "I2C peripheral clock frequency out of range." +#endif + +#elif defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \ + defined(STM32F10X_HD_VL) +#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 24) +#error "I2C peripheral clock frequency out of range." +#endif + +#elif defined(STM32F10X_LD) || defined(STM32F10X_MD) || \ + defined(STM32F10X_HD) || defined(STM32F10X_XL) || \ + defined(STM32F10X_CL) +#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 36) +#error "I2C peripheral clock frequency out of range." +#endif +#else +#error "unspecified, unsupported or invalid STM32 platform" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type representing an I2C address. + */ +typedef uint16_t i2caddr_t; + +/** + * @brief Type of I2C driver condition flags. + */ +typedef uint32_t i2cflags_t; + +/** + * @brief Supported modes for the I2C bus. + */ +typedef enum { + OPMODE_I2C = 1, + OPMODE_SMBUS_DEVICE = 2, + OPMODE_SMBUS_HOST = 3, +} i2copmode_t; + +/** + * @brief Supported duty cycle modes for the I2C bus. + */ +typedef enum { + STD_DUTY_CYCLE = 1, + FAST_DUTY_CYCLE_2 = 2, + FAST_DUTY_CYCLE_16_9 = 3, +} i2cdutycycle_t; + +/** + * @brief Type of I2C driver configuration structure. + */ +typedef struct { + /* End of the mandatory fields.*/ + i2copmode_t op_mode; /**< @brief Specifies the I2C mode. */ + uint32_t clock_speed; /**< @brief Specifies the clock frequency. + @note Must be set to a value lower + than 400kHz. */ + i2cdutycycle_t duty_cycle; /**< @brief Specifies the I2C fast mode + duty cycle. */ +} I2CConfig; + +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct I2CDriver I2CDriver; + +/** + * @brief Structure representing an I2C driver. + */ +struct I2CDriver { + /** + * @brief Driver state. + */ + i2cstate_t state; + /** + * @brief Current configuration data. + */ + const I2CConfig *config; + /** + * @brief Error flags. + */ + i2cflags_t errors; +#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the bus. + */ + mutex_t mutex; +#endif /* I2C_USE_MUTUAL_EXCLUSION */ +#if defined(I2C_DRIVER_EXT_FIELDS) + I2C_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion. + */ + thread_reference_t thread; + /** + * @brief Current slave address without R/W bit. + */ + i2caddr_t addr; + /** + * @brief RX DMA mode bit mask. + */ + uint32_t rxdmamode; + /** + * @brief TX DMA mode bit mask. + */ + uint32_t txdmamode; + /** + * @brief Receive DMA channel. + */ + const stm32_dma_stream_t *dmarx; + /** + * @brief Transmit DMA channel. + */ + const stm32_dma_stream_t *dmatx; + /** + * @brief Pointer to the I2Cx registers block. + */ + I2C_TypeDef *i2c; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Get errors from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_errors(i2cp) ((i2cp)->errors) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +#if STM32_I2C_USE_I2C1 +extern I2CDriver I2CD1; +#endif + +#if STM32_I2C_USE_I2C2 +extern I2CDriver I2CD2; +#endif + +#if STM32_I2C_USE_I2C3 +extern I2CDriver I2CD3; +#endif +#endif /* !defined(__DOXYGEN__) */ + +#ifdef __cplusplus +extern "C" { +#endif + void i2c_lld_init(void); + void i2c_lld_start(I2CDriver *i2cp); + void i2c_lld_stop(I2CDriver *i2cp); + msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); + msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_I2C */ + +#endif /* HAL_I2C_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/driver.mk new file mode 100644 index 0000000..69b63ce --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/driver.mk @@ -0,0 +1,21 @@ +ifeq ($(USE_HAL_I2C_FALLBACK),yes) + # Fallback SW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + else + PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C +else + # Default HW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c + endif + else + PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c + endif + PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2 +endif diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c new file mode 100644 index 0000000..06c2858 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c @@ -0,0 +1,1169 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file I2Cv2/hal_i2c_lld.c + * @brief STM32 I2C subsystem low level driver source. + * + * @addtogroup I2C + * @{ + */ + +#include "hal.h" + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if STM32_I2C_USE_DMA == TRUE +#define DMAMODE_COMMON \ + (STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | \ + STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | \ + STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE) + +#define I2C1_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM, \ + STM32_I2C1_RX_DMA_CHN) + +#define I2C1_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM, \ + STM32_I2C1_TX_DMA_CHN) + +#define I2C2_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM, \ + STM32_I2C2_RX_DMA_CHN) + +#define I2C2_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM, \ + STM32_I2C2_TX_DMA_CHN) + +#define I2C3_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM, \ + STM32_I2C3_RX_DMA_CHN) + +#define I2C3_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM, \ + STM32_I2C3_TX_DMA_CHN) + +#define I2C4_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C4_RX_DMA_STREAM, \ + STM32_I2C4_RX_DMA_CHN) + +#define I2C4_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2C_I2C4_TX_DMA_STREAM, \ + STM32_I2C4_TX_DMA_CHN) +#endif /* STM32_I2C_USE_DMA == TRUE */ + +#if STM32_I2C_USE_DMA == TRUE +#define i2c_lld_get_rxbytes(i2cp) dmaStreamGetTransactionSize((i2cp)->dmarx) +#define i2c_lld_get_txbytes(i2cp) dmaStreamGetTransactionSize((i2cp)->dmatx) +#else +#define i2c_lld_get_rxbytes(i2cp) (i2cp)->rxbytes +#define i2c_lld_get_txbytes(i2cp) (i2cp)->txbytes +#endif + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define I2C_ERROR_MASK \ + ((uint32_t)(I2C_ISR_BERR | I2C_ISR_ARLO | I2C_ISR_OVR | I2C_ISR_PECERR | \ + I2C_ISR_TIMEOUT | I2C_ISR_ALERT)) + +#define I2C_INT_MASK \ + ((uint32_t)(I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF | I2C_ISR_NACKF | \ + I2C_ISR_ADDR | I2C_ISR_RXNE | I2C_ISR_TXIS)) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief I2C1 driver identifier.*/ +#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) +I2CDriver I2CD1; +#endif + +/** @brief I2C2 driver identifier.*/ +#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) +I2CDriver I2CD2; +#endif + +/** @brief I2C3 driver identifier.*/ +#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) +I2CDriver I2CD3; +#endif + +/** @brief I2C4 driver identifier.*/ +#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__) +I2CDriver I2CD4; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Slave address setup. + * @note The RW bit is set to zero internally. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * + * @notapi + */ +static void i2c_lld_set_address(I2CDriver *i2cp, i2caddr_t addr) { + I2C_TypeDef *dp = i2cp->i2c; + + /* Address alignment depends on the addressing mode selected.*/ + if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0U) + dp->CR2 = (uint32_t)addr << 1U; + else + dp->CR2 = (uint32_t)addr; +} + +/** + * @brief I2C RX transfer setup. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_setup_rx_transfer(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + uint32_t reload; + size_t n; + + /* The unit can transfer 255 bytes maximum in a single operation.*/ + n = i2c_lld_get_rxbytes(i2cp); + if (n > 255U) { + n = 255U; + reload = I2C_CR2_RELOAD; + } + else { + reload = 0U; + } + + /* Configures the CR2 registers with both the calculated and static + settings.*/ + dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 | + I2C_CR2_RD_WRN | (n << 16U) | reload; +} + +/** + * @brief I2C TX transfer setup. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_setup_tx_transfer(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + uint32_t reload; + size_t n; + + /* The unit can transfer 255 bytes maximum in a single operation.*/ + n = i2c_lld_get_txbytes(i2cp); + if (n > 255U) { + n = 255U; + reload = I2C_CR2_RELOAD; + } + else { + reload = 0U; + } + + /* Configures the CR2 registers with both the calculated and static + settings.*/ + dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 | + (n << 16U) | reload; +} + +/** + * @brief Aborts an I2C transaction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_abort_operation(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + + if (dp->CR1 & I2C_CR1_PE) { + /* Stops the I2C peripheral.*/ + dp->CR1 &= ~I2C_CR1_PE; + while (dp->CR1 & I2C_CR1_PE) + dp->CR1 &= ~I2C_CR1_PE; + dp->CR1 |= I2C_CR1_PE; + } + +#if STM32_I2C_USE_DMA == TRUE + /* Stops the associated DMA streams.*/ + dmaStreamDisable(i2cp->dmatx); + dmaStreamDisable(i2cp->dmarx); +#else + dp->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE); +#endif +} + +/** + * @brief I2C shared ISR code. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] isr content of the ISR register to be decoded + * + * @notapi + */ +static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) { + I2C_TypeDef *dp = i2cp->i2c; + + /* Special case of a received NACK, the transfer is aborted.*/ + if ((isr & I2C_ISR_NACKF) != 0U) { +#if STM32_I2C_USE_DMA == TRUE + /* Stops the associated DMA streams.*/ + dmaStreamDisable(i2cp->dmatx); + dmaStreamDisable(i2cp->dmarx); +#endif + + /* Error flag.*/ + i2cp->errors |= I2C_ACK_FAILURE; + + /* Transaction finished sending the STOP.*/ + dp->CR2 |= I2C_CR2_STOP; + + /* Make sure no more interrupts.*/ + dp->CR1 &= ~(I2C_CR1_TCIE | I2C_CR1_TXIE | I2C_CR1_RXIE); + + /* Errors are signaled to the upper layer.*/ + _i2c_wakeup_error_isr(i2cp); + + return; + } + +#if STM32_I2C_USE_DMA == FALSE + /* Handling of data transfer if the DMA mode is disabled.*/ + { + uint32_t cr1 = dp->CR1; + + if (i2cp->state == I2C_ACTIVE_TX) { + /* Transmission phase.*/ + if (((cr1 &I2C_CR1_TXIE) != 0U) && ((isr & I2C_ISR_TXIS) != 0U)) { + dp->TXDR = (uint32_t)*i2cp->txptr; + i2cp->txptr++; + i2cp->txbytes--; + if (i2cp->txbytes == 0U) { + dp->CR1 &= ~I2C_CR1_TXIE; + } + } + } + else { + /* Receive phase.*/ + if (((cr1 & I2C_CR1_RXIE) != 0U) && ((isr & I2C_ISR_RXNE) != 0U)) { + *i2cp->rxptr = (uint8_t)dp->RXDR; + i2cp->rxptr++; + i2cp->rxbytes--; + if (i2cp->rxbytes == 0U) { + dp->CR1 &= ~I2C_CR1_RXIE; + } + } + } + } +#endif + + /* Partial transfer handling, restarting the transfer and returning.*/ + if ((isr & I2C_ISR_TCR) != 0U) { + if (i2cp->state == I2C_ACTIVE_TX) { + i2c_lld_setup_tx_transfer(i2cp); + } + else { + i2c_lld_setup_rx_transfer(i2cp); + } + return; + } + + /* The following condition is true if a transfer phase has been completed.*/ + if ((isr & I2C_ISR_TC) != 0U) { + if (i2cp->state == I2C_ACTIVE_TX) { + /* End of the transmit phase.*/ + +#if STM32_I2C_USE_DMA == TRUE + /* Disabling TX DMA channel.*/ + dmaStreamDisable(i2cp->dmatx); +#endif + + /* Starting receive phase if necessary.*/ + if (i2c_lld_get_rxbytes(i2cp) > 0U) { + /* Setting up the peripheral.*/ + i2c_lld_setup_rx_transfer(i2cp); + +#if STM32_I2C_USE_DMA == TRUE + /* Enabling RX DMA.*/ + dmaStreamEnable(i2cp->dmarx); +#else + /* RX interrupt enabled.*/ + dp->CR1 |= I2C_CR1_RXIE; +#endif + + /* Starts the read operation.*/ + dp->CR2 |= I2C_CR2_START; + + /* State change.*/ + i2cp->state = I2C_ACTIVE_RX; + + /* Note, returning because the transaction is not over yet.*/ + return; + } + } + else { + /* End of the receive phase.*/ +#if STM32_I2C_USE_DMA == TRUE + /* Disabling RX DMA channel.*/ + dmaStreamDisable(i2cp->dmarx); +#endif + } + + /* Transaction finished sending the STOP.*/ + dp->CR2 |= I2C_CR2_STOP; + + /* Make sure no more 'Transfer Complete' interrupts.*/ + dp->CR1 &= ~I2C_CR1_TCIE; + + /* Normal transaction end.*/ + _i2c_wakeup_isr(i2cp); + } +} + +/** + * @brief I2C error handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] isr content of the ISR register to be decoded + * + * @notapi + */ +static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t isr) { + +#if STM32_I2C_USE_DMA == TRUE + /* Clears DMA interrupt flags just to be safe.*/ + dmaStreamDisable(i2cp->dmatx); + dmaStreamDisable(i2cp->dmarx); +#else + /* Disabling RX and TX interrupts.*/ + i2cp->i2c->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE); +#endif + + if (isr & I2C_ISR_BERR) + i2cp->errors |= I2C_BUS_ERROR; + + if (isr & I2C_ISR_ARLO) + i2cp->errors |= I2C_ARBITRATION_LOST; + + if (isr & I2C_ISR_OVR) + i2cp->errors |= I2C_OVERRUN; + + if (isr & I2C_ISR_TIMEOUT) + i2cp->errors |= I2C_TIMEOUT; + + /* If some error has been identified then sends wakes the waiting thread.*/ + if (i2cp->errors != I2C_NO_ERROR) + _i2c_wakeup_error_isr(i2cp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) +#if defined(STM32_I2C1_GLOBAL_HANDLER) || defined(__DOXYGEN__) +/** + * @brief I2C1 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C1_GLOBAL_HANDLER) { + uint32_t isr = I2CD1.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD1.i2c->ICR = isr; + + if (isr & I2C_ERROR_MASK) + i2c_lld_serve_error_interrupt(&I2CD1, isr); + else if (isr & I2C_INT_MASK) + i2c_lld_serve_interrupt(&I2CD1, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#elif defined(STM32_I2C1_EVENT_HANDLER) && defined(STM32_I2C1_ERROR_HANDLER) +OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) { + uint32_t isr = I2CD1.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD1.i2c->ICR = isr & I2C_INT_MASK; + + i2c_lld_serve_interrupt(&I2CD1, isr); + + OSAL_IRQ_EPILOGUE(); +} + +OSAL_IRQ_HANDLER(STM32_I2C1_ERROR_HANDLER) { + uint32_t isr = I2CD1.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD1.i2c->ICR = isr & I2C_ERROR_MASK; + + i2c_lld_serve_error_interrupt(&I2CD1, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "I2C1 interrupt handlers not defined" +#endif +#endif /* STM32_I2C_USE_I2C1 */ + +#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) +#if defined(STM32_I2C2_GLOBAL_HANDLER) || defined(__DOXYGEN__) +/** + * @brief I2C2 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C2_GLOBAL_HANDLER) { + uint32_t isr = I2CD2.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD2.i2c->ICR = isr; + + if (isr & I2C_ERROR_MASK) + i2c_lld_serve_error_interrupt(&I2CD2, isr); + else if (isr & I2C_INT_MASK) + i2c_lld_serve_interrupt(&I2CD2, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#elif defined(STM32_I2C2_EVENT_HANDLER) && defined(STM32_I2C2_ERROR_HANDLER) +OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) { + uint32_t isr = I2CD2.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD2.i2c->ICR = isr & I2C_INT_MASK; + + i2c_lld_serve_interrupt(&I2CD2, isr); + + OSAL_IRQ_EPILOGUE(); +} + +OSAL_IRQ_HANDLER(STM32_I2C2_ERROR_HANDLER) { + uint32_t isr = I2CD2.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD2.i2c->ICR = isr & I2C_ERROR_MASK; + + i2c_lld_serve_error_interrupt(&I2CD2, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "I2C2 interrupt handlers not defined" +#endif +#endif /* STM32_I2C_USE_I2C2 */ + +#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) +#if defined(STM32_I2C3_GLOBAL_HANDLER) || defined(__DOXYGEN__) +/** + * @brief I2C3 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C3_GLOBAL_HANDLER) { + uint32_t isr = I2CD3.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD3.i2c->ICR = isr; + + if (isr & I2C_ERROR_MASK) + i2c_lld_serve_error_interrupt(&I2CD3, isr); + else if (isr & I2C_INT_MASK) + i2c_lld_serve_interrupt(&I2CD3, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#elif defined(STM32_I2C3_EVENT_HANDLER) && defined(STM32_I2C3_ERROR_HANDLER) +OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) { + uint32_t isr = I2CD3.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD3.i2c->ICR = isr & I2C_INT_MASK; + + i2c_lld_serve_interrupt(&I2CD3, isr); + + OSAL_IRQ_EPILOGUE(); +} + +OSAL_IRQ_HANDLER(STM32_I2C3_ERROR_HANDLER) { + uint32_t isr = I2CD3.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD3.i2c->ICR = isr & I2C_ERROR_MASK; + + i2c_lld_serve_error_interrupt(&I2CD3, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "I2C3 interrupt handlers not defined" +#endif +#endif /* STM32_I2C_USE_I2C3 */ + +#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__) +#if defined(STM32_I2C4_GLOBAL_HANDLER) || defined(__DOXYGEN__) +/** + * @brief I2C4 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C4_GLOBAL_HANDLER) { + uint32_t isr = I2CD4.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD4.i2c->ICR = isr; + + if (isr & I2C_ERROR_MASK) + i2c_lld_serve_error_interrupt(&I2CD4, isr); + else if (isr & I2C_INT_MASK) + i2c_lld_serve_interrupt(&I2CD4, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#elif defined(STM32_I2C4_EVENT_HANDLER) && defined(STM32_I2C4_ERROR_HANDLER) +OSAL_IRQ_HANDLER(STM32_I2C4_EVENT_HANDLER) { + uint32_t isr = I2CD4.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD4.i2c->ICR = isr & I2C_INT_MASK; + + i2c_lld_serve_interrupt(&I2CD4, isr); + + OSAL_IRQ_EPILOGUE(); +} + +OSAL_IRQ_HANDLER(STM32_I2C4_ERROR_HANDLER) { + uint32_t isr = I2CD4.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD4.i2c->ICR = isr & I2C_ERROR_MASK; + + i2c_lld_serve_error_interrupt(&I2CD4, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "I2C4 interrupt handlers not defined" +#endif +#endif /* STM32_I2C_USE_I2C4 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2C driver initialization. + * + * @notapi + */ +void i2c_lld_init(void) { + +#if STM32_I2C_USE_I2C1 + i2cObjectInit(&I2CD1); + I2CD1.thread = NULL; + I2CD1.i2c = I2C1; +#if STM32_I2C_USE_DMA == TRUE + I2CD1.dmarx = NULL; + I2CD1.dmatx = NULL; +#endif +#endif /* STM32_I2C_USE_I2C1 */ + +#if STM32_I2C_USE_I2C2 + i2cObjectInit(&I2CD2); + I2CD2.thread = NULL; + I2CD2.i2c = I2C2; +#if STM32_I2C_USE_DMA == TRUE + I2CD2.dmarx = NULL; + I2CD2.dmatx = NULL; +#endif +#endif /* STM32_I2C_USE_I2C2 */ + +#if STM32_I2C_USE_I2C3 + i2cObjectInit(&I2CD3); + I2CD3.thread = NULL; + I2CD3.i2c = I2C3; +#if STM32_I2C_USE_DMA == TRUE + I2CD3.dmarx = NULL; + I2CD3.dmatx = NULL; +#endif +#endif /* STM32_I2C_USE_I2C3 */ + +#if STM32_I2C_USE_I2C4 + i2cObjectInit(&I2CD4); + I2CD4.thread = NULL; + I2CD4.i2c = I2C4; +#if STM32_I2C_USE_DMA == TRUE + I2CD4.dmarx = NULL; + I2CD4.dmatx = NULL; +#endif +#endif /* STM32_I2C_USE_I2C4 */ +} + +/** + * @brief Configures and activates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_start(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + + /* Make sure I2C peripheral is disabled */ + dp->CR1 &= ~I2C_CR1_PE; + + /* If in stopped state then enables the I2C and DMA clocks.*/ + if (i2cp->state == I2C_STOP) { + +#if STM32_I2C_USE_DMA == TRUE + /* Common DMA modes.*/ + i2cp->txdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_M2P; + i2cp->rxdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_P2M; +#endif + +#if STM32_I2C_USE_I2C1 + if (&I2CD1 == i2cp) { + + rccResetI2C1(); + rccEnableI2C1(true); +#if STM32_I2C_USE_DMA == TRUE + { + i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C1_RX_DMA_STREAM, + STM32_I2C_I2C1_IRQ_PRIORITY, + NULL, + (void *)i2cp); + osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream"); + i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C1_TX_DMA_STREAM, + STM32_I2C_I2C1_IRQ_PRIORITY, + NULL, + (void *)i2cp); + osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); + + i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(i2cp->dmarx, STM32_DMAMUX1_I2C1_RX); + dmaSetRequestSource(i2cp->dmatx, STM32_DMAMUX1_I2C1_TX); +#endif + } +#endif /* STM32_I2C_USE_DMA == TRUE */ + +#if defined(STM32_I2C1_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicEnableVector(STM32_I2C1_GLOBAL_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY); +#elif defined(STM32_I2C1_EVENT_NUMBER) && defined(STM32_I2C1_ERROR_NUMBER) + nvicEnableVector(STM32_I2C1_EVENT_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY); + nvicEnableVector(STM32_I2C1_ERROR_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY); +#else +#error "I2C1 interrupt numbers not defined" +#endif + } +#endif /* STM32_I2C_USE_I2C1 */ + +#if STM32_I2C_USE_I2C2 + if (&I2CD2 == i2cp) { + + rccResetI2C2(); + rccEnableI2C2(true); +#if STM32_I2C_USE_DMA == TRUE + { + i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C2_RX_DMA_STREAM, + STM32_I2C_I2C2_IRQ_PRIORITY, + NULL, + (void *)i2cp); + osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream"); + i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C2_TX_DMA_STREAM, + STM32_I2C_I2C2_IRQ_PRIORITY, + NULL, + (void *)i2cp); + osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); + + i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(i2cp->dmarx, STM32_DMAMUX1_I2C2_RX); + dmaSetRequestSource(i2cp->dmatx, STM32_DMAMUX1_I2C2_TX); +#endif + } +#endif /* STM32_I2C_USE_DMA == TRUE */ + +#if defined(STM32_I2C2_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicEnableVector(STM32_I2C2_GLOBAL_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY); +#elif defined(STM32_I2C2_EVENT_NUMBER) && defined(STM32_I2C2_ERROR_NUMBER) + nvicEnableVector(STM32_I2C2_EVENT_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY); + nvicEnableVector(STM32_I2C2_ERROR_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY); +#else +#error "I2C2 interrupt numbers not defined" +#endif + } +#endif /* STM32_I2C_USE_I2C2 */ + +#if STM32_I2C_USE_I2C3 + if (&I2CD3 == i2cp) { + + rccResetI2C3(); + rccEnableI2C3(true); +#if STM32_I2C_USE_DMA == TRUE + { + i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C3_RX_DMA_STREAM, + STM32_I2C_I2C3_IRQ_PRIORITY, + NULL, + (void *)i2cp); + osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream"); + i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C3_TX_DMA_STREAM, + STM32_I2C_I2C3_IRQ_PRIORITY, + NULL, + (void *)i2cp); + osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); + + i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(i2cp->dmarx, STM32_DMAMUX1_I2C3_RX); + dmaSetRequestSource(i2cp->dmatx, STM32_DMAMUX1_I2C3_TX); +#endif + } +#endif /* STM32_I2C_USE_DMA == TRUE */ + +#if defined(STM32_I2C3_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicEnableVector(STM32_I2C3_GLOBAL_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY); +#elif defined(STM32_I2C3_EVENT_NUMBER) && defined(STM32_I2C3_ERROR_NUMBER) + nvicEnableVector(STM32_I2C3_EVENT_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY); + nvicEnableVector(STM32_I2C3_ERROR_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY); +#else +#error "I2C3 interrupt numbers not defined" +#endif + } +#endif /* STM32_I2C_USE_I2C3 */ + +#if STM32_I2C_USE_I2C4 + if (&I2CD4 == i2cp) { + + rccResetI2C4(); + rccEnableI2C4(true); +#if STM32_I2C_USE_DMA == TRUE + { + i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C4_RX_DMA_STREAM, + STM32_I2C_I2C4_IRQ_PRIORITY, + NULL, + (void *)i2cp); + osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream"); + i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C4_TX_DMA_STREAM, + STM32_I2C_I2C4_IRQ_PRIORITY, + NULL, + (void *)i2cp); + osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); + + i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C4_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C4_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(i2cp->dmarx, STM32_DMAMUX1_I2C4_RX); + dmaSetRequestSource(i2cp->dmatx, STM32_DMAMUX1_I2C4_TX); +#endif + } +#endif /* STM32_I2C_USE_DMA == TRUE */ + +#if defined(STM32_I2C4_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicEnableVector(STM32_I2C4_GLOBAL_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY); +#elif defined(STM32_I2C4_EVENT_NUMBER) && defined(STM32_I2C4_ERROR_NUMBER) + nvicEnableVector(STM32_I2C4_EVENT_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY); + nvicEnableVector(STM32_I2C4_ERROR_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY); +#else +#error "I2C4 interrupt numbers not defined" +#endif + } +#endif /* STM32_I2C_USE_I2C4 */ + } + +#if STM32_I2C_USE_DMA == TRUE + /* I2C registers pointed by the DMA.*/ + dmaStreamSetPeripheral(i2cp->dmarx, &dp->RXDR); + dmaStreamSetPeripheral(i2cp->dmatx, &dp->TXDR); +#endif + + /* Reset i2c peripheral, the TCIE bit will be handled separately.*/ + dp->CR1 = i2cp->config->cr1 | +#if STM32_I2C_USE_DMA == TRUE + I2C_CR1_TXDMAEN | I2C_CR1_RXDMAEN | /* Enable only if using DMA */ +#endif + I2C_CR1_ERRIE | I2C_CR1_NACKIE; + + /* Setup I2C parameters.*/ + dp->TIMINGR = i2cp->config->timingr; + + /* Ready to go.*/ + dp->CR1 |= I2C_CR1_PE; +} + +/** + * @brief Deactivates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_stop(I2CDriver *i2cp) { + + /* If not in stopped state then disables the I2C clock.*/ + if (i2cp->state != I2C_STOP) { + + /* I2C disable.*/ + i2c_lld_abort_operation(i2cp); +#if STM32_I2C_USE_DMA == TRUE + dmaStreamFreeI(i2cp->dmatx); + dmaStreamFreeI(i2cp->dmarx); + i2cp->dmatx = NULL; + i2cp->dmarx = NULL; +#endif + +#if STM32_I2C_USE_I2C1 + if (&I2CD1 == i2cp) { +#if defined(STM32_I2C1_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicDisableVector(STM32_I2C1_GLOBAL_NUMBER); +#elif defined(STM32_I2C1_EVENT_NUMBER) && defined(STM32_I2C1_ERROR_NUMBER) + nvicDisableVector(STM32_I2C1_EVENT_NUMBER); + nvicDisableVector(STM32_I2C1_ERROR_NUMBER); +#else +#error "I2C1 interrupt numbers not defined" +#endif + + rccDisableI2C1(); + } +#endif + +#if STM32_I2C_USE_I2C2 + if (&I2CD2 == i2cp) { +#if defined(STM32_I2C2_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicDisableVector(STM32_I2C2_GLOBAL_NUMBER); +#elif defined(STM32_I2C2_EVENT_NUMBER) && defined(STM32_I2C2_ERROR_NUMBER) + nvicDisableVector(STM32_I2C2_EVENT_NUMBER); + nvicDisableVector(STM32_I2C2_ERROR_NUMBER); +#else +#error "I2C2 interrupt numbers not defined" +#endif + + rccDisableI2C2(); + } +#endif + +#if STM32_I2C_USE_I2C3 + if (&I2CD3 == i2cp) { +#if defined(STM32_I2C3_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicDisableVector(STM32_I2C3_GLOBAL_NUMBER); +#elif defined(STM32_I2C3_EVENT_NUMBER) && defined(STM32_I2C3_ERROR_NUMBER) + nvicDisableVector(STM32_I2C3_EVENT_NUMBER); + nvicDisableVector(STM32_I2C3_ERROR_NUMBER); +#else +#error "I2C3 interrupt numbers not defined" +#endif + + rccDisableI2C3(); + } +#endif + +#if STM32_I2C_USE_I2C4 + if (&I2CD4 == i2cp) { +#if defined(STM32_I2C4_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicDisableVector(STM32_I2C4_GLOBAL_NUMBER); +#elif defined(STM32_I2C4_EVENT_NUMBER) && defined(STM32_I2C4_ERROR_NUMBER) + nvicDisableVector(STM32_I2C4_EVENT_NUMBER); + nvicDisableVector(STM32_I2C4_ERROR_NUMBER); +#else +#error "I2C4 interrupt numbers not defined" +#endif + + rccDisableI2C4(); + } +#endif + } +} + +/** + * @brief Receives data via the I2C bus as master. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + msg_t msg; + I2C_TypeDef *dp = i2cp->i2c; + systime_t start, end; + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + +#if STM32_I2C_USE_DMA == TRUE + /* RX DMA setup.*/ + dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); + dmaStreamSetMemory0(i2cp->dmarx, rxbuf); + dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); +#else + i2cp->rxptr = rxbuf; + i2cp->rxbytes = rxbytes; +#endif + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT)); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { + osalSysLock(); + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if ((dp->ISR & I2C_ISR_BUSY) == 0) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + return MSG_TIMEOUT; + } + + osalSysUnlock(); + } + + /* Setting up the slave address.*/ + i2c_lld_set_address(i2cp, addr); + + /* Setting up the peripheral.*/ + i2c_lld_setup_rx_transfer(i2cp); + +#if STM32_I2C_USE_DMA == TRUE + /* Enabling RX DMA.*/ + dmaStreamEnable(i2cp->dmarx); + + /* Transfer complete interrupt enabled.*/ + dp->CR1 |= I2C_CR1_TCIE; +#else + + /* Transfer complete and RX interrupts enabled.*/ + dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_RXIE; +#endif + + /* Starts the operation.*/ + dp->CR2 |= I2C_CR2_START; + + /* Waits for the operation completion or a timeout.*/ + msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + + /* In case of a software timeout a STOP is sent as an extreme attempt + to release the bus and DMA is forcibly disabled.*/ + if (msg == MSG_TIMEOUT) { + dp->CR2 |= I2C_CR2_STOP; +#if STM32_I2C_USE_DMA == TRUE + dmaStreamDisable(i2cp->dmarx); +#endif + } + + return msg; +} + +/** + * @brief Transmits data via the I2C bus as master. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[in] txbuf pointer to the transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + msg_t msg; + I2C_TypeDef *dp = i2cp->i2c; + systime_t start, end; + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + +#if STM32_I2C_USE_DMA == TRUE + /* TX DMA setup.*/ + dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); + dmaStreamSetMemory0(i2cp->dmatx, txbuf); + dmaStreamSetTransactionSize(i2cp->dmatx, txbytes); + + /* RX DMA setup, note, rxbytes can be zero but we write the value anyway.*/ + dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); + dmaStreamSetMemory0(i2cp->dmarx, rxbuf); + dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); +#else + i2cp->txptr = txbuf; + i2cp->txbytes = txbytes; + i2cp->rxptr = rxbuf; + i2cp->rxbytes = rxbytes; +#endif + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT)); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { + osalSysLock(); + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if ((dp->ISR & I2C_ISR_BUSY) == 0) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + return MSG_TIMEOUT; + } + + osalSysUnlock(); + } + + /* Setting up the slave address.*/ + i2c_lld_set_address(i2cp, addr); + + /* Preparing the transfer.*/ + i2c_lld_setup_tx_transfer(i2cp); + +#if STM32_I2C_USE_DMA == TRUE + /* Enabling TX DMA.*/ + dmaStreamEnable(i2cp->dmatx); + + /* Transfer complete interrupt enabled.*/ + dp->CR1 |= I2C_CR1_TCIE; +#else + /* Transfer complete and TX interrupts enabled.*/ + dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_TXIE; +#endif + + /* Starts the operation.*/ + dp->CR2 |= I2C_CR2_START; + + /* Waits for the operation completion or a timeout.*/ + msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + + /* In case of a software timeout a STOP is sent as an extreme attempt + to release the bus and DMA is forcibly disabled.*/ + if (msg == MSG_TIMEOUT) { + dp->CR2 |= I2C_CR2_STOP; +#if STM32_I2C_USE_DMA == TRUE + dmaStreamDisable(i2cp->dmarx); + dmaStreamDisable(i2cp->dmatx); +#endif + } + + return msg; +} + +#endif /* HAL_USE_I2C */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.h new file mode 100644 index 0000000..b1004e7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.h @@ -0,0 +1,509 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file I2Cv2/hal_i2c_lld.h + * @brief STM32 I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#ifndef HAL_I2C_LLD_H +#define HAL_I2C_LLD_H + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name TIMINGR register definitions + * @{ + */ +#define STM32_TIMINGR_PRESC_MASK (15U << 28) +#define STM32_TIMINGR_PRESC(n) ((n) << 28) +#define STM32_TIMINGR_SCLDEL_MASK (15U << 20) +#define STM32_TIMINGR_SCLDEL(n) ((n) << 20) +#define STM32_TIMINGR_SDADEL_MASK (15U << 16) +#define STM32_TIMINGR_SDADEL(n) ((n) << 16) +#define STM32_TIMINGR_SCLH_MASK (255U << 8) +#define STM32_TIMINGR_SCLH(n) ((n) << 8) +#define STM32_TIMINGR_SCLL_MASK (255U << 0) +#define STM32_TIMINGR_SCLL(n) ((n) << 0) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief I2C1 driver enable switch. + * @details If set to @p TRUE the support for I2C1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C1 FALSE +#endif + +/** + * @brief I2C2 driver enable switch. + * @details If set to @p TRUE the support for I2C2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C2 FALSE +#endif + +/** + * @brief I2C3 driver enable switch. + * @details If set to @p TRUE the support for I2C3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C3) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C3 FALSE +#endif + +/** + * @brief I2C4 driver enable switch. + * @details If set to @p TRUE the support for I2C4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C4) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C4 FALSE +#endif + +/** + * @brief I2C timeout on busy condition in milliseconds. + */ +#if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_I2C_BUSY_TIMEOUT 50 +#endif + +/** + * @brief I2C1 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C1_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2C2 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C2_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2C3 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C3_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2C4 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C4_IRQ_PRIORITY 10 +#endif + +/** + * @brief DMA use switch. + */ +#if !defined(STM32_I2C_USE_DMA) || defined(__DOXYGEN__) +#define STM32_I2C_USE_DMA TRUE +#endif + +/** + * @brief I2C1 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_I2C_I2C1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C1_DMA_PRIORITY 1 +#endif + +/** + * @brief I2C2 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_I2C_I2C2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C2_DMA_PRIORITY 1 +#endif + +/** + * @brief I2C3 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_I2C_I2C3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C3_DMA_PRIORITY 1 +#endif + +/** + * @brief I2C4 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_I2C_I2C4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C4_DMA_PRIORITY 1 +#endif + +/** + * @brief I2C DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(STM32_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/** @brief error checks */ +#if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1 +#error "I2C1 not present in the selected device" +#endif + +#if STM32_I2C_USE_I2C2 && !STM32_HAS_I2C2 +#error "I2C2 not present in the selected device" +#endif + +#if STM32_I2C_USE_I2C3 && !STM32_HAS_I2C3 +#error "I2C3 not present in the selected device" +#endif + +#if STM32_I2C_USE_I2C4 && !STM32_HAS_I2C4 +#error "I2C4 not present in the selected device" +#endif + +#if !STM32_I2C_USE_I2C1 && !STM32_I2C_USE_I2C2 && !STM32_I2C_USE_I2C3 && \ + !STM32_I2C_USE_I2C4 +#error "I2C driver activated but no I2C peripheral assigned" +#endif + +#if STM32_I2C_USE_I2C1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C1" +#endif + +#if STM32_I2C_USE_I2C2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C2" +#endif + +#if STM32_I2C_USE_I2C3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C3" +#endif + +#if STM32_I2C_USE_I2C4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C4" +#endif + +#if STM32_I2C_USE_DMA == TRUE +#if STM32_I2C_USE_I2C1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C1" +#endif + +#if STM32_I2C_USE_I2C2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C2" +#endif + +#if STM32_I2C_USE_I2C3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C3" +#endif + +#if STM32_I2C_USE_I2C4 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C4" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_I2C_USE_I2C1 && (!defined(STM32_I2C_I2C1_RX_DMA_STREAM) || \ + !defined(STM32_I2C_I2C1_TX_DMA_STREAM)) +#error "I2C1 DMA streams not defined" +#endif + +#if STM32_I2C_USE_I2C2 && (!defined(STM32_I2C_I2C2_RX_DMA_STREAM) || \ + !defined(STM32_I2C_I2C2_TX_DMA_STREAM)) +#error "I2C2 DMA streams not defined" +#endif + +#if STM32_I2C_USE_I2C3 && (!defined(STM32_I2C_I2C3_RX_DMA_STREAM) || \ + !defined(STM32_I2C_I2C3_TX_DMA_STREAM)) +#error "I2C3 DMA streams not defined" +#endif + +#if STM32_I2C_USE_I2C4 && (!defined(STM32_I2C_I2C4_RX_DMA_STREAM) || \ + !defined(STM32_I2C_I2C4_TX_DMA_STREAM)) +#error "I2C4 DMA streams not defined" +#endif + +/* Devices without DMAMUX require an additional check.*/ +#if !STM32_DMA_SUPPORTS_DMAMUX + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_I2C_USE_I2C1 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_RX_DMA_STREAM, \ + STM32_I2C1_RX_DMA_MSK) +#error "invalid DMA stream associated to I2C1 RX" +#endif + +#if STM32_I2C_USE_I2C1 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_TX_DMA_STREAM, \ + STM32_I2C1_TX_DMA_MSK) +#error "invalid DMA stream associated to I2C1 TX" +#endif + +#if STM32_I2C_USE_I2C2 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_RX_DMA_STREAM, \ + STM32_I2C2_RX_DMA_MSK) +#error "invalid DMA stream associated to I2C2 RX" +#endif + +#if STM32_I2C_USE_I2C2 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_TX_DMA_STREAM, \ + STM32_I2C2_TX_DMA_MSK) +#error "invalid DMA stream associated to I2C2 TX" +#endif + +#if STM32_I2C_USE_I2C3 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_RX_DMA_STREAM, \ + STM32_I2C3_RX_DMA_MSK) +#error "invalid DMA stream associated to I2C3 RX" +#endif + +#if STM32_I2C_USE_I2C3 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_TX_DMA_STREAM, \ + STM32_I2C3_TX_DMA_MSK) +#error "invalid DMA stream associated to I2C3 TX" +#endif + +#if STM32_I2C_USE_I2C4 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C4_RX_DMA_STREAM, \ + STM32_I2C4_RX_DMA_MSK) +#error "invalid DMA stream associated to I2C4 RX" +#endif + +#if STM32_I2C_USE_I2C4 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C4_TX_DMA_STREAM, \ + STM32_I2C4_TX_DMA_MSK) +#error "invalid DMA stream associated to I2C4 TX" +#endif + +#endif /* !STM32_DMA_SUPPORTS_DMAMUX */ + +#endif /* STM32_ADVANCED_DMA */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif +#endif /* STM32_I2C_USE_DMA == TRUE */ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type representing an I2C address. + */ +typedef uint16_t i2caddr_t; + +/** + * @brief Type of I2C driver condition flags. + */ +typedef uint32_t i2cflags_t; + +/** + * @brief Type of I2C driver configuration structure. + */ +typedef struct { + /** + * @brief TIMINGR register initialization. + * @note Refer to the STM32 reference manual, the values are affected + * by the system clock settings in mcuconf.h. + */ + uint32_t timingr; + /** + * @brief CR1 register initialization. + * @note Leave to zero unless you know what you are doing. + */ + uint32_t cr1; + /** + * @brief CR2 register initialization. + * @note Only the ADD10 bit can eventually be specified here. + */ + uint32_t cr2; +} I2CConfig; + +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct I2CDriver I2CDriver; + +/** + * @brief Structure representing an I2C driver. + */ +struct I2CDriver { + /** + * @brief Driver state. + */ + i2cstate_t state; + /** + * @brief Current configuration data. + */ + const I2CConfig *config; + /** + * @brief Error flags. + */ + i2cflags_t errors; +#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) + mutex_t mutex; +#endif /* I2C_USE_MUTUAL_EXCLUSION */ +#if defined(I2C_DRIVER_EXT_FIELDS) + I2C_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion. + */ + thread_reference_t thread; +#if (STM32_I2C_USE_DMA == TRUE) || defined(__DOXYGEN__) + /** + * @brief RX DMA mode bit mask. + */ + uint32_t rxdmamode; + /** + * @brief TX DMA mode bit mask. + */ + uint32_t txdmamode; + /** + * @brief Receive DMA channel. + */ + const stm32_dma_stream_t *dmarx; + /** + * @brief Transmit DMA channel. + */ + const stm32_dma_stream_t *dmatx; +#else /* STM32_I2C_USE_DMA == FALSE */ + /** + * @brief Pointer to the next TX buffer location. + */ + const uint8_t *txptr; + /** + * @brief Number of bytes in TX phase. + */ + size_t txbytes; + /** + * @brief Pointer to the next RX buffer location. + */ + uint8_t *rxptr; + /** + * @brief Number of bytes in RX phase. + */ + size_t rxbytes; +#endif /* STM32_I2C_USE_DMA == FALSE */ + /** + * @brief Pointer to the I2Cx registers block. + */ + I2C_TypeDef *i2c; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Get errors from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_errors(i2cp) ((i2cp)->errors) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +#if STM32_I2C_USE_I2C1 +extern I2CDriver I2CD1; +#endif + +#if STM32_I2C_USE_I2C2 +extern I2CDriver I2CD2; +#endif + +#if STM32_I2C_USE_I2C3 +extern I2CDriver I2CD3; +#endif + +#if STM32_I2C_USE_I2C4 +extern I2CDriver I2CD4; +#endif + +#endif /* !defined(__DOXYGEN__) */ + +#ifdef __cplusplus +extern "C" { +#endif + void i2c_lld_init(void); + void i2c_lld_start(I2CDriver *i2cp); + void i2c_lld_stop(I2CDriver *i2cp); + msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); + msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_I2C */ + +#endif /* HAL_I2C_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/driver.mk new file mode 100644 index 0000000..ef55dfd --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/driver.mk @@ -0,0 +1,21 @@ +ifeq ($(USE_HAL_I2C_FALLBACK),yes) + # Fallback SW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + else + PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C +else + # Default HW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c + endif + else + PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c + endif + PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv3 +endif diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c new file mode 100644 index 0000000..24b1ace --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c @@ -0,0 +1,1316 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file I2Cv3/hal_i2c_lld.c + * @brief STM32 I2C subsystem low level driver source. + * + * @addtogroup I2C + * @{ + */ + +#include "hal.h" + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if STM32_I2C_USE_DMA == TRUE + +#if defined(STM32_I2C_DMA_REQUIRED) +#define DMAMODE_COMMON \ + (STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | \ + STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | \ + STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE) +#endif + +#if defined(STM32_I2C_BDMA_REQUIRED) +#define BDMAMODE_COMMON \ + (STM32_BDMA_CR_PSIZE_BYTE | STM32_BDMA_CR_MSIZE_BYTE | \ + STM32_BDMA_CR_MINC | \ + STM32_BDMA_CR_TEIE | STM32_BDMA_CR_TCIE) +#endif + +#endif /* STM32_I2C_USE_DMA == TRUE */ + +#if 0 +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#if defined(STM32_I2C_DMA_REQUIRED) + { + } +#endif +#endif + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define I2C_ERROR_MASK \ + ((uint32_t)(I2C_ISR_BERR | I2C_ISR_ARLO | I2C_ISR_OVR | I2C_ISR_PECERR | \ + I2C_ISR_TIMEOUT | I2C_ISR_ALERT)) + +#define I2C_INT_MASK \ + ((uint32_t)(I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF | I2C_ISR_NACKF | \ + I2C_ISR_ADDR | I2C_ISR_RXNE | I2C_ISR_TXIS)) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief I2C1 driver identifier.*/ +#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) +I2CDriver I2CD1; +#endif + +/** @brief I2C2 driver identifier.*/ +#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) +I2CDriver I2CD2; +#endif + +/** @brief I2C3 driver identifier.*/ +#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) +I2CDriver I2CD3; +#endif + +/** @brief I2C4 driver identifier.*/ +#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__) +I2CDriver I2CD4; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if STM32_I2C_USE_DMA == TRUE +static inline void i2c_lld_start_rx_dma(I2CDriver *i2cp) { + +#if STM32_I2C4_USE_BDMA == TRUE +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + bdmaStreamEnable(i2cp->rx.bdma); + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#endif /* STM32_I2C4_USE_BDMA == TRUE */ +#if defined(STM32_I2C_DMA_REQUIRED) + { + dmaStreamEnable(i2cp->rx.dma); + } +#endif +} + +static inline void i2c_lld_start_tx_dma(I2CDriver *i2cp) { + +#if STM32_I2C4_USE_BDMA == TRUE +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + bdmaStreamEnable(i2cp->tx.bdma); + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#endif /* STM32_I2C4_USE_BDMA == TRUE */ +#if defined(STM32_I2C_DMA_REQUIRED) + { + dmaStreamEnable(i2cp->tx.dma); + } +#endif +} + +static inline void i2c_lld_stop_rx_dma(I2CDriver *i2cp) { + +#if STM32_I2C4_USE_BDMA == TRUE +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + bdmaStreamDisable(i2cp->rx.bdma); + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#endif /* STM32_I2C4_USE_BDMA == TRUE */ +#if defined(STM32_I2C_DMA_REQUIRED) + { + dmaStreamDisable(i2cp->rx.dma); + } +#endif +} + +static inline void i2c_lld_stop_tx_dma(I2CDriver *i2cp) { + +#if STM32_I2C4_USE_BDMA == TRUE +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + bdmaStreamDisable(i2cp->tx.bdma); + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#endif /* STM32_I2C4_USE_BDMA == TRUE */ +#if defined(STM32_I2C_DMA_REQUIRED) + { + dmaStreamDisable(i2cp->tx.dma); + } +#endif +} +#endif /* STM32_I2C_USE_DMA == TRUE */ + +/** + * @brief Slave address setup. + * @note The RW bit is set to zero internally. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * + * @notapi + */ +static void i2c_lld_set_address(I2CDriver *i2cp, i2caddr_t addr) { + I2C_TypeDef *dp = i2cp->i2c; + + /* Address alignment depends on the addressing mode selected.*/ + if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0U) + dp->CR2 = (uint32_t)addr << 1U; + else + dp->CR2 = (uint32_t)addr; +} + +/** + * @brief I2C RX transfer setup. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_setup_rx_transfer(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + uint32_t reload; + size_t n; + + /* The unit can transfer 255 bytes maximum in a single operation.*/ + n = i2cp->rxbytes; + if (n > 255U) { + n = 255U; + reload = I2C_CR2_RELOAD; + } + else { + reload = 0U; + } + i2cp->rxbytes -= n; + + /* Configures the CR2 registers with both the calculated and static + settings.*/ + dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 | + I2C_CR2_RD_WRN | (n << 16U) | reload; +} + +/** + * @brief I2C TX transfer setup. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_setup_tx_transfer(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + uint32_t reload; + size_t n; + + /* The unit can transfer 255 bytes maximum in a single operation.*/ + n = i2cp->txbytes; + if (n > 255U) { + n = 255U; + reload = I2C_CR2_RELOAD; + } + else { + reload = 0U; + } + i2cp->txbytes -= n; + + /* Configures the CR2 registers with both the calculated and static + settings.*/ + dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 | + (n << 16U) | reload; +} + +/** + * @brief Aborts an I2C transaction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_abort_operation(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + + if (dp->CR1 & I2C_CR1_PE) { + /* Stops the I2C peripheral.*/ + dp->CR1 &= ~I2C_CR1_PE; + while (dp->CR1 & I2C_CR1_PE) + dp->CR1 &= ~I2C_CR1_PE; + dp->CR1 |= I2C_CR1_PE; + } + +#if STM32_I2C_USE_DMA == TRUE + /* Stops the associated DMA streams.*/ + i2c_lld_stop_rx_dma(i2cp); + i2c_lld_stop_tx_dma(i2cp); +#else + dp->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE); +#endif +} + +/** + * @brief I2C shared ISR code. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] isr content of the ISR register to be decoded + * + * @notapi + */ +static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) { + I2C_TypeDef *dp = i2cp->i2c; + + /* Special case of a received NACK, the transfer is aborted.*/ + if ((isr & I2C_ISR_NACKF) != 0U) { +#if STM32_I2C_USE_DMA == TRUE + /* Stops the associated DMA streams.*/ + i2c_lld_stop_rx_dma(i2cp); + i2c_lld_stop_tx_dma(i2cp); +#endif + + /* Error flag.*/ + i2cp->errors |= I2C_ACK_FAILURE; + + /* Transaction finished sending the STOP.*/ + dp->CR2 |= I2C_CR2_STOP; + + /* Make sure no more interrupts.*/ + dp->CR1 &= ~(I2C_CR1_TCIE | I2C_CR1_TXIE | I2C_CR1_RXIE); + + /* Errors are signaled to the upper layer.*/ + _i2c_wakeup_error_isr(i2cp); + + return; + } + +#if STM32_I2C_USE_DMA == FALSE + /* Handling of data transfer if the DMA mode is disabled.*/ + { + uint32_t cr1 = dp->CR1; + + if (i2cp->state == I2C_ACTIVE_TX) { + /* Transmission phase.*/ + if (((cr1 &I2C_CR1_TXIE) != 0U) && ((isr & I2C_ISR_TXIS) != 0U)) { + dp->TXDR = (uint32_t)*i2cp->txptr; + i2cp->txptr++; + i2cp->txbytes--; + if (i2cp->txbytes == 0U) { + dp->CR1 &= ~I2C_CR1_TXIE; + } + } + } + else { + /* Receive phase.*/ + if (((cr1 & I2C_CR1_RXIE) != 0U) && ((isr & I2C_ISR_RXNE) != 0U)) { + *i2cp->rxptr = (uint8_t)dp->RXDR; + i2cp->rxptr++; + i2cp->rxbytes--; + if (i2cp->rxbytes == 0U) { + dp->CR1 &= ~I2C_CR1_RXIE; + } + } + } + } +#endif + + /* Partial transfer handling, restarting the transfer and returning.*/ + if ((isr & I2C_ISR_TCR) != 0U) { + if (i2cp->state == I2C_ACTIVE_TX) { + i2c_lld_setup_tx_transfer(i2cp); + } + else { + i2c_lld_setup_rx_transfer(i2cp); + } + return; + } + + /* The following condition is true if a transfer phase has been completed.*/ + if ((isr & I2C_ISR_TC) != 0U) { + if (i2cp->state == I2C_ACTIVE_TX) { + /* End of the transmit phase.*/ + +#if STM32_I2C_USE_DMA == TRUE + /* Disabling TX DMA channel.*/ + i2c_lld_stop_tx_dma(i2cp); +#endif + + /* Starting receive phase if necessary.*/ + if (i2cp->rxbytes > 0U) { + /* Setting up the peripheral.*/ + i2c_lld_setup_rx_transfer(i2cp); + +#if STM32_I2C_USE_DMA == TRUE + /* Enabling RX DMA.*/ + i2c_lld_start_rx_dma(i2cp); +#else + /* RX interrupt enabled.*/ + dp->CR1 |= I2C_CR1_RXIE; +#endif + + /* Starts the read operation.*/ + dp->CR2 |= I2C_CR2_START; + + /* State change.*/ + i2cp->state = I2C_ACTIVE_RX; + + /* Note, returning because the transaction is not over yet.*/ + return; + } + } + else { + /* End of the receive phase.*/ +#if STM32_I2C_USE_DMA == TRUE + /* Disabling RX DMA channel.*/ + i2c_lld_stop_rx_dma(i2cp); +#endif + } + + /* Transaction finished sending the STOP.*/ + dp->CR2 |= I2C_CR2_STOP; + + /* Make sure no more 'Transfer Complete' interrupts.*/ + dp->CR1 &= ~I2C_CR1_TCIE; + + /* Normal transaction end.*/ + _i2c_wakeup_isr(i2cp); + } +} + +/** + * @brief I2C error handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] isr content of the ISR register to be decoded + * + * @notapi + */ +static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t isr) { + +#if STM32_I2C_USE_DMA == TRUE + /* Clears DMA interrupt flags just to be safe.*/ + i2c_lld_stop_rx_dma(i2cp); + i2c_lld_stop_tx_dma(i2cp); +#else + /* Disabling RX and TX interrupts.*/ + i2cp->i2c->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE); +#endif + + if (isr & I2C_ISR_BERR) + i2cp->errors |= I2C_BUS_ERROR; + + if (isr & I2C_ISR_ARLO) + i2cp->errors |= I2C_ARBITRATION_LOST; + + if (isr & I2C_ISR_OVR) + i2cp->errors |= I2C_OVERRUN; + + if (isr & I2C_ISR_TIMEOUT) + i2cp->errors |= I2C_TIMEOUT; + + /* If some error has been identified then wake the waiting thread.*/ + if (i2cp->errors != I2C_NO_ERROR) + _i2c_wakeup_error_isr(i2cp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) +#if defined(STM32_I2C1_GLOBAL_HANDLER) || defined(__DOXYGEN__) +/** + * @brief I2C1 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C1_GLOBAL_HANDLER) { + uint32_t isr = I2CD1.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD1.i2c->ICR = isr; + + if (isr & I2C_ERROR_MASK) + i2c_lld_serve_error_interrupt(&I2CD1, isr); + else if (isr & I2C_INT_MASK) + i2c_lld_serve_interrupt(&I2CD1, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#elif defined(STM32_I2C1_EVENT_HANDLER) && defined(STM32_I2C1_ERROR_HANDLER) +OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) { + uint32_t isr = I2CD1.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD1.i2c->ICR = isr & I2C_INT_MASK; + + i2c_lld_serve_interrupt(&I2CD1, isr); + + OSAL_IRQ_EPILOGUE(); +} + +OSAL_IRQ_HANDLER(STM32_I2C1_ERROR_HANDLER) { + uint32_t isr = I2CD1.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD1.i2c->ICR = isr & I2C_ERROR_MASK; + + i2c_lld_serve_error_interrupt(&I2CD1, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "I2C1 interrupt handlers not defined" +#endif +#endif /* STM32_I2C_USE_I2C1 */ + +#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) +#if defined(STM32_I2C2_GLOBAL_HANDLER) || defined(__DOXYGEN__) +/** + * @brief I2C2 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C2_GLOBAL_HANDLER) { + uint32_t isr = I2CD2.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD2.i2c->ICR = isr; + + if (isr & I2C_ERROR_MASK) + i2c_lld_serve_error_interrupt(&I2CD2, isr); + else if (isr & I2C_INT_MASK) + i2c_lld_serve_interrupt(&I2CD2, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#elif defined(STM32_I2C2_EVENT_HANDLER) && defined(STM32_I2C2_ERROR_HANDLER) +OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) { + uint32_t isr = I2CD2.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD2.i2c->ICR = isr & I2C_INT_MASK; + + i2c_lld_serve_interrupt(&I2CD2, isr); + + OSAL_IRQ_EPILOGUE(); +} + +OSAL_IRQ_HANDLER(STM32_I2C2_ERROR_HANDLER) { + uint32_t isr = I2CD2.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD2.i2c->ICR = isr & I2C_ERROR_MASK; + + i2c_lld_serve_error_interrupt(&I2CD2, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "I2C2 interrupt handlers not defined" +#endif +#endif /* STM32_I2C_USE_I2C2 */ + +#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) +#if defined(STM32_I2C3_GLOBAL_HANDLER) || defined(__DOXYGEN__) +/** + * @brief I2C3 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C3_GLOBAL_HANDLER) { + uint32_t isr = I2CD3.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD3.i2c->ICR = isr; + + if (isr & I2C_ERROR_MASK) + i2c_lld_serve_error_interrupt(&I2CD3, isr); + else if (isr & I2C_INT_MASK) + i2c_lld_serve_interrupt(&I2CD3, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#elif defined(STM32_I2C3_EVENT_HANDLER) && defined(STM32_I2C3_ERROR_HANDLER) +OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) { + uint32_t isr = I2CD3.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD3.i2c->ICR = isr & I2C_INT_MASK; + + i2c_lld_serve_interrupt(&I2CD3, isr); + + OSAL_IRQ_EPILOGUE(); +} + +OSAL_IRQ_HANDLER(STM32_I2C3_ERROR_HANDLER) { + uint32_t isr = I2CD3.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD3.i2c->ICR = isr & I2C_ERROR_MASK; + + i2c_lld_serve_error_interrupt(&I2CD3, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "I2C3 interrupt handlers not defined" +#endif +#endif /* STM32_I2C_USE_I2C3 */ + +#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__) +#if defined(STM32_I2C4_GLOBAL_HANDLER) || defined(__DOXYGEN__) +/** + * @brief I2C4 event interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(STM32_I2C4_GLOBAL_HANDLER) { + uint32_t isr = I2CD4.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD4.i2c->ICR = isr; + + if (isr & I2C_ERROR_MASK) + i2c_lld_serve_error_interrupt(&I2CD4, isr); + else if (isr & I2C_INT_MASK) + i2c_lld_serve_interrupt(&I2CD4, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#elif defined(STM32_I2C4_EVENT_HANDLER) && defined(STM32_I2C4_ERROR_HANDLER) +OSAL_IRQ_HANDLER(STM32_I2C4_EVENT_HANDLER) { + uint32_t isr = I2CD4.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD4.i2c->ICR = isr & I2C_INT_MASK; + + i2c_lld_serve_interrupt(&I2CD4, isr); + + OSAL_IRQ_EPILOGUE(); +} + +OSAL_IRQ_HANDLER(STM32_I2C4_ERROR_HANDLER) { + uint32_t isr = I2CD4.i2c->ISR; + + OSAL_IRQ_PROLOGUE(); + + /* Clearing IRQ bits.*/ + I2CD4.i2c->ICR = isr & I2C_ERROR_MASK; + + i2c_lld_serve_error_interrupt(&I2CD4, isr); + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "I2C4 interrupt handlers not defined" +#endif +#endif /* STM32_I2C_USE_I2C4 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2C driver initialization. + * + * @notapi + */ +void i2c_lld_init(void) { + +#if STM32_I2C_USE_I2C1 + i2cObjectInit(&I2CD1); + I2CD1.thread = NULL; + I2CD1.i2c = I2C1; +#if STM32_I2C_USE_DMA == TRUE +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + I2CD1.is_bdma = false; +#endif + I2CD1.rx.dma = NULL; + I2CD1.tx.dma = NULL; +#endif +#if defined(STM32_I2C1_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicEnableVector(STM32_I2C1_GLOBAL_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY); +#elif defined(STM32_I2C1_EVENT_NUMBER) && defined(STM32_I2C1_ERROR_NUMBER) + nvicEnableVector(STM32_I2C1_EVENT_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY); + nvicEnableVector(STM32_I2C1_ERROR_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY); +#else +#error "I2C1 interrupt numbers not defined" +#endif +#endif /* STM32_I2C_USE_I2C1 */ + +#if STM32_I2C_USE_I2C2 + i2cObjectInit(&I2CD2); + I2CD2.thread = NULL; + I2CD2.i2c = I2C2; +#if STM32_I2C_USE_DMA == TRUE +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + I2CD2.is_bdma = false; +#endif + I2CD2.rx.dma = NULL; + I2CD2.tx.dma = NULL; +#endif +#if defined(STM32_I2C2_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicEnableVector(STM32_I2C2_GLOBAL_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY); +#elif defined(STM32_I2C2_EVENT_NUMBER) && defined(STM32_I2C2_ERROR_NUMBER) + nvicEnableVector(STM32_I2C2_EVENT_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY); + nvicEnableVector(STM32_I2C2_ERROR_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY); +#else +#error "I2C2 interrupt numbers not defined" +#endif +#endif /* STM32_I2C_USE_I2C2 */ + +#if STM32_I2C_USE_I2C3 + i2cObjectInit(&I2CD3); + I2CD3.thread = NULL; + I2CD3.i2c = I2C3; +#if STM32_I2C_USE_DMA == TRUE +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + I2CD3.is_bdma = false; +#endif + I2CD3.rx.dma = NULL; + I2CD3.tx.dma = NULL; +#endif +#if defined(STM32_I2C3_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicEnableVector(STM32_I2C3_GLOBAL_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY); +#elif defined(STM32_I2C3_EVENT_NUMBER) && defined(STM32_I2C3_ERROR_NUMBER) + nvicEnableVector(STM32_I2C3_EVENT_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY); + nvicEnableVector(STM32_I2C3_ERROR_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY); +#else +#error "I2C3 interrupt numbers not defined" +#endif +#endif /* STM32_I2C_USE_I2C3 */ + +#if STM32_I2C_USE_I2C4 + i2cObjectInit(&I2CD4); + I2CD4.thread = NULL; + I2CD4.i2c = I2C4; +#if STM32_I2C_USE_DMA == TRUE +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) +#if STM32_I2C4_USE_BDMA == TRUE + I2CD4.is_bdma = true; + I2CD4.rx.bdma = NULL; + I2CD4.tx.bdma = NULL; +#else + I2CD4.is_bdma = false; + I2CD4.rx.dma = NULL; + I2CD4.tx.dma = NULL; +#endif /* STM32_I2C4_USE_BDMA == TRUE */ +#endif /* defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) */ +#endif /* STM32_I2C_USE_DMA == TRUE */ +#if defined(STM32_I2C4_GLOBAL_NUMBER) || defined(__DOXYGEN__) + nvicEnableVector(STM32_I2C4_GLOBAL_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY); +#elif defined(STM32_I2C4_EVENT_NUMBER) && defined(STM32_I2C4_ERROR_NUMBER) + nvicEnableVector(STM32_I2C4_EVENT_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY); + nvicEnableVector(STM32_I2C4_ERROR_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY); +#else +#error "I2C4 interrupt numbers not defined" +#endif +#endif /* STM32_I2C_USE_I2C4 */ +} + +/** + * @brief Configures and activates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_start(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + + /* Make sure I2C peripheral is disabled */ + dp->CR1 &= ~I2C_CR1_PE; + + /* If in stopped state then enables the I2C and DMA clocks.*/ + if (i2cp->state == I2C_STOP) { + +#if STM32_I2C_USE_DMA == TRUE + /* Common DMA modes.*/ +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + i2cp->txdmamode = BDMAMODE_COMMON | STM32_BDMA_CR_DIR_M2P; + i2cp->rxdmamode = BDMAMODE_COMMON | STM32_BDMA_CR_DIR_P2M; + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#if defined(STM32_I2C_DMA_REQUIRED) + { + i2cp->txdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_M2P; + i2cp->rxdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_P2M; + } +#endif +#endif /* STM32_I2C_USE_DMA == TRUE */ + +#if STM32_I2C_USE_I2C1 + if (&I2CD1 == i2cp) { + + rccResetI2C1(); + rccEnableI2C1(true); +#if STM32_I2C_USE_DMA == TRUE + { + i2cp->rx.dma = dmaStreamAllocI(STM32_I2C_I2C1_RX_DMA_STREAM, + STM32_I2C_I2C1_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->rx.dma != NULL, "unable to allocate stream"); + i2cp->tx.dma = dmaStreamAllocI(STM32_I2C_I2C1_TX_DMA_STREAM, + STM32_I2C_I2C1_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->tx.dma != NULL, "unable to allocate stream"); + + i2cp->rxdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); + dmaSetRequestSource(i2cp->rx.dma, STM32_DMAMUX1_I2C1_RX); + dmaSetRequestSource(i2cp->tx.dma, STM32_DMAMUX1_I2C1_TX); + } +#endif /* STM32_I2C_USE_DMA == TRUE */ + } +#endif /* STM32_I2C_USE_I2C1 */ + +#if STM32_I2C_USE_I2C2 + if (&I2CD2 == i2cp) { + + rccResetI2C2(); + rccEnableI2C2(true); +#if STM32_I2C_USE_DMA == TRUE + { + i2cp->rx.dma = dmaStreamAllocI(STM32_I2C_I2C2_RX_DMA_STREAM, + STM32_I2C_I2C2_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->rx.dma != NULL, "unable to allocate stream"); + i2cp->tx.dma = dmaStreamAllocI(STM32_I2C_I2C2_TX_DMA_STREAM, + STM32_I2C_I2C2_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->tx.dma != NULL, "unable to allocate stream"); + + i2cp->rxdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); + dmaSetRequestSource(i2cp->rx.dma, STM32_DMAMUX1_I2C2_RX); + dmaSetRequestSource(i2cp->tx.dma, STM32_DMAMUX1_I2C2_TX); + } +#endif /* STM32_I2C_USE_DMA == TRUE */ + } +#endif /* STM32_I2C_USE_I2C2 */ + +#if STM32_I2C_USE_I2C3 + if (&I2CD3 == i2cp) { + + rccResetI2C3(); + rccEnableI2C3(true); +#if STM32_I2C_USE_DMA == TRUE + { + i2cp->rx.dma = dmaStreamAllocI(STM32_I2C_I2C3_RX_DMA_STREAM, + STM32_I2C_I2C3_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->rx.dma != NULL, "unable to allocate stream"); + i2cp->tx.dma = dmaStreamAllocI(STM32_I2C_I2C3_TX_DMA_STREAM, + STM32_I2C_I2C3_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->tx.dma != NULL, "unable to allocate stream"); + + i2cp->rxdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); + dmaSetRequestSource(i2cp->rx.dma, STM32_DMAMUX1_I2C3_RX); + dmaSetRequestSource(i2cp->tx.dma, STM32_DMAMUX1_I2C3_TX); + } +#endif /* STM32_I2C_USE_DMA == TRUE */ + } +#endif /* STM32_I2C_USE_I2C3 */ + +#if STM32_I2C_USE_I2C4 + if (&I2CD4 == i2cp) { + + rccResetI2C4(); + rccEnableI2C4(true); +#if STM32_I2C_USE_DMA == TRUE + { +#if STM32_I2C4_USE_BDMA == TRUE + i2cp->rx.bdma = bdmaStreamAllocI(STM32_I2C_I2C4_RX_BDMA_STREAM, + STM32_I2C_I2C4_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->rx.bdma != NULL, "unable to allocate stream"); + i2cp->tx.bdma = bdmaStreamAllocI(STM32_I2C_I2C4_TX_BDMA_STREAM, + STM32_I2C_I2C4_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->tx.bdma != NULL, "unable to allocate stream"); + + i2cp->rxdmamode |= STM32_BDMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY); + i2cp->txdmamode |= STM32_BDMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY); + bdmaSetRequestSource(i2cp->rx.bdma, STM32_DMAMUX2_I2C4_RX); + bdmaSetRequestSource(i2cp->tx.bdma, STM32_DMAMUX2_I2C4_TX); +#else /* STM32_I2C4_USE_BDMA != TRUE */ + i2cp->rx.dma = dmaStreamAllocI(STM32_I2C_I2C4_RX_DMA_STREAM, + STM32_I2C_I2C4_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->rx.dma != NULL, "unable to allocate stream"); + i2cp->tx.dma = dmaStreamAllocI(STM32_I2C_I2C4_TX_DMA_STREAM, + STM32_I2C_I2C4_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(i2cp->tx.dma != NULL, "unable to allocate stream"); + + i2cp->rxdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY); + i2cp->txdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY); + dmaSetRequestSource(i2cp->rx.dma, STM32_DMAMUX1_I2C4_RX); + dmaSetRequestSource(i2cp->tx.dma, STM32_DMAMUX1_I2C4_TX); +#endif /* STM32_I2C4_USE_BDMA != TRUE */ + } +#endif /* STM32_I2C_USE_DMA == TRUE */ + } +#endif /* STM32_I2C_USE_I2C4 */ + } + +#if STM32_I2C_USE_DMA == TRUE + /* I2C registers pointed by the DMA.*/ +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + bdmaStreamSetPeripheral(i2cp->rx.bdma, &dp->RXDR); + bdmaStreamSetPeripheral(i2cp->tx.bdma, &dp->TXDR); + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#if defined(STM32_I2C_DMA_REQUIRED) + { + dmaStreamSetPeripheral(i2cp->rx.dma, &dp->RXDR); + dmaStreamSetPeripheral(i2cp->tx.dma, &dp->TXDR); + } +#endif +#endif /* STM32_I2C_USE_DMA == TRUE */ + + /* Reset i2c peripheral, the TCIE bit will be handled separately.*/ + dp->CR1 = i2cp->config->cr1 | +#if STM32_I2C_USE_DMA == TRUE + I2C_CR1_TXDMAEN | I2C_CR1_RXDMAEN | /* Enable only if using DMA */ +#endif + I2C_CR1_ERRIE | I2C_CR1_NACKIE; + + /* Setup I2C parameters.*/ + dp->TIMINGR = i2cp->config->timingr; + + /* Ready to go.*/ + dp->CR1 |= I2C_CR1_PE; +} + +/** + * @brief Deactivates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_stop(I2CDriver *i2cp) { + + /* If not in stopped state then disables the I2C clock.*/ + if (i2cp->state != I2C_STOP) { + + /* I2C disable.*/ + i2c_lld_abort_operation(i2cp); + +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + bdmaStreamFreeI(i2cp->rx.bdma); + bdmaStreamFreeI(i2cp->tx.bdma); + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#if defined(STM32_I2C_DMA_REQUIRED) + { + dmaStreamFreeI(i2cp->rx.dma); + dmaStreamFreeI(i2cp->tx.dma); + } +#endif + +#if STM32_I2C_USE_I2C1 + if (&I2CD1 == i2cp) { + rccDisableI2C1(); + } +#endif + +#if STM32_I2C_USE_I2C2 + if (&I2CD2 == i2cp) { + rccDisableI2C2(); + } +#endif + +#if STM32_I2C_USE_I2C3 + if (&I2CD3 == i2cp) { + rccDisableI2C3(); + } +#endif + +#if STM32_I2C_USE_I2C4 + if (&I2CD4 == i2cp) { + rccDisableI2C4(); + } +#endif + } +} + +/** + * @brief Receives data via the I2C bus as master. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + msg_t msg; + I2C_TypeDef *dp = i2cp->i2c; + systime_t start, end; + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + + /* Sizes of transfer phases.*/ + i2cp->txbytes = 0U; + i2cp->rxbytes = rxbytes; + +#if STM32_I2C_USE_DMA == TRUE + /* RX DMA setup.*/ +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + bdmaStreamSetMode(i2cp->rx.bdma, i2cp->rxdmamode); + bdmaStreamSetMemory(i2cp->rx.bdma, rxbuf); + bdmaStreamSetTransactionSize(i2cp->rx.bdma, rxbytes); + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#if defined(STM32_I2C_DMA_REQUIRED) + { + dmaStreamSetMode(i2cp->rx.dma, i2cp->rxdmamode); + dmaStreamSetMemory0(i2cp->rx.dma, rxbuf); + dmaStreamSetTransactionSize(i2cp->rx.dma, rxbytes); + } +#endif +#else + i2cp->rxptr = rxbuf; +#endif + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT)); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { + osalSysLock(); + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if ((dp->ISR & I2C_ISR_BUSY) == 0) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + return MSG_TIMEOUT; + } + + osalSysUnlock(); + } + + /* Setting up the slave address.*/ + i2c_lld_set_address(i2cp, addr); + + /* Setting up the peripheral.*/ + i2c_lld_setup_rx_transfer(i2cp); + +#if STM32_I2C_USE_DMA == TRUE + /* Enabling RX DMA.*/ + i2c_lld_start_rx_dma(i2cp); + + /* Transfer complete interrupt enabled.*/ + dp->CR1 |= I2C_CR1_TCIE; +#else + + /* Transfer complete and RX interrupts enabled.*/ + dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_RXIE; +#endif + + /* Starts the operation.*/ + dp->CR2 |= I2C_CR2_START; + + /* Waits for the operation completion or a timeout.*/ + msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + + /* In case of a software timeout a STOP is sent as an extreme attempt + to release the bus and DMA is forcibly disabled.*/ + if (msg == MSG_TIMEOUT) { + dp->CR2 |= I2C_CR2_STOP; +#if STM32_I2C_USE_DMA == TRUE + i2c_lld_stop_rx_dma(i2cp); +#endif + } + + return msg; +} + +/** + * @brief Transmits data via the I2C bus as master. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[in] txbuf pointer to the transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + msg_t msg; + I2C_TypeDef *dp = i2cp->i2c; + systime_t start, end; + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + + /* Sizes of transfer phases.*/ + i2cp->txbytes = txbytes; + i2cp->rxbytes = rxbytes; + +#if STM32_I2C_USE_DMA == TRUE + /* TX and RX DMA setup.*/ +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + if (i2cp->is_bdma) +#endif +#if defined(STM32_I2C_BDMA_REQUIRED) + { + bdmaStreamSetMode(i2cp->tx.bdma, i2cp->txdmamode); + bdmaStreamSetMemory(i2cp->tx.bdma, txbuf); + bdmaStreamSetTransactionSize(i2cp->tx.bdma, txbytes); + + bdmaStreamSetMode(i2cp->rx.bdma, i2cp->rxdmamode); + bdmaStreamSetMemory(i2cp->rx.bdma, rxbuf); + bdmaStreamSetTransactionSize(i2cp->rx.bdma, rxbytes); + } +#endif +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) + else +#endif +#if defined(STM32_I2C_DMA_REQUIRED) + { + dmaStreamSetMode(i2cp->tx.dma, i2cp->txdmamode); + dmaStreamSetMemory0(i2cp->tx.dma, txbuf); + dmaStreamSetTransactionSize(i2cp->tx.dma, txbytes); + + dmaStreamSetMode(i2cp->rx.dma, i2cp->rxdmamode); + dmaStreamSetMemory0(i2cp->rx.dma, rxbuf); + dmaStreamSetTransactionSize(i2cp->rx.dma, rxbytes); + } +#endif +#else + i2cp->txptr = txbuf; + i2cp->rxptr = rxbuf; +#endif + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT)); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { + osalSysLock(); + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if ((dp->ISR & I2C_ISR_BUSY) == 0) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + return MSG_TIMEOUT; + } + + osalSysUnlock(); + } + + /* Setting up the slave address.*/ + i2c_lld_set_address(i2cp, addr); + + /* Preparing the transfer.*/ + i2c_lld_setup_tx_transfer(i2cp); + +#if STM32_I2C_USE_DMA == TRUE + /* Enabling TX DMA.*/ + i2c_lld_start_tx_dma(i2cp); + + /* Transfer complete interrupt enabled.*/ + dp->CR1 |= I2C_CR1_TCIE; +#else + /* Transfer complete and TX interrupts enabled.*/ + dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_TXIE; +#endif + + /* Starts the operation.*/ + dp->CR2 |= I2C_CR2_START; + + /* Waits for the operation completion or a timeout.*/ + msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + + /* In case of a software timeout a STOP is sent as an extreme attempt + to release the bus and DMA is forcibly disabled.*/ + if (msg == MSG_TIMEOUT) { + dp->CR2 |= I2C_CR2_STOP; +#if STM32_I2C_USE_DMA == TRUE + i2c_lld_stop_rx_dma(i2cp); + i2c_lld_stop_tx_dma(i2cp); +#endif + } + + return msg; +} + +#endif /* HAL_USE_I2C */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.h new file mode 100644 index 0000000..ee29a4e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.h @@ -0,0 +1,603 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file I2Cv3/hal_i2c_lld.h + * @brief STM32 I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#ifndef HAL_I2C_LLD_H +#define HAL_I2C_LLD_H + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name TIMINGR register definitions + * @{ + */ +#define STM32_TIMINGR_PRESC_MASK (15U << 28) +#define STM32_TIMINGR_PRESC(n) ((n) << 28) +#define STM32_TIMINGR_SCLDEL_MASK (15U << 20) +#define STM32_TIMINGR_SCLDEL(n) ((n) << 20) +#define STM32_TIMINGR_SDADEL_MASK (15U << 16) +#define STM32_TIMINGR_SDADEL(n) ((n) << 16) +#define STM32_TIMINGR_SCLH_MASK (255U << 8) +#define STM32_TIMINGR_SCLH(n) ((n) << 8) +#define STM32_TIMINGR_SCLL_MASK (255U << 0) +#define STM32_TIMINGR_SCLL(n) ((n) << 0) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief I2C1 driver enable switch. + * @details If set to @p TRUE the support for I2C1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C1 FALSE +#endif + +/** + * @brief I2C2 driver enable switch. + * @details If set to @p TRUE the support for I2C2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C2 FALSE +#endif + +/** + * @brief I2C3 driver enable switch. + * @details If set to @p TRUE the support for I2C3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C3) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C3 FALSE +#endif + +/** + * @brief I2C4 driver enable switch. + * @details If set to @p TRUE the support for I2C4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_I2C_USE_I2C4) || defined(__DOXYGEN__) +#define STM32_I2C_USE_I2C4 FALSE +#endif + +/** + * @brief I2C timeout on busy condition in milliseconds. + */ +#if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_I2C_BUSY_TIMEOUT 50 +#endif + +/** + * @brief I2C1 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C1_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2C2 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C2_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2C3 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C3_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2C4 interrupt priority level setting. + */ +#if !defined(STM32_I2C_I2C4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C4_IRQ_PRIORITY 10 +#endif + +/** + * @brief DMA use switch. + */ +#if !defined(STM32_I2C_USE_DMA) || defined(__DOXYGEN__) +#define STM32_I2C_USE_DMA TRUE +#endif + +/** + * @brief I2C1 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_I2C_I2C1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C1_DMA_PRIORITY 1 +#endif + +/** + * @brief I2C2 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_I2C_I2C2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C2_DMA_PRIORITY 1 +#endif + +/** + * @brief I2C3 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_I2C_I2C3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C3_DMA_PRIORITY 1 +#endif + +/** + * @brief I2C4 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_I2C_I2C4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2C_I2C4_DMA_PRIORITY 1 +#endif + +/** + * @brief I2C DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(STM32_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks.*/ +#if !defined(STM32_HAS_I2C1) +#error "STM32_HAS_I2C1 not defined in registry" +#endif + +#if !defined(STM32_HAS_I2C2) +#error "STM32_HAS_I2C2 not defined in registry" +#endif + +#if !defined(STM32_HAS_I2C3) +#error "STM32_HAS_I2C3 not defined in registry" +#endif + +#if !defined(STM32_HAS_I2C4) +#error "STM32_HAS_I2C4 not defined in registry" +#endif + +#if !defined(STM32_I2C4_USE_BDMA) +#error "STM32_I2C4_USE_BDMA not defined in registry" +#endif + +/** @brief error checks */ +#if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1 +#error "I2C1 not present in the selected device" +#endif + +#if STM32_I2C_USE_I2C2 && !STM32_HAS_I2C2 +#error "I2C2 not present in the selected device" +#endif + +#if STM32_I2C_USE_I2C3 && !STM32_HAS_I2C3 +#error "I2C3 not present in the selected device" +#endif + +#if STM32_I2C_USE_I2C4 && !STM32_HAS_I2C4 +#error "I2C4 not present in the selected device" +#endif + +#if !STM32_I2C_USE_I2C1 && !STM32_I2C_USE_I2C2 && !STM32_I2C_USE_I2C3 && \ + !STM32_I2C_USE_I2C4 +#error "I2C driver activated but no I2C peripheral assigned" +#endif + +#if STM32_I2C_USE_I2C1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C1" +#endif + +#if STM32_I2C_USE_I2C2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C2" +#endif + +#if STM32_I2C_USE_I2C3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C3" +#endif + +#if STM32_I2C_USE_I2C4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C4" +#endif + +#if STM32_I2C_USE_DMA == TRUE + +#if STM32_I2C_USE_I2C1 +#if !defined(STM32_I2C_I2C1_RX_DMA_STREAM) +#error "STM32_I2C_I2C1_RX_DMA_STREAM not defined" +#endif + +#if !defined(STM32_I2C_I2C1_TX_DMA_STREAM) +#error "STM32_I2C_I2C1_TX_DMA_STREAM not defined" +#endif + +#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to I2C1 RX" +#endif + +#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to I2C1 TX" +#endif + +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C1" +#endif +#endif + +#if STM32_I2C_USE_I2C2 +#if !defined(STM32_I2C_I2C2_RX_DMA_STREAM) +#error "STM32_I2C_I2C2_RX_DMA_STREAM not defined" +#endif + +#if !defined(STM32_I2C_I2C2_TX_DMA_STREAM) +#error "STM32_I2C_I2C2_TX_DMA_STREAM not defined" +#endif + +#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to I2C2 RX" +#endif + +#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to I2C2 TX" +#endif + +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C2" +#endif +#endif + +#if STM32_I2C_USE_I2C3 +#if !defined(STM32_I2C_I2C3_RX_DMA_STREAM) +#error "STM32_I2C_I2C3_RX_DMA_STREAM not defined" +#endif + +#if !defined(STM32_I2C_I2C3_TX_DMA_STREAM) +#error "STM32_I2C_I2C3_TX_DMA_STREAM not defined" +#endif + +#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to I2C3 RX" +#endif + +#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to I2C3 TX" +#endif + +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C3" +#endif +#endif + +#if STM32_I2C_USE_I2C4 +#if STM32_I2C4_USE_BDMA + +#if !defined(STM32_I2C_I2C4_RX_BDMA_STREAM) +#error "STM32_I2C_I2C4_RX_BDMA_STREAM not defined" +#endif + +#if !defined(STM32_I2C_I2C4_TX_BDMA_STREAM) +#error "STM32_I2C_I2C4_TX_BDMA_STREAM not defined" +#endif + +#if !STM32_BDMA_IS_VALID_STREAM(STM32_I2C_I2C4_RX_BDMA_STREAM) +#error "Invalid BDMA stream assigned to I2C4 RX" +#endif + +#if !STM32_BDMA_IS_VALID_STREAM(STM32_I2C_I2C4_TX_BDMA_STREAM) +#error "Invalid BDMA stream assigned to I2C4 TX" +#endif + +#if !STM32_BDMA_IS_VALID_PRIORITY(STM32_I2C_I2C4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C4" +#endif + +#else /* !STM32_I2C4_USE_BDMA */ + +#if !defined(STM32_I2C_I2C4_RX_DMA_STREAM) +#error "STM32_I2C_I2C4_RX_DMA_STREAM not defined" +#endif + +#if !defined(STM32_I2C_I2C4_TX_DMA_STREAM) +#error "STM32_I2C_I2C4_TX_DMA_STREAM not defined" +#endif + +#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C4_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to I2C4 RX" +#endif + +#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C4_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to I2C4 TX" +#endif + +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to I2C4" +#endif + +#endif /* !STM32_I2C4_USE_BDMA */ +#endif /* STM32_I2C_USE_I2C4 */ + +#if STM32_I2C4_USE_BDMA == TRUE + +#if STM32_I2C_USE_I2C1 || STM32_I2C_USE_I2C2 || STM32_I2C_USE_I2C3 +#define STM32_I2C_DMA_REQUIRED +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif +#endif + +#if STM32_I2C_USE_I2C4 +#define STM32_I2C_BDMA_REQUIRED +#if !defined(STM32_BDMA_REQUIRED) +#define STM32_BDMA_REQUIRED +#endif +#endif +#else /* STM32_I2C4_USE_BDMA != TRUE */ + +#if STM32_I2C_USE_I2C1 || STM32_I2C_USE_I2C2 || STM32_I2C_USE_I2C3 || STM32_I2C_USE_I2C4 +#define STM32_I2C_DMA_REQUIRED +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif +#endif + +#endif /* STM32_I2C4_USE_BDMA != TRUE */ + +#endif /* STM32_I2C_USE_DMA == TRUE */ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type representing an I2C address. + */ +typedef uint16_t i2caddr_t; + +/** + * @brief Type of I2C driver condition flags. + */ +typedef uint32_t i2cflags_t; + +/** + * @brief Type of I2C driver configuration structure. + */ +typedef struct { + /** + * @brief TIMINGR register initialization. + * @note Refer to the STM32 reference manual, the values are affected + * by the system clock settings in mcuconf.h. + */ + uint32_t timingr; + /** + * @brief CR1 register initialization. + * @note Leave to zero unless you know what you are doing. + */ + uint32_t cr1; + /** + * @brief CR2 register initialization. + * @note Only the ADD10 bit can eventually be specified here. + */ + uint32_t cr2; +} I2CConfig; + +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct I2CDriver I2CDriver; + +/** + * @brief Structure representing an I2C driver. + */ +struct I2CDriver { + /** + * @brief Driver state. + */ + i2cstate_t state; + /** + * @brief Current configuration data. + */ + const I2CConfig *config; + /** + * @brief Error flags. + */ + i2cflags_t errors; +#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) + mutex_t mutex; +#endif /* I2C_USE_MUTUAL_EXCLUSION */ +#if defined(I2C_DRIVER_EXT_FIELDS) + I2C_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion. + */ + thread_reference_t thread; + /** + * @brief Number of bytes in TX phase. + */ + size_t txbytes; + /** + * @brief Number of bytes in RX phase. + */ + size_t rxbytes; +#if (STM32_I2C_USE_DMA == TRUE) || defined(__DOXYGEN__) + /** + * @brief RX DMA mode bit mask. + */ + uint32_t rxdmamode; + /** + * @brief TX DMA mode bit mask. + */ + uint32_t txdmamode; +#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_BDMA_REQUIRED) + /** + * @brief DMA type for this instance. + */ + bool is_bdma; +#endif + /** + * @brief Union of the RX DMA streams. + */ + union { +#if defined(STM32_I2C_DMA_REQUIRED) || defined(__DOXYGEN__) + /** + * @brief Receive DMA stream. + */ + const stm32_dma_stream_t *dma; +#endif +#if (STM32_I2C4_USE_BDMA == TRUE) || defined(__DOXYGEN__) +#if defined(STM32_BDMA_REQUIRED) || defined(__DOXYGEN__) + /** + * @brief Receive BDMA stream. + */ + const stm32_bdma_stream_t *bdma; +#endif +#endif + } rx; + /** + * @brief Union of the TX DMA streams. + */ + union { +#if defined(STM32_I2C_DMA_REQUIRED) || defined(__DOXYGEN__) + /** + * @brief Transmit DMA stream. + */ + const stm32_dma_stream_t *dma; +#endif +#if (STM32_I2C4_USE_BDMA == TRUE) || defined(__DOXYGEN__) +#if defined(STM32_BDMA_REQUIRED) || defined(__DOXYGEN__) + /** + * @brief Transmit DMA stream. + */ + const stm32_bdma_stream_t *bdma; +#endif +#endif + } tx; +#else /* STM32_I2C_USE_DMA == FALSE */ + /** + * @brief Pointer to the next TX buffer location. + */ + const uint8_t *txptr; + /** + * @brief Pointer to the next RX buffer location. + */ + uint8_t *rxptr; +#endif /* STM32_I2C_USE_DMA == FALSE */ + /** + * @brief Pointer to the I2Cx registers block. + */ + I2C_TypeDef *i2c; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Get errors from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_errors(i2cp) ((i2cp)->errors) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +#if STM32_I2C_USE_I2C1 +extern I2CDriver I2CD1; +#endif + +#if STM32_I2C_USE_I2C2 +extern I2CDriver I2CD2; +#endif + +#if STM32_I2C_USE_I2C3 +extern I2CDriver I2CD3; +#endif + +#if STM32_I2C_USE_I2C4 +extern I2CDriver I2CD4; +#endif + +#endif /* !defined(__DOXYGEN__) */ + +#ifdef __cplusplus +extern "C" { +#endif + void i2c_lld_init(void); + void i2c_lld_start(I2CDriver *i2cp); + void i2c_lld_stop(I2CDriver *i2cp); + msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); + msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_I2C */ + +#endif /* HAL_I2C_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/driver.mk new file mode 100644 index 0000000..2964178 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c new file mode 100644 index 0000000..1a62533 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c @@ -0,0 +1,758 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file MACv1/hal_mac_lld.c + * @brief STM32 low level MAC driver code. + * + * @addtogroup MAC + * @{ + */ + +#include + +#include "hal.h" + +#if HAL_USE_MAC || defined(__DOXYGEN__) + +#include "hal_mii.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define BUFFER_SIZE ((((STM32_MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4) + +/* Fixing inconsistencies in ST headers.*/ +#if !defined(ETH_MACMIIAR_CR_Div102) && defined(ETH_MACMIIAR_CR_DIV102) +#define ETH_MACMIIAR_CR_Div102 ETH_MACMIIAR_CR_DIV102 +#endif +#if !defined(ETH_MACMIIAR_CR_Div62) && defined(ETH_MACMIIAR_CR_DIV62) +#define ETH_MACMIIAR_CR_Div62 ETH_MACMIIAR_CR_DIV62 +#endif +#if !defined(ETH_MACMIIAR_CR_Div42) && defined(ETH_MACMIIAR_CR_DIV42) +#define ETH_MACMIIAR_CR_Div42 ETH_MACMIIAR_CR_DIV42 +#endif +#if !defined(ETH_MACMIIAR_CR_Div26) && defined(ETH_MACMIIAR_CR_DIV26) +#define ETH_MACMIIAR_CR_Div26 ETH_MACMIIAR_CR_DIV26 +#endif +#if !defined(ETH_MACMIIAR_CR_Div16) && defined(ETH_MACMIIAR_CR_DIV16) +#define ETH_MACMIIAR_CR_Div16 ETH_MACMIIAR_CR_DIV16 +#endif + +/* MII divider optimal value.*/ +#if (STM32_HCLK >= 150000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div102 +#elif (STM32_HCLK >= 100000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div62 +#elif (STM32_HCLK >= 60000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div42 +#elif (STM32_HCLK >= 35000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div26 +#elif (STM32_HCLK >= 20000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div16 +#else +#error "STM32_HCLK below minimum frequency for ETH operations (20MHz)" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief Ethernet driver 1. + */ +MACDriver ETHD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const uint8_t default_mac_address[] = {0xAA, 0x55, 0x13, + 0x37, 0x01, 0x10}; + +static stm32_eth_rx_descriptor_t __eth_rd[STM32_MAC_RECEIVE_BUFFERS]; +static stm32_eth_tx_descriptor_t __eth_td[STM32_MAC_TRANSMIT_BUFFERS]; + +static uint32_t __eth_rb[STM32_MAC_RECEIVE_BUFFERS][BUFFER_SIZE]; +static uint32_t __eth_tb[STM32_MAC_TRANSMIT_BUFFERS][BUFFER_SIZE]; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Writes a PHY register. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[in] reg register number + * @param[in] value new register value + * + * @notapi + */ +void mii_write(MACDriver *macp, uint32_t reg, uint32_t value) { + + ETH->MACMIIDR = value; + ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR | + ETH_MACMIIAR_MW | ETH_MACMIIAR_MB; + while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0) + ; +} + +/** + * @brief Reads a PHY register. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[in] reg register number + * + * @return The PHY register content. + * + * @notapi + */ +uint32_t mii_read(MACDriver *macp, uint32_t reg) { + + ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR | ETH_MACMIIAR_MB; + while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0) + ; + return ETH->MACMIIDR; +} + +#if !defined(BOARD_PHY_ADDRESS) +/** + * @brief PHY address detection. + * + * @param[in] macp pointer to the @p MACDriver object + */ +static void mii_find_phy(MACDriver *macp) { + uint32_t i; + +#if STM32_MAC_PHY_TIMEOUT > 0 + unsigned n = STM32_MAC_PHY_TIMEOUT; + do { +#endif + for (i = 0U; i <= 31U; i++) { + macp->phyaddr = i << 11U; + ETH->MACMIIDR = (i << 6U) | MACMIIDR_CR; + if ((mii_read(macp, MII_PHYSID1) == (BOARD_PHY_ID >> 16U)) && + ((mii_read(macp, MII_PHYSID2) & 0xFFF0U) == (BOARD_PHY_ID & 0xFFF0U))) { + return; + } + } +#if STM32_MAC_PHY_TIMEOUT > 0 + n--; + } while (n > 0U); +#endif + /* Wrong or defective board.*/ + osalSysHalt("MAC failure"); +} +#endif + +/** + * @brief MAC address setup. + * + * @param[in] p pointer to a six bytes buffer containing the MAC + * address + */ +static void mac_lld_set_address(const uint8_t *p) { + + /* MAC address configuration, only a single address comparator is used, + hash table not used.*/ + ETH->MACA0HR = ((uint32_t)p[5] << 8) | + ((uint32_t)p[4] << 0); + ETH->MACA0LR = ((uint32_t)p[3] << 24) | + ((uint32_t)p[2] << 16) | + ((uint32_t)p[1] << 8) | + ((uint32_t)p[0] << 0); + ETH->MACA1HR = 0x0000FFFF; + ETH->MACA1LR = 0xFFFFFFFF; + ETH->MACA2HR = 0x0000FFFF; + ETH->MACA2LR = 0xFFFFFFFF; + ETH->MACA3HR = 0x0000FFFF; + ETH->MACA3LR = 0xFFFFFFFF; + ETH->MACHTHR = 0; + ETH->MACHTLR = 0; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +OSAL_IRQ_HANDLER(STM32_ETH_HANDLER) { + uint32_t dmasr; + + OSAL_IRQ_PROLOGUE(); + + dmasr = ETH->DMASR; + ETH->DMASR = dmasr; /* Clear status bits.*/ + + if (dmasr & ETH_DMASR_RS) { + /* Data Received.*/ + osalSysLockFromISR(); + osalThreadDequeueAllI(ÐD1.rdqueue, MSG_RESET); +#if MAC_USE_EVENTS + osalEventBroadcastFlagsI(ÐD1.rdevent, 0); +#endif + osalSysUnlockFromISR(); + } + + if (dmasr & ETH_DMASR_TS) { + /* Data Transmitted.*/ + osalSysLockFromISR(); + osalThreadDequeueAllI(ÐD1.tdqueue, MSG_RESET); + osalSysUnlockFromISR(); + } + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level MAC initialization. + * + * @notapi + */ +void mac_lld_init(void) { + unsigned i; + + macObjectInit(ÐD1); + ETHD1.link_up = false; + + /* Descriptor tables are initialized in chained mode, note that the first + word is not initialized here but in mac_lld_start().*/ + for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++) { + __eth_rd[i].rdes1 = STM32_RDES1_RCH | STM32_MAC_BUFFERS_SIZE; + __eth_rd[i].rdes2 = (uint32_t)__eth_rb[i]; + __eth_rd[i].rdes3 = (uint32_t)&__eth_rd[(i + 1) % STM32_MAC_RECEIVE_BUFFERS]; + } + for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++) { + __eth_td[i].tdes1 = 0; + __eth_td[i].tdes2 = (uint32_t)__eth_tb[i]; + __eth_td[i].tdes3 = (uint32_t)&__eth_td[(i + 1) % STM32_MAC_TRANSMIT_BUFFERS]; + } + + /* Selection of the RMII or MII mode based on info exported by board.h.*/ +#if defined(STM32F10X_CL) +#if defined(BOARD_PHY_RMII) + AFIO->MAPR |= AFIO_MAPR_MII_RMII_SEL; +#else + AFIO->MAPR &= ~AFIO_MAPR_MII_RMII_SEL; +#endif +#elif defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32F7XX) +#if defined(BOARD_PHY_RMII) + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; +#else + SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL; +#endif +#else +#error "unsupported STM32 platform for MAC driver" +#endif + + /* Reset of the MAC core.*/ + rccResetETH(); + + /* MAC clocks temporary activation.*/ + rccEnableETH(true); + + /* PHY address setup.*/ +#if defined(BOARD_PHY_ADDRESS) + ETHD1.phyaddr = BOARD_PHY_ADDRESS << 11; +#else + mii_find_phy(ÐD1); +#endif + +#if defined(BOARD_PHY_RESET) + /* PHY board-specific reset procedure.*/ + BOARD_PHY_RESET(); +#else + /* PHY soft reset procedure.*/ + mii_write(ÐD1, MII_BMCR, BMCR_RESET); +#if defined(BOARD_PHY_RESET_DELAY) + osalSysPolledDelayX(BOARD_PHY_RESET_DELAY); +#endif + while (mii_read(ÐD1, MII_BMCR) & BMCR_RESET) + ; +#endif + +#if STM32_MAC_ETH1_CHANGE_PHY_STATE + /* PHY in power down mode until the driver will be started.*/ + mii_write(ÐD1, MII_BMCR, mii_read(ÐD1, MII_BMCR) | BMCR_PDOWN); +#endif + + /* MAC clocks stopped again.*/ + rccDisableETH(); +} + +/** + * @brief Configures and activates the MAC peripheral. + * + * @param[in] macp pointer to the @p MACDriver object + * + * @notapi + */ +void mac_lld_start(MACDriver *macp) { + unsigned i; + + /* Resets the state of all descriptors.*/ + for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++) + __eth_rd[i].rdes0 = STM32_RDES0_OWN; + macp->rxptr = (stm32_eth_rx_descriptor_t *)__eth_rd; + for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++) + __eth_td[i].tdes0 = STM32_TDES0_TCH; + macp->txptr = (stm32_eth_tx_descriptor_t *)__eth_td; + + /* MAC clocks activation and commanded reset procedure.*/ + rccEnableETH(true); +#if defined(STM32_MAC_DMABMR_SR) + ETH->DMABMR |= ETH_DMABMR_SR; + while (ETH->DMABMR & ETH_DMABMR_SR) + ; +#endif + + /* ISR vector enabled.*/ + nvicEnableVector(STM32_ETH_NUMBER, STM32_MAC_ETH1_IRQ_PRIORITY); + +#if STM32_MAC_ETH1_CHANGE_PHY_STATE + /* PHY in power up mode.*/ + mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) & ~BMCR_PDOWN); +#endif + + /* MAC configuration.*/ + ETH->MACFFR = 0; + ETH->MACFCR = 0; + ETH->MACVLANTR = 0; + + /* MAC address setup.*/ + if (macp->config->mac_address == NULL) + mac_lld_set_address(default_mac_address); + else + mac_lld_set_address(macp->config->mac_address); + + /* Transmitter and receiver enabled. + Note that the complete setup of the MAC is performed when the link + status is detected.*/ +#if STM32_MAC_IP_CHECKSUM_OFFLOAD + ETH->MACCR = ETH_MACCR_IPCO | ETH_MACCR_RE | ETH_MACCR_TE; +#else + ETH->MACCR = ETH_MACCR_RE | ETH_MACCR_TE; +#endif + + /* DMA configuration: + Descriptor chains pointers.*/ + ETH->DMARDLAR = (uint32_t)__eth_rd; + ETH->DMATDLAR = (uint32_t)__eth_td; + + /* Enabling required interrupt sources.*/ + ETH->DMASR = ETH->DMASR; + ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE; + + /* DMA general settings.*/ + ETH->DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_RDP_1Beat | ETH_DMABMR_PBL_1Beat; + + /* Check because errata on some devices. There should be no need to + disable flushing because the TXFIFO should be empty on macStart().*/ +#if !defined(STM32_MAC_DISABLE_TX_FLUSH) + /* Transmit FIFO flush.*/ + ETH->DMAOMR = ETH_DMAOMR_FTF; + while (ETH->DMAOMR & ETH_DMAOMR_FTF) + ; +#endif + + /* DMA final configuration and start.*/ + ETH->DMAOMR = ETH_DMAOMR_DTCEFD | ETH_DMAOMR_RSF | ETH_DMAOMR_TSF | + ETH_DMAOMR_ST | ETH_DMAOMR_SR; +} + +/** + * @brief Deactivates the MAC peripheral. + * + * @param[in] macp pointer to the @p MACDriver object + * + * @notapi + */ +void mac_lld_stop(MACDriver *macp) { + + if (macp->state != MAC_STOP) { +#if STM32_MAC_ETH1_CHANGE_PHY_STATE + /* PHY in power down mode until the driver will be restarted.*/ + mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) | BMCR_PDOWN); +#endif + + /* MAC and DMA stopped.*/ + ETH->MACCR = 0; + ETH->DMAOMR = 0; + ETH->DMAIER = 0; + ETH->DMASR = ETH->DMASR; + + /* MAC clocks stopped.*/ + rccDisableETH(); + + /* ISR vector disabled.*/ + nvicDisableVector(STM32_ETH_NUMBER); + } +} + +/** + * @brief Returns a transmission descriptor. + * @details One of the available transmission descriptors is locked and + * returned. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[out] tdp pointer to a @p MACTransmitDescriptor structure + * @return The operation status. + * @retval MSG_OK the descriptor has been obtained. + * @retval MSG_TIMEOUT descriptor not available. + * + * @notapi + */ +msg_t mac_lld_get_transmit_descriptor(MACDriver *macp, + MACTransmitDescriptor *tdp) { + stm32_eth_tx_descriptor_t *tdes; + + if (!macp->link_up) + return MSG_TIMEOUT; + + /* Get Current TX descriptor.*/ + tdes = macp->txptr; + + /* Ensure that descriptor isn't owned by the Ethernet DMA or locked by + another thread.*/ + if (tdes->tdes0 & (STM32_TDES0_OWN | STM32_TDES0_LOCKED)) { + return MSG_TIMEOUT; + } + + /* Marks the current descriptor as locked using a reserved bit.*/ + tdes->tdes0 |= STM32_TDES0_LOCKED; + + /* Next TX descriptor to use.*/ + macp->txptr = (stm32_eth_tx_descriptor_t *)tdes->tdes3; + + /* Set the buffer size and configuration.*/ + tdp->offset = 0; + tdp->size = STM32_MAC_BUFFERS_SIZE; + tdp->physdesc = tdes; + + return MSG_OK; +} + +/** + * @brief Releases a transmit descriptor and starts the transmission of the + * enqueued data as a single frame. + * + * @param[in] tdp the pointer to the @p MACTransmitDescriptor structure + * + * @notapi + */ +void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp) { + + osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN), + "attempt to release descriptor already owned by DMA"); + + osalSysLock(); + + /* Unlocks the descriptor and returns it to the DMA engine.*/ + tdp->physdesc->tdes1 = tdp->offset; + tdp->physdesc->tdes0 = STM32_TDES0_CIC(STM32_MAC_IP_CHECKSUM_OFFLOAD) | + STM32_TDES0_IC | STM32_TDES0_LS | STM32_TDES0_FS | + STM32_TDES0_TCH | STM32_TDES0_OWN; + + /* Wait for the write to tdes0 to go through before resuming the DMA.*/ + __DSB(); + + /* If the DMA engine is stalled then a restart request is issued.*/ + if ((ETH->DMASR & ETH_DMASR_TPS) == ETH_DMASR_TPS_Suspended) { + ETH->DMASR = ETH_DMASR_TBUS; + ETH->DMATPDR = ETH_DMASR_TBUS; /* Any value is OK.*/ + } + + osalSysUnlock(); +} + +/** + * @brief Returns a receive descriptor. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[out] rdp pointer to a @p MACReceiveDescriptor structure + * @return The operation status. + * @retval MSG_OK the descriptor has been obtained. + * @retval MSG_TIMEOUT descriptor not available. + * + * @notapi + */ +msg_t mac_lld_get_receive_descriptor(MACDriver *macp, + MACReceiveDescriptor *rdp) { + stm32_eth_rx_descriptor_t *rdes; + + /* Get Current RX descriptor.*/ + rdes = macp->rxptr; + + /* Iterates through received frames until a valid one is found, invalid + frames are discarded.*/ + while (!(rdes->rdes0 & STM32_RDES0_OWN)) { + if (!(rdes->rdes0 & (STM32_RDES0_AFM | STM32_RDES0_ES)) +#if STM32_MAC_IP_CHECKSUM_OFFLOAD + && (rdes->rdes0 & STM32_RDES0_FT) + && !(rdes->rdes0 & (STM32_RDES0_IPHCE | STM32_RDES0_PCE)) +#endif + && (rdes->rdes0 & STM32_RDES0_FS) && (rdes->rdes0 & STM32_RDES0_LS)) { + /* Found a valid one.*/ + rdp->offset = 0; + rdp->size = ((rdes->rdes0 & STM32_RDES0_FL_MASK) >> 16) - 4; + rdp->physdesc = rdes; + macp->rxptr = (stm32_eth_rx_descriptor_t *)rdes->rdes3; + + return MSG_OK; + } + /* Invalid frame found, purging.*/ + rdes->rdes0 = STM32_RDES0_OWN; + rdes = (stm32_eth_rx_descriptor_t *)rdes->rdes3; + } + + /* Next descriptor to check.*/ + macp->rxptr = rdes; + + return MSG_TIMEOUT; +} + +/** + * @brief Releases a receive descriptor. + * @details The descriptor and its buffer are made available for more incoming + * frames. + * + * @param[in] rdp the pointer to the @p MACReceiveDescriptor structure + * + * @notapi + */ +void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp) { + + osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN), + "attempt to release descriptor already owned by DMA"); + + osalSysLock(); + + /* Give buffer back to the Ethernet DMA.*/ + rdp->physdesc->rdes0 = STM32_RDES0_OWN; + + /* Wait for the write to rdes0 to go through before resuming the DMA.*/ + __DSB(); + + /* If the DMA engine is stalled then a restart request is issued.*/ + if ((ETH->DMASR & ETH_DMASR_RPS) == ETH_DMASR_RPS_Suspended) { + ETH->DMASR = ETH_DMASR_RBUS; + ETH->DMARPDR = ETH_DMASR_RBUS; /* Any value is OK.*/ + } + + osalSysUnlock(); +} + +/** + * @brief Updates and returns the link status. + * + * @param[in] macp pointer to the @p MACDriver object + * @return The link status. + * @retval true if the link is active. + * @retval false if the link is down. + * + * @notapi + */ +bool mac_lld_poll_link_status(MACDriver *macp) { + uint32_t maccr, bmsr, bmcr; + + maccr = ETH->MACCR; + + /* PHY CR and SR registers read.*/ + (void)mii_read(macp, MII_BMSR); + bmsr = mii_read(macp, MII_BMSR); + bmcr = mii_read(macp, MII_BMCR); + + /* Check on auto-negotiation mode.*/ + if (bmcr & BMCR_ANENABLE) { + uint32_t lpa; + + /* Auto-negotiation must be finished without faults and link established.*/ + if ((bmsr & (BMSR_LSTATUS | BMSR_RFAULT | BMSR_ANEGCOMPLETE)) != + (BMSR_LSTATUS | BMSR_ANEGCOMPLETE)) + return macp->link_up = false; + + /* Auto-negotiation enabled, checks the LPA register.*/ + lpa = mii_read(macp, MII_LPA); + + /* Check on link speed.*/ + if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4)) + maccr |= ETH_MACCR_FES; + else + maccr &= ~ETH_MACCR_FES; + + /* Check on link mode.*/ + if (lpa & (LPA_10FULL | LPA_100FULL)) + maccr |= ETH_MACCR_DM; + else + maccr &= ~ETH_MACCR_DM; + } + else { + /* Link must be established.*/ + if (!(bmsr & BMSR_LSTATUS)) + return macp->link_up = false; + + /* Check on link speed.*/ + if (bmcr & BMCR_SPEED100) + maccr |= ETH_MACCR_FES; + else + maccr &= ~ETH_MACCR_FES; + + /* Check on link mode.*/ + if (bmcr & BMCR_FULLDPLX) + maccr |= ETH_MACCR_DM; + else + maccr &= ~ETH_MACCR_DM; + } + + /* Changes the mode in the MAC.*/ + ETH->MACCR = maccr; + + /* Returns the link status.*/ + return macp->link_up = true; +} + +/** + * @brief Writes to a transmit descriptor's stream. + * + * @param[in] tdp pointer to a @p MACTransmitDescriptor structure + * @param[in] buf pointer to the buffer containing the data to be + * written + * @param[in] size number of bytes to be written + * @return The number of bytes written into the descriptor's + * stream, this value can be less than the amount + * specified in the parameter @p size if the maximum + * frame size is reached. + * + * @notapi + */ +size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp, + uint8_t *buf, + size_t size) { + + osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN), + "attempt to write descriptor already owned by DMA"); + + if (size > tdp->size - tdp->offset) + size = tdp->size - tdp->offset; + + if (size > 0) { + memcpy((uint8_t *)(tdp->physdesc->tdes2) + tdp->offset, buf, size); + tdp->offset += size; + } + return size; +} + +/** + * @brief Reads from a receive descriptor's stream. + * + * @param[in] rdp pointer to a @p MACReceiveDescriptor structure + * @param[in] buf pointer to the buffer that will receive the read data + * @param[in] size number of bytes to be read + * @return The number of bytes read from the descriptor's + * stream, this value can be less than the amount + * specified in the parameter @p size if there are + * no more bytes to read. + * + * @notapi + */ +size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp, + uint8_t *buf, + size_t size) { + + osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN), + "attempt to read descriptor already owned by DMA"); + + if (size > rdp->size - rdp->offset) + size = rdp->size - rdp->offset; + + if (size > 0) { + memcpy(buf, (uint8_t *)(rdp->physdesc->rdes2) + rdp->offset, size); + rdp->offset += size; + } + return size; +} + +#if MAC_USE_ZERO_COPY || defined(__DOXYGEN__) +/** + * @brief Returns a pointer to the next transmit buffer in the descriptor + * chain. + * @note The API guarantees that enough buffers can be requested to fill + * a whole frame. + * + * @param[in] tdp pointer to a @p MACTransmitDescriptor structure + * @param[in] size size of the requested buffer. Specify the frame size + * on the first call then scale the value down subtracting + * the amount of data already copied into the previous + * buffers. + * @param[out] sizep pointer to variable receiving the buffer size, it is + * zero when the last buffer has already been returned. + * Note that a returned size lower than the amount + * requested means that more buffers must be requested + * in order to fill the frame data entirely. + * @return Pointer to the returned buffer. + * @retval NULL if the buffer chain has been entirely scanned. + * + * @notapi + */ +uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp, + size_t size, + size_t *sizep) { + + if (tdp->offset == 0) { + *sizep = tdp->size; + tdp->offset = size; + return (uint8_t *)tdp->physdesc->tdes2; + } + *sizep = 0; + return NULL; +} + +/** + * @brief Returns a pointer to the next receive buffer in the descriptor + * chain. + * @note The API guarantees that the descriptor chain contains a whole + * frame. + * + * @param[in] rdp pointer to a @p MACReceiveDescriptor structure + * @param[out] sizep pointer to variable receiving the buffer size, it is + * zero when the last buffer has already been returned. + * @return Pointer to the returned buffer. + * @retval NULL if the buffer chain has been entirely scanned. + * + * @notapi + */ +const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp, + size_t *sizep) { + + if (rdp->size > 0) { + *sizep = rdp->size; + rdp->offset = rdp->size; + rdp->size = 0; + return (uint8_t *)rdp->physdesc->rdes2; + } + *sizep = 0; + return NULL; +} +#endif /* MAC_USE_ZERO_COPY */ + +#endif /* HAL_USE_MAC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.h new file mode 100644 index 0000000..31ad016 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.h @@ -0,0 +1,359 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file MACv1/hal_mac_lld.h + * @brief STM32 low level MAC driver header. + * + * @addtogroup MAC + * @{ + */ + +#ifndef HAL_MAC_LLD_H +#define HAL_MAC_LLD_H + +#if HAL_USE_MAC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief This implementation supports the zero-copy mode API. + */ +#define MAC_SUPPORTS_ZERO_COPY TRUE + +/** + * @name RDES0 constants + * @{ + */ +#define STM32_RDES0_OWN 0x80000000 +#define STM32_RDES0_AFM 0x40000000 +#define STM32_RDES0_FL_MASK 0x3FFF0000 +#define STM32_RDES0_ES 0x00008000 +#define STM32_RDES0_DESERR 0x00004000 +#define STM32_RDES0_SAF 0x00002000 +#define STM32_RDES0_LE 0x00001000 +#define STM32_RDES0_OE 0x00000800 +#define STM32_RDES0_VLAN 0x00000400 +#define STM32_RDES0_FS 0x00000200 +#define STM32_RDES0_LS 0x00000100 +#define STM32_RDES0_IPHCE 0x00000080 +#define STM32_RDES0_LCO 0x00000040 +#define STM32_RDES0_FT 0x00000020 +#define STM32_RDES0_RWT 0x00000010 +#define STM32_RDES0_RE 0x00000008 +#define STM32_RDES0_DE 0x00000004 +#define STM32_RDES0_CE 0x00000002 +#define STM32_RDES0_PCE 0x00000001 +/** @} */ + +/** + * @name RDES1 constants + * @{ + */ +#define STM32_RDES1_DIC 0x80000000 +#define STM32_RDES1_RBS2_MASK 0x1FFF0000 +#define STM32_RDES1_RER 0x00008000 +#define STM32_RDES1_RCH 0x00004000 +#define STM32_RDES1_RBS1_MASK 0x00001FFF +/** @} */ + +/** + * @name TDES0 constants + * @{ + */ +#define STM32_TDES0_OWN 0x80000000 +#define STM32_TDES0_IC 0x40000000 +#define STM32_TDES0_LS 0x20000000 +#define STM32_TDES0_FS 0x10000000 +#define STM32_TDES0_DC 0x08000000 +#define STM32_TDES0_DP 0x04000000 +#define STM32_TDES0_TTSE 0x02000000 +#define STM32_TDES0_LOCKED 0x01000000 /* NOTE: Pseudo flag. */ +#define STM32_TDES0_CIC_MASK 0x00C00000 +#define STM32_TDES0_CIC(n) ((n) << 22) +#define STM32_TDES0_TER 0x00200000 +#define STM32_TDES0_TCH 0x00100000 +#define STM32_TDES0_TTSS 0x00020000 +#define STM32_TDES0_IHE 0x00010000 +#define STM32_TDES0_ES 0x00008000 +#define STM32_TDES0_JT 0x00004000 +#define STM32_TDES0_FF 0x00002000 +#define STM32_TDES0_IPE 0x00001000 +#define STM32_TDES0_LCA 0x00000800 +#define STM32_TDES0_NC 0x00000400 +#define STM32_TDES0_LCO 0x00000200 +#define STM32_TDES0_EC 0x00000100 +#define STM32_TDES0_VF 0x00000080 +#define STM32_TDES0_CC_MASK 0x00000078 +#define STM32_TDES0_ED 0x00000004 +#define STM32_TDES0_UF 0x00000002 +#define STM32_TDES0_DB 0x00000001 +/** @} */ + +/** + * @name TDES1 constants + * @{ + */ +#define STM32_TDES1_TBS2_MASK 0x1FFF0000 +#define STM32_TDES1_TBS1_MASK 0x00001FFF +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief Number of available transmit buffers. + */ +#if !defined(STM32_MAC_TRANSMIT_BUFFERS) || defined(__DOXYGEN__) +#define STM32_MAC_TRANSMIT_BUFFERS 2 +#endif + +/** + * @brief Number of available receive buffers. + */ +#if !defined(STM32_MAC_RECEIVE_BUFFERS) || defined(__DOXYGEN__) +#define STM32_MAC_RECEIVE_BUFFERS 4 +#endif + +/** + * @brief Maximum supported frame size. + */ +#if !defined(STM32_MAC_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define STM32_MAC_BUFFERS_SIZE 1522 +#endif + +/** + * @brief PHY detection timeout. + * @details Timeout for PHY address detection, the scan for a PHY is performed + * the specified number of times before invoking the failure handler. + * This setting applies only if the PHY address is not explicitly + * set in the board header file using @p BOARD_PHY_ADDRESS. A zero + * value disables the timeout and a single search is performed. + */ +#if !defined(STM32_MAC_PHY_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_MAC_PHY_TIMEOUT 100 +#endif + +/** + * @brief Change the PHY power state inside the driver. + */ +#if !defined(STM32_MAC_ETH1_CHANGE_PHY_STATE) || defined(__DOXYGEN__) +#define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE +#endif + +/** + * @brief ETHD1 interrupt priority level setting. + */ +#if !defined(STM32_MAC_ETH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_MAC_ETH1_IRQ_PRIORITY 13 +#endif + +/** + * @brief IP checksum offload. + * @details The following modes are available: + * - 0 Function disabled. + * - 1 Only IP header checksum calculation and insertion are enabled. + * - 2 IP header checksum and payload checksum calculation and + * insertion are enabled, but pseudo-header checksum is not + * calculated in hardware. + * - 3 IP Header checksum and payload checksum calculation and + * insertion are enabled, and pseudo-header checksum is + * calculated in hardware. + * . + */ +#if !defined(STM32_MAC_IP_CHECKSUM_OFFLOAD) || defined(__DOXYGEN__) +#define STM32_MAC_IP_CHECKSUM_OFFLOAD 0 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of an STM32 Ethernet receive descriptor. + */ +typedef struct { + volatile uint32_t rdes0; + volatile uint32_t rdes1; + volatile uint32_t rdes2; + volatile uint32_t rdes3; +} stm32_eth_rx_descriptor_t; + +/** + * @brief Type of an STM32 Ethernet transmit descriptor. + */ +typedef struct { + volatile uint32_t tdes0; + volatile uint32_t tdes1; + volatile uint32_t tdes2; + volatile uint32_t tdes3; +} stm32_eth_tx_descriptor_t; + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief MAC address. + */ + uint8_t *mac_address; + /* End of the mandatory fields.*/ +} MACConfig; + +/** + * @brief Structure representing a MAC driver. + */ +struct MACDriver { + /** + * @brief Driver state. + */ + macstate_t state; + /** + * @brief Current configuration data. + */ + const MACConfig *config; + /** + * @brief Transmit semaphore. + */ + threads_queue_t tdqueue; + /** + * @brief Receive semaphore. + */ + threads_queue_t rdqueue; +#if MAC_USE_EVENTS || defined(__DOXYGEN__) + /** + * @brief Receive event. + */ + event_source_t rdevent; +#endif + /* End of the mandatory fields.*/ + /** + * @brief Link status flag. + */ + bool link_up; + /** + * @brief PHY address (pre shifted). + */ + uint32_t phyaddr; + /** + * @brief Receive next frame pointer. + */ + stm32_eth_rx_descriptor_t *rxptr; + /** + * @brief Transmit next frame pointer. + */ + stm32_eth_tx_descriptor_t *txptr; +}; + +/** + * @brief Structure representing a transmit descriptor. + */ +typedef struct { + /** + * @brief Current write offset. + */ + size_t offset; + /** + * @brief Available space size. + */ + size_t size; + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the physical descriptor. + */ + stm32_eth_tx_descriptor_t *physdesc; +} MACTransmitDescriptor; + +/** + * @brief Structure representing a receive descriptor. + */ +typedef struct { + /** + * @brief Current read offset. + */ + size_t offset; + /** + * @brief Available data size. + */ + size_t size; + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the physical descriptor. + */ + stm32_eth_rx_descriptor_t *physdesc; +} MACReceiveDescriptor; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern MACDriver ETHD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void mii_write(MACDriver *macp, uint32_t reg, uint32_t value); + uint32_t mii_read(MACDriver *macp, uint32_t reg); + void mac_lld_init(void); + void mac_lld_start(MACDriver *macp); + void mac_lld_stop(MACDriver *macp); + msg_t mac_lld_get_transmit_descriptor(MACDriver *macp, + MACTransmitDescriptor *tdp); + void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp); + msg_t mac_lld_get_receive_descriptor(MACDriver *macp, + MACReceiveDescriptor *rdp); + void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp); + bool mac_lld_poll_link_status(MACDriver *macp); + size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp, + uint8_t *buf, + size_t size); + size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp, + uint8_t *buf, + size_t size); +#if MAC_USE_ZERO_COPY + uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp, + size_t size, + size_t *sizep); + const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp, + size_t *sizep); +#endif /* MAC_USE_ZERO_COPY */ +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_MAC */ + +#endif /* HAL_MAC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/driver.mk new file mode 100644 index 0000000..d10e2ad --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MDMAv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/notes.txt new file mode 100644 index 0000000..a092556 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/notes.txt @@ -0,0 +1,11 @@ +STM32 MDMAv1 driver. + +Driver capability: + +- The driver supports the STM32 complex MDMA controller found on H7 + sub-family. + +The file registry must export: + +STM32_MDMA_CHn_HANDLER - Vector name for channel "n" (0..15). +STM32_MDMA_CHn_NUMBER - Vector number for channel "n" (0..15). diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c new file mode 100644 index 0000000..c77bfa0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c @@ -0,0 +1,355 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file MDMAv1/stm32_mdma.c + * @brief MDMA helper driver code. + * + * @addtogroup STM32_MDMA + * @details MDMA sharing helper driver. In the STM32 the MDMA channels are a + * shared resource, this driver allows to allocate and free MDMA + * STM32 at runtime in order to allow all the other device + * drivers to coordinate the access to the resource. + * @note The MDMA ISR handlers are all declared into this module because + * sharing, the various device drivers can associate a callback to + * ISRs when allocating channels. + * @{ + */ + +#include "hal.h" + +/* The following macro is only defined if some driver requiring MDMA services + has been enabled.*/ +#if defined(STM32_MDMA_REQUIRED) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Global MDMA-related data structures. + */ +static struct { + /** + * @brief Mask of the allocated channels. + */ + uint32_t allocated_mask; + /** + * @brief MDMA IRQ redirectors. + */ + stm32_mdma_channel_t channels[STM32_MDMA_CHANNELS]; +} mdma; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static void mdma_serve_interrupt(const stm32_mdma_channel_t *mdmachp) { + uint32_t flags; + + flags = mdmachp->channel->CISR; + mdmachp->channel->CIFCR = flags; + if (mdmachp->func != NULL) { + mdmachp->func(mdmachp->param, flags); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief MDMA shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_MDMA_HANDLER) { + uint32_t gisr = MDMA->GISR0; + OSAL_IRQ_PROLOGUE(); + + if ((gisr & (1U << 0)) != 0U) { + mdma_serve_interrupt(&mdma.channels[0]); + } + + if ((gisr & (1U << 1)) != 0U) { + mdma_serve_interrupt(&mdma.channels[1]); + } + + if ((gisr & (1U << 2)) != 0U) { + mdma_serve_interrupt(&mdma.channels[2]); + } + + if ((gisr & (1U << 3)) != 0U) { + mdma_serve_interrupt(&mdma.channels[3]); + } + + if ((gisr & (1U << 4)) != 0U) { + mdma_serve_interrupt(&mdma.channels[4]); + } + + if ((gisr & (1U << 5)) != 0U) { + mdma_serve_interrupt(&mdma.channels[5]); + } + + if ((gisr & (1U << 6)) != 0U) { + mdma_serve_interrupt(&mdma.channels[6]); + } + + if ((gisr & (1U << 7)) != 0U) { + mdma_serve_interrupt(&mdma.channels[7]); + } + + if ((gisr & (1U << 8)) != 0U) { + mdma_serve_interrupt(&mdma.channels[8]); + } + + if ((gisr & (1U << 9)) != 0U) { + mdma_serve_interrupt(&mdma.channels[9]); + } + + if ((gisr & (1U << 10)) != 0U) { + mdma_serve_interrupt(&mdma.channels[10]); + } + + if ((gisr & (1U << 11)) != 0U) { + mdma_serve_interrupt(&mdma.channels[11]); + } + + if ((gisr & (1U << 12)) != 0U) { + mdma_serve_interrupt(&mdma.channels[12]); + } + + if ((gisr & (1U << 13)) != 0U) { + mdma_serve_interrupt(&mdma.channels[13]); + } + + if ((gisr & (1U << 14)) != 0U) { + mdma_serve_interrupt(&mdma.channels[14]); + } + + if ((gisr & (1U << 15)) != 0U) { + mdma_serve_interrupt(&mdma.channels[15]); + } + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief STM32 MDMA helper initialization. + * + * @init + */ +void mdmaInit(void) { + static MDMA_Channel_TypeDef * const ch[STM32_MDMA_CHANNELS] = { + MDMA_Channel0, MDMA_Channel1, MDMA_Channel2, MDMA_Channel3, + MDMA_Channel4, MDMA_Channel5, MDMA_Channel6, MDMA_Channel7, + MDMA_Channel8, MDMA_Channel9, MDMA_Channel10, MDMA_Channel11, + MDMA_Channel12, MDMA_Channel13, MDMA_Channel14, MDMA_Channel15 + }; + unsigned i; + + mdma.allocated_mask = 0U; + for (i = 0U; i < STM32_MDMA_CHANNELS; i++) { + MDMA_Channel_TypeDef *cp = ch[i]; + mdma.channels[i].channel = cp; + mdma.channels[i].func = NULL; + mdma.channels[i].channel->CCR = STM32_MDMA_CCR_RESET_VALUE; + mdma.channels[i].channel->CTCR = STM32_MDMA_CTCR_RESET_VALUE; + mdma.channels[i].channel->CIFCR = STM32_MDMA_CIFCR_CTEIF | + STM32_MDMA_CIFCR_CBRTIF | + STM32_MDMA_CIFCR_CBRTIF | + STM32_MDMA_CIFCR_CCTCIF | + STM32_MDMA_CIFCR_CTEIF; + } +} + +/** + * @brief Allocates an MDMA channel. + * @details The channel is allocated and, if required, the MDMA clock enabled. + * The function also enables the IRQ vector associated to the channel + * and initializes its priority. + * + * @param[in] id numeric identifiers of a specific channel or: + * - @p STM32_MDMA_CHANNEL_ID_ANY for any channel. + * . + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return Pointer to the allocated @p stm32_mdma_channel_t + * structure. + * @retval NULL if a/the channel is not available. + * + * @iclass + */ +const stm32_mdma_channel_t *dmaChannelAllocI(uint32_t id, + stm32_mdmaisr_t func, + void *param) { + uint32_t i, startid, endid; + + osalDbgCheckClassI(); + + if (id < STM32_MDMA_CHANNELS) { + startid = id; + endid = id; + } + else if (id == STM32_MDMA_CHANNEL_ID_ANY) { + startid = 0U; + endid = STM32_MDMA_CHANNELS - 1U; + } + else { + osalDbgCheck(false); + return NULL; + } + + for (i = startid; i <= endid; i++) { + uint32_t mask = (1U << i); + if ((mdma.allocated_mask & mask) == 0U) { + stm32_mdma_channel_t *mdmachp = &mdma.channels[i]; + + /* Installs the MDMA handler.*/ + mdma.allocated_mask |= mask; + mdmachp->func = func; + mdmachp->param = param; + + /* Enabling MDMA clocks required by the current channels set.*/ + if (mdma.allocated_mask != 0U) { + rccEnableMDMA(true); + } + + return mdmachp; + } + } + + return NULL; +} + +/** + * @brief Allocates a MDMA channel. + * @details The channel is allocated and, if required, the MDMA clock enabled. + * The function also enables the IRQ vector associated to the channel + * and initializes its priority. + * + * @param[in] id numeric identifiers of a specific channel or: + * - @p STM32_MDMA_CHANNEL_ID_ANY for any channel. + * . + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return Pointer to the allocated @p stm32_mdma_channel_t + * structure. + * @retval NULL if a/the channel is not available. + * + * @api + */ +const stm32_mdma_channel_t *dmaChannelAlloc(uint32_t id, + stm32_mdmaisr_t func, + void *param) { + const stm32_mdma_channel_t *mdmachp; + + osalSysLock(); + mdmachp = mdmaChannelAllocI(id, func, param); + osalSysUnlock(); + + return mdmachp; +} + +/** + * @brief Releases a MDMA channel. + * @details The channel is freed and, if required, the MDMA clock disabled. + * Trying to release a unallocated channel is an illegal operation + * and is trapped if assertions are enabled. + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + * + * @iclass + */ +void mdmaChannelFreeI(const stm32_mdma_channel_t *mdmachp) { + uint32_t channel = mdmachp - mdma.channels; + osalDbgCheck(mdmachp != NULL); + + /* Check if the channels is not taken.*/ + osalDbgAssert((mdma.allocated_mask & (1U << channel)) != 0U, + "not allocated"); + + /* Marks the channel as not allocated.*/ + mdma.allocated_mask &= ~(1U << channel); + + /* Shutting down clocks that are no more required, if any.*/ + if (mdma.allocated_mask == 0U) { + rccDisableMDMA(); + } +} + +/** + * @brief Releases a MDMA channel. + * @details The channel is freed and, if required, the MDMA clock disabled. + * Trying to release a unallocated channel is an illegal operation + * and is trapped if assertions are enabled. + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + * + * @api + */ +void mdmaChannelFree(const stm32_mdma_channel_t *mdmachp) { + + osalSysLock(); + mdmaChannelFreeI(mdmachp); + osalSysUnlock(); +} + +/** + * @brief MDMA stream disable. + * @details The function disables the specified stream, waits for the disable + * operation to complete and then clears any pending interrupt. + * @pre The stream must have been allocated using @p mdmaChannelAlloc(). + * @post After use the stream can be released using @p mdmaChannelFree(). + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + * + * @xclass + */ +void mdmaChannelDisableX(const stm32_mdma_channel_t *mdmachp) { + uint32_t ccr = mdmachp->channel->CCR; + + /* Clearing CCR regardless of previous state.*/ + mdmachp->channel->CCR &= ~(STM32_MDMA_CCR_TCIE | STM32_MDMA_CCR_BTIE | + STM32_MDMA_CCR_BRTIE | STM32_MDMA_CCR_CTCIE | + STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_EN); + + /* If the channel was enabled then waiting for ongoing operations + to finish.*/ + if ((ccr & STM32_MDMA_CCR_EN) != 0U) { + while (((mdmachp)->channel->CISR & STM32_MDMA_CISR_CTCIF) == 0U) + ; + } + + /* Clearing IRQ sources.*/ + mdmaChannelClearInterruptX(mdmachp); +} + +#endif /* defined(STM32_MDMA_REQUIRED) */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.h new file mode 100644 index 0000000..6dfe9eb --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.h @@ -0,0 +1,448 @@ +/* + ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file MDMAv1/stm32_mdma.h + * @brief MDMA helper driver header. + * + * @addtogroup STM32_MDMA + * @{ + */ + +#ifndef STM32_MDMA_H +#define STM32_MDMA_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Total number of MDMA streams. + */ +#define STM32_MDMA_CHANNELS 16U + +/** + * @brief Mask of the ISR bits passed to the MDMA callback functions. + */ +#define STM32_MDMA_ISR_MASK 0x1FU + +/** + * @brief Checks if a MDMA priority is within the valid range. + * @param[in] prio MDMA priority + * + * @retval The check result. + * @retval false invalid MDMA priority. + * @retval true correct MDMA priority. + */ +#define STM32_MDMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U)) + +/** + * @brief Checks if a MDMA channel id is within the valid range. + * + * @param[in] id MDMA channel id + * @retval The check result. + * @retval false invalid MDMA channel. + * @retval true correct MDMA channel. + */ +#define STM32_MDMA_IS_VALID_CHANNEL(id) (((id) >= 0U) && \ + ((id) <= STM32_MDMA_CHANNELS)) + +/** + * @brief Special stream identifier + */ +#define STM32_MDMA_CHANNEL_ID_ANY STM32_MDMA_CHANNELS + +/** + * @name CISR register constants + * @{ + */ +#define STM32_MDMA_CISR_TEIF (1U << 0) +#define STM32_MDMA_CISR_CTCIF (1U << 1) +#define STM32_MDMA_CISR_BRTIF (1U << 2) +#define STM32_MDMA_CISR_BTIF (1U << 3) +#define STM32_MDMA_CISR_TCIF (1U << 4) +#define STM32_MDMA_CISR_CRQA (1U << 16) +/** @} */ + +/** + * @name CIFCR register constants + * @{ + */ +#define STM32_MDMA_CIFCR_CTEIF (1U << 0) +#define STM32_MDMA_CIFCR_CCTCIF (1U << 1) +#define STM32_MDMA_CIFCR_CBRTIF (1U << 2) +#define STM32_MDMA_CIFCR_CBTIF (1U << 3) +#define STM32_MDMA_CIFCR_CTCIF (1U << 4) +/** @} */ + +/** + * @name CESR register constants + * @{ + */ +#define STM32_MDMA_CESR_TEA_MASK (127U << 0) +#define STM32_MDMA_CESR_TED (1U << 7) +#define STM32_MDMA_CESR_TELD (1U << 8) +#define STM32_MDMA_CESR_TEMD (1U << 9) +#define STM32_MDMA_CESR_ASE (1U << 10) +#define STM32_MDMA_CESR_BSE (1U << 11) +/** @} */ + +/** + * @name CCR register constants + * @{ + */ +#define STM32_MDMA_CCR_RESET_VALUE 0x00000000U +#define STM32_MDMA_CCR_EN (1U << 0) +#define STM32_MDMA_CCR_TEIE (1U << 1) +#define STM32_MDMA_CCR_CTCIE (1U << 2) +#define STM32_MDMA_CCR_BRTIE (1U << 3) +#define STM32_MDMA_CCR_BTIE (1U << 4) +#define STM32_MDMA_CCR_TCIE (1U << 5) +#define STM32_MDMA_CCR_PL_MASK (3U << 6) +#define STM32_MDMA_CCR_PL(n) ((n) << 6) +#define STM32_MDMA_CCR_BEX (1U << 12) +#define STM32_MDMA_CCR_HEX (1U << 13) +#define STM32_MDMA_CCR_WEX (1U << 14) +#define STM32_MDMA_CCR_SWRQ (1U << 16) +/** @} */ + +/** + * @name CTCR register constants + * @{ + */ +#define STM32_MDMA_CTCR_RESET_VALUE 0x00000000U + +#define STM32_MDMA_CTCR_SINC_MASK (3U << 0) +#define STM32_MDMA_CTCR_SINC(n) ((n) << 0) +#define STM32_MDMA_CTCR_SINC_FIXED STM32_MDMA_CTCR_SINC(0U) +#define STM32_MDMA_CTCR_SINC_INC STM32_MDMA_CTCR_SINC(1U) +#define STM32_MDMA_CTCR_SINC_DEC STM32_MDMA_CTCR_SINC(3U) + +#define STM32_MDMA_CTCR_DINC_MASK (3U << 2) +#define STM32_MDMA_CTCR_DINC(n) ((n) << 2) +#define STM32_MDMA_CTCR_DINC_FIXED STM32_MDMA_CTCR_DINC(0U) +#define STM32_MDMA_CTCR_DINC_INC STM32_MDMA_CTCR_DINC(1U) +#define STM32_MDMA_CTCR_DINC_DEC STM32_MDMA_CTCR_DINC(3U) + +#define STM32_MDMA_CTCR_SSIZE_MASK (3U << 4) +#define STM32_MDMA_CTCR_SSIZE(n) ((n) << 4) +#define STM32_MDMA_CTCR_SSIZE_BYTE STM32_MDMA_CTCR_SSIZE(0U) +#define STM32_MDMA_CTCR_SSIZE_HALF STM32_MDMA_CTCR_SSIZE(1U) +#define STM32_MDMA_CTCR_SSIZE_WORD STM32_MDMA_CTCR_SSIZE(2U) +#define STM32_MDMA_CTCR_SSIZE_DWORD STM32_MDMA_CTCR_SSIZE(3U) + +#define STM32_MDMA_CTCR_DSIZE_MASK (3U << 6) +#define STM32_MDMA_CTCR_DSIZE(n) ((n) << 6) +#define STM32_MDMA_CTCR_DSIZE_BYTE STM32_MDMA_CTCR_DSIZE(0U) +#define STM32_MDMA_CTCR_DSIZE_HALF STM32_MDMA_CTCR_DSIZE(1U) +#define STM32_MDMA_CTCR_DSIZE_WORD STM32_MDMA_CTCR_DSIZE(2U) +#define STM32_MDMA_CTCR_DSIZE_DWORD STM32_MDMA_CTCR_DSIZE(3U) + +#define STM32_MDMA_CTCR_SINCOS_MASK (3U << 8) +#define STM32_MDMA_CTCR_SINCOS(n) ((n) << 8) +#define STM32_MDMA_CTCR_SINCOS_BYTE STM32_MDMA_CTCR_SINCOS(0U) +#define STM32_MDMA_CTCR_SINCOS_HALF STM32_MDMA_CTCR_SINCOS(1U) +#define STM32_MDMA_CTCR_SINCOS_WORD STM32_MDMA_CTCR_SINCOS(2U) +#define STM32_MDMA_CTCR_SINCOS_DWORD STM32_MDMA_CTCR_SINCOS(3U) + +#define STM32_MDMA_CTCR_DINCOS_MASK (3U << 10) +#define STM32_MDMA_CTCR_DINCOS(n) ((n) << 10) +#define STM32_MDMA_CTCR_DINCOS_BYTE STM32_MDMA_CTCR_DINCOS(0U) +#define STM32_MDMA_CTCR_DINCOS_HALF STM32_MDMA_CTCR_DINCOS(1U) +#define STM32_MDMA_CTCR_DINCOS_WORD STM32_MDMA_CTCR_DINCOS(2U) +#define STM32_MDMA_CTCR_DINCOS_DWORD STM32_MDMA_CTCR_DINCOS(3U) + +#define STM32_MDMA_CTCR_SBURST_MASK (7U << 12) +#define STM32_MDMA_CTCR_SBURST(n) ((n) << 12) +#define STM32_MDMA_CTCR_SBURST_1 STM32_MDMA_CTCR_SBURST(0U) +#define STM32_MDMA_CTCR_SBURST_2 STM32_MDMA_CTCR_SBURST(1U) +#define STM32_MDMA_CTCR_SBURST_4 STM32_MDMA_CTCR_SBURST(2U) +#define STM32_MDMA_CTCR_SBURST_8 STM32_MDMA_CTCR_SBURST(3U) +#define STM32_MDMA_CTCR_SBURST_16 STM32_MDMA_CTCR_SBURST(4U) +#define STM32_MDMA_CTCR_SBURST_32 STM32_MDMA_CTCR_SBURST(5U) +#define STM32_MDMA_CTCR_SBURST_64 STM32_MDMA_CTCR_SBURST(6U) +#define STM32_MDMA_CTCR_SBURST_128 STM32_MDMA_CTCR_SBURST(7U) + +#define STM32_MDMA_CTCR_DBURST_MASK (7U << 15) +#define STM32_MDMA_CTCR_DBURST(n) ((n) << 15) +#define STM32_MDMA_CTCR_DBURST_1 STM32_MDMA_CTCR_DBURST(0U) +#define STM32_MDMA_CTCR_DBURST_2 STM32_MDMA_CTCR_DBURST(1U) +#define STM32_MDMA_CTCR_DBURST_4 STM32_MDMA_CTCR_DBURST(2U) +#define STM32_MDMA_CTCR_DBURST_8 STM32_MDMA_CTCR_DBURST(3U) +#define STM32_MDMA_CTCR_DBURST_16 STM32_MDMA_CTCR_DBURST(4U) +#define STM32_MDMA_CTCR_DBURST_32 STM32_MDMA_CTCR_DBURST(5U) +#define STM32_MDMA_CTCR_DBURST_64 STM32_MDMA_CTCR_DBURST(6U) +#define STM32_MDMA_CTCR_DBURST_128 STM32_MDMA_CTCR_DBURST(7U) + +#define STM32_MDMA_CTCR_TLEN_MASK (127U << 18) +#define STM32_MDMA_CTCR_TLEN(n) ((n) << 18) + +#define STM32_MDMA_CTCR_PKE (1U << 25) + +#define STM32_MDMA_CTCR_PAM_MASK (3U << 26) +#define STM32_MDMA_CTCR_PAM(n) ((n) << 26) +#define STM32_MDMA_CTCR_PAM_RIGHT STM32_MDMA_CTCR_PAM(0U) +#define STM32_MDMA_CTCR_PAM_RIGHT_SE STM32_MDMA_CTCR_PAM(1U) +#define STM32_MDMA_CTCR_PAM_LEFT STM32_MDMA_CTCR_PAM(2U) + +#define STM32_MDMA_CTCR_TRGM_MASK (3U << 28) +#define STM32_MDMA_CTCR_TRGM(n) ((n) << 28) +#define STM32_MDMA_CTCR_TRGM_BUFFER STM32_MDMA_CTCR_TRGM(0U) +#define STM32_MDMA_CTCR_TRGM_BLOCK STM32_MDMA_CTCR_TRGM(1U) +#define STM32_MDMA_CTCR_TRGM_REP_BLOCK STM32_MDMA_CTCR_TRGM(2U) +#define STM32_MDMA_CTCR_TRGM_WHOLE STM32_MDMA_CTCR_TRGM(3U) + +#define STM32_MDMA_CTCR_SWRM (1U << 30) + +#define STM32_MDMA_CTCR_BWM_MASK (1U << 31) +#define STM32_MDMA_CTCR_BWM_NON_BUFF (0U << 31) +#define STM32_MDMA_CTCR_BWM_BUFF (1U << 31) +/** @} */ + +/** + * @name BNDTR register constants + * @{ + */ +#define STM32_MDMA_CBNDTR_BNDT_MASK (0x1FFFFU << 0) +#define STM32_MDMA_CBNDTR_BNDT(n) ((n) << 0) +#define STM32_MDMA_CBNDTR_BRSUM (1U << 18) +#define STM32_MDMA_CBNDTR_BRDUM (1U << 19) +#define STM32_MDMA_CBNDTR_BRC_MASK (0xFFFU << 20) +#define STM32_MDMA_CBNDTR_BRC(n) ((n) << 20) +/** @} */ + +/** + * @name CBRUR register constants + * @{ + */ +#define STM32_MDMA_CBRUR_SUV_MASK (0xFFFFU << 0) +#define STM32_MDMA_CBRUR_SUV(n) ((n) << 0) +#define STM32_MDMA_CBRUR_DUV_MASK (0xFFFFU << 16) +#define STM32_MDMA_CBRUR_DUV(n) ((n) << 16) +/** @} */ + +/** + * @name CTBR register constants + * @{ + */ +#define STM32_MDMA_CTBR_TSEL_MASK (0x3FU << 0) +#define STM32_MDMA_CTBR_TSEL(n) ((n) << 0) +#define STM32_MDMA_CTBR_TSEL_SBUS (1U << 16) +#define STM32_MDMA_CTBR_TSEL_DBUS (1U << 17) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_MDMA_HANDLER) +#error "STM32_MDMA_HANDLER missing in registry" +#endif + +#if !defined(STM32_MDMA_NUMBER) +#error "STM32_MDMA_NUMBER missing in registry" +#endif + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_MDMA_PRIORITY) +#error "STM32_IRQ_MDMA_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_MDMA_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_MDMA_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief STM32 MDMA ISR function type. + * + * @param[in] p parameter for the registered function + * @param[in] flags content of the CISR register + */ +typedef void (*stm32_mdmaisr_t)(void *p, uint32_t flags); + +/** + * @brief STM32 MDMA stream descriptor structure. + */ +typedef struct { + /** + * @brief Associated MDMA channel. + */ + MDMA_Channel_TypeDef *channel; + /** + * @brief MDMA callback function. + */ + stm32_mdmaisr_t func; + /** + * @brief MDMA callback parameter. + */ + void *param; +} stm32_mdma_channel_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Associates a source address to a MDMA stream. + * @pre The stream must have been allocated using @p mdmaChannelAlloc(). + * @post After use the stream can be released using @p mdmaChannelFree(). + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + * @param[in] addr value to be written in the CSAR register + * + * @xclass + */ +#define mdmaChannelSetSourceX(mdmachp, addr) do { \ + (mdmachp)->channel->CSAR = (uint32_t)(addr); \ +} while (0) + +/** + * @brief Associates a memory destination to a MDMA stream. + * @pre The stream must have been allocated using @p mdmaChannelAlloc(). + * @post After use the stream can be released using @p mdmaChannelFree(). + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + * @param[in] addr value to be written in the CDAR register + * + * @xclass + */ +#define mdmaChannelSetDestinationX(mdmachp, addr) do { \ + (mdmachp)->channel->CDAR = (uint32_t)(addr); \ +} while (0) + +/** + * @brief Sets parameters related to the transaction size. + * @pre The stream must have been allocated using @p mdmaChannelAlloc(). + * @post After use the stream can be released using @p mdmaChannelFree(). + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + * @param[in] size number of bytes per block + * @param[in] n number of blocks repetitions + * @param[in] opt other option bits for the CBNDTR register + * + * @xclass + */ +#define mdmaChannelSetTransactionSizeX(mdmachp, size, n, opt) do { \ + (mdmachp)->channel->CBNDTR = (uint32_t)STM32_MDMA_CBNDTR_BNDT(size) | \ + (uint32_t)STM32_MDMA_CBNDTR_BRC(n) | \ + (uint32_t)opt; \ +} while (0) + +/** + * @brief Programs the stream mode settings. + * @pre The stream must have been allocated using @p mdmaChannelAlloc(). + * @post After use the stream can be released using @p mdmaChannelFree(). + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + * @param[in] ctcr value to be written in the CTCR register + * @param[in] ccr value to be written in the CCR register + * + * @xclass + */ +#define mdmaChannelSetModeX(mdmachp, ctcr, ccr) do { \ + (mdmachp)->channel->CTCR = (uint32_t)(ctcr); \ + (mdmachp)->channel->CCR = (uint32_t)(ccr); \ +} while (0) + +/** + * @brief MDMA stream enable. + * @pre The stream must have been allocated using @p mdmaChannelAlloc(). + * @post After use the stream can be released using @p mdmaChannelFree(). + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + * + * @xclass + */ +#define mdmaChannelEnableX(mdmachp) do { \ + (mdmachp)->channel->CCR |= STM32_MDMA_CCR_EN; \ +} while (0) + +/** + * @brief Channel enable check. + * @pre The stream must have been allocated using @p mdmaChannelAlloc(). + * @post After use the stream can be released using @p mdmaChannelFree(). + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + */ +#define mdmaChannelIsEnabled(mdmachp) \ + (((mdmachp)->channel->CCR & STM32_MDMA_CCR_EN) != 0U) + +/** + * @brief MDMA stream interrupt sources clear. + * @pre The stream must have been allocated using @p mdmaChannelAlloc(). + * @post After use the stream can be released using @p mdmaChannelFree(). + * + * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure + * + * @xclass + */ +#define mdmaChannelClearInterruptX(mdmachp) do { \ + (mdmachp)->channel->CIFCR = (STM32_MDMA_CIFCR_CTEIF | \ + STM32_MDMA_CIFCR_CBRTIF | \ + STM32_MDMA_CIFCR_CBRTIF | \ + STM32_MDMA_CIFCR_CCTCIF | \ + STM32_MDMA_CIFCR_CTEIF); \ +} while (0) + +/** + * @brief MDMA IRQ enable. + */ +#define mdma_irq_init() \ + nvicEnableVector(STM32_MDMA_NUMBER, STM32_IRQ_MDMA_PRIORITY) + +/** + * @brief MDMA IRQ disable. + */ +#define mdma_irq_deinit() \ + nvicDisableVector(STM32_MDMA_NUMBER) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void mdmaInit(void); + const stm32_mdma_channel_t *mdmaChannelAllocI(uint32_t id, + stm32_mdmaisr_t func, + void *param); + const stm32_mdma_channel_t *mdmaChannelAlloc(uint32_t id, + stm32_mdmaisr_t func, + void *param); + void mdmaChannelFreeI(const stm32_mdma_channel_t *mdmachp); + void mdmaChannelFree(const stm32_mdma_channel_t *mdmachp); + void mdmaChannelDisableX(const stm32_mdma_channel_t *mdmachp); +#ifdef __cplusplus +} +#endif + +#endif /* STM32_MDMA_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/driver.mk new file mode 100644 index 0000000..987220b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_WSPI TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OCTOSPIv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c new file mode 100644 index 0000000..c71e38a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c @@ -0,0 +1,464 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file OCTOSPIv1/hal_wspi_lld.c + * @brief STM32 WSPI subsystem low level driver source. + * + * @addtogroup WSPI + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* Workarounds for bugs in ST headers.*/ +#if !defined(OCTOSPI_FCR_CTOF) && defined(OCTOSPI_FCR_TOF) +#define OCTOSPI_FCR_CTOF OCTOSPI_FCR_TOF +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief OCTOSPI1 driver identifier.*/ +#if STM32_WSPI_USE_OCTOSPI1 || defined(__DOXYGEN__) +WSPIDriver WSPID1; +#endif + +/** @brief OCTOSPI2 driver identifier.*/ +#if STM32_WSPI_USE_OCTOSPI2 || defined(__DOXYGEN__) +WSPIDriver WSPID2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Waits for completion of previous operation. + */ +static inline void wspi_lld_sync(WSPIDriver *wspip) { + + while ((wspip->ospi->SR & OCTOSPI_SR_BUSY) != 0U) { + } +} + +/** + * @brief Shared service routine. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void wspi_lld_serve_dma_interrupt(WSPIDriver *wspip, uint32_t flags) { + + (void)wspip; + (void)flags; + + /* DMA errors handling.*/ +#if defined(STM32_WSPI_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_WSPI_DMA_ERROR_HOOK(wspip); + } +#endif +} + +/** + * @brief Shared service routine. + * + * @param[in] wspip pointer to the @p WSPIDriver object + */ +static void wspi_lld_serve_interrupt(WSPIDriver *wspip) { + + /* Portable WSPI ISR code defined in the high level driver, note, it is + a macro.*/ + _wspi_isr_code(wspip); + + /* Stop everything, we need to give DMA enough time to complete the ongoing + operation. Race condition hidden here.*/ + while (dmaStreamGetTransactionSize(wspip->dma) > 0U) + ; + dmaStreamDisable(wspip->dma); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_WSPI_USE_OCTOSPI1 || defined(__DOXYGEN__) +#if !defined(STM32_OCTOSPI1_SUPPRESS_ISR) +#if !defined(STM32_OCTOSPI1_HANDLER) +#error "STM32_OCTOSPI1_HANDLER not defined" +#endif +/** + * @brief STM32_OCTOSPI1_HANDLER interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_OCTOSPI1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + OCTOSPI1->FCR = OCTOSPI_FCR_CTEF | OCTOSPI_FCR_CTCF | + OCTOSPI_FCR_CSMF | OCTOSPI_FCR_CTOF; + + wspi_lld_serve_interrupt(&WSPID1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_OCTOSPI1_SUPPRESS_ISR) */ +#endif /* STM32_WSPI_USE_OCTOSPI1 */ + +#if STM32_WSPI_USE_OCTOSPI2 || defined(__DOXYGEN__) +#if !defined(STM32_OCTOSPI2_SUPPRESS_ISR) +#if !defined(STM32_OCTOSPI2_HANDLER) +#error "STM32_OCTOSPI2_HANDLER not defined" +#endif +/** + * @brief STM32_OCTOSPI2_HANDLER interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_OCTOSPI2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + OCTOSPI2->FCR = OCTOSPI_FCR_CTEF | OCTOSPI_FCR_CTCF | + OCTOSPI_FCR_CSMF | OCTOSPI_FCR_CTOF; + + wspi_lld_serve_interrupt(&WSPID2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_OCTOSPI2_SUPPRESS_ISR) */ +#endif /* STM32_WSPI_USE_OCTOSPI2 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level WSPI driver initialization. + * + * @notapi + */ +void wspi_lld_init(void) { + +#if STM32_WSPI_USE_OCTOSPI1 + wspiObjectInit(&WSPID1); + WSPID1.ospi = OCTOSPI1; + WSPID1.dma = NULL; + WSPID1.dmamode = STM32_DMA_CR_CHSEL(OCTOSPI1_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_WSPI_OCTOSPI1_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_BYTE | + STM32_DMA_CR_MSIZE_BYTE | + STM32_DMA_CR_MINC | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + nvicEnableVector(STM32_OCTOSPI1_NUMBER, STM32_WSPI_OCTOSPI1_IRQ_PRIORITY); +#endif + +#if STM32_WSPI_USE_OCTOSPI2 + wspiObjectInit(&WSPID2); + WSPID2.ospi = OCTOSPI2; + WSPID2.dma = NULL; + WSPID2.dmamode = STM32_DMA_CR_CHSEL(OCTOSPI2_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_WSPI_OCTOSPI2_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_BYTE | + STM32_DMA_CR_MSIZE_BYTE | + STM32_DMA_CR_MINC | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + nvicEnableVector(STM32_OCTOSPI2_NUMBER, STM32_WSPI_OCTOSPI2_IRQ_PRIORITY); +#endif +} + +/** + * @brief Configures and activates the WSPI peripheral. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @notapi + */ +void wspi_lld_start(WSPIDriver *wspip) { + + /* If in stopped state then full initialization.*/ + if (wspip->state == WSPI_STOP) { +#if STM32_WSPI_USE_OCTOSPI1 + if (&WSPID1 == wspip) { + wspip->dma = dmaStreamAllocI(STM32_WSPI_OCTOSPI1_DMA_STREAM, + STM32_WSPI_OCTOSPI1_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)wspi_lld_serve_dma_interrupt, + (void *)wspip); + osalDbgAssert(wspip->dma != NULL, "unable to allocate stream"); + rccEnableOCTOSPI1(true); + dmaSetRequestSource(wspip->dma, STM32_DMAMUX1_OCTOSPI1); + } +#endif + +#if STM32_WSPI_USE_OCTOSPI2 + if (&WSPID2 == wspip) { + wspip->dma = dmaStreamAllocI(STM32_WSPI_OCTOSPI2_DMA_STREAM, + STM32_WSPI_OCTOSPI2_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)wspi_lld_serve_dma_interrupt, + (void *)wspip); + osalDbgAssert(wspip->dma != NULL, "unable to allocate stream"); + rccEnableOCTOSPI2(true); + dmaSetRequestSource(wspip->dma, STM32_DMAMUX1_OCTOSPI2); + } +#endif + + /* Common initializations.*/ + dmaStreamSetPeripheral(wspip->dma, &wspip->ospi->DR); + } + + /* WSPI setup and enable.*/ + wspip->ospi->DCR1 = wspip->config->dcr1; + wspip->ospi->DCR2 = wspip->config->dcr2 | + STM32_DCR2_PRESCALER(STM32_WSPI_OCTOSPI1_PRESCALER_VALUE - 1U); + wspip->ospi->DCR3 = wspip->config->dcr3; + wspip->ospi->CR = OCTOSPI_CR_TCIE | OCTOSPI_CR_DMAEN | OCTOSPI_CR_EN; + wspip->ospi->FCR = OCTOSPI_FCR_CTEF | OCTOSPI_FCR_CTCF | + OCTOSPI_FCR_CSMF | OCTOSPI_FCR_CTOF; +} + +/** + * @brief Deactivates the WSPI peripheral. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @notapi + */ +void wspi_lld_stop(WSPIDriver *wspip) { + + /* Waiting for the previous operation to complete, if any.*/ + wspi_lld_sync(wspip); + + /* If in ready state then disables the OCTOSPI clock.*/ + if (wspip->state == WSPI_READY) { + + /* WSPI disable.*/ + wspip->ospi->CR = 0U; + + /* Releasing the DMA.*/ + dmaStreamFreeI(wspip->dma); + wspip->dma = NULL; + + /* Stopping involved clocks.*/ +#if STM32_WSPI_USE_OCTOSPI1 + if (&WSPID1 == wspip) { + rccDisableOCTOSPI1(); + } +#endif + } +} + +/** + * @brief Sends a command without data phase. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * + * @notapi + */ +void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp) { + +#if 0 //STM32_USE_STM32_D1_WORKAROUND == TRUE + /* If it is a command without address and alternate phases then the command + is sent as an alternate byte, the command phase is suppressed.*/ + if ((cmdp->cfg & (WSPI_CFG_ADDR_MODE_MASK | WSPI_CFG_ALT_MODE_MASK)) == 0U) { + /* The command mode field is copied in the alternate mode field. All + other fields are not used in this scenario.*/ + wspip->ospi->DLR = 0U; + wspip->ospi->ABR = cmdp->cmd; + wspip->ospi->CCR = (cmdp->cfg & WSPI_CFG_CMD_MODE_MASK) << 6U; + return; + } +#endif + wspip->ospi->CR &= ~OCTOSPI_CR_FMODE; + wspip->ospi->DLR = 0U; + wspip->ospi->TCR = cmdp->dummy; + wspip->ospi->CCR = cmdp->cfg; + wspip->ospi->ABR = cmdp->alt; + wspip->ospi->IR = cmdp->cmd; + if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) { + wspip->ospi->AR = cmdp->addr; + } + + /* Waiting for the previous operation to complete.*/ + wspi_lld_sync(wspip); +} + +/** + * @brief Sends a command with data over the WSPI bus. + * @post At the end of the operation the configured callback is invoked. + * @note If using DTR in 8 lines mode then the following restrictions + * apply: + * - Command size must be 0, 2 or 4 bytes. + * - Address must be even. + * - Alternate bytes size must be 0, 2 or 4 bytes. + * - Data size must be a multiple of two. + * . + * There is no check on the above conditions in order to keep the + * code efficient. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, const uint8_t *txbuf) { + + dmaStreamSetMemory0(wspip->dma, txbuf); + dmaStreamSetTransactionSize(wspip->dma, n); + dmaStreamSetMode(wspip->dma, wspip->dmamode | STM32_DMA_CR_DIR_M2P); + + wspip->ospi->CR &= ~OCTOSPI_CR_FMODE; + wspip->ospi->DLR = n - 1U; + wspip->ospi->TCR = cmdp->dummy; + wspip->ospi->CCR = cmdp->cfg; + wspip->ospi->ABR = cmdp->alt; + wspip->ospi->IR = cmdp->cmd; + if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) { + wspip->ospi->AR = cmdp->addr; + } + + dmaStreamEnable(wspip->dma); +} + +/** + * @brief Sends a command then receives data over the WSPI bus. + * @post At the end of the operation the configured callback is invoked. + * @note If using DTR in 8 lines mode then the following restrictions + * apply: + * - Command size must be 0, 2 or 4 bytes. + * - Address must be even. + * - Alternate bytes size must be 0, 2 or 4 bytes. + * - Data size must be a multiple of two. + * . + * There is no check on the above conditions in order to keep the + * code efficient. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, uint8_t *rxbuf) { + + dmaStreamSetMemory0(wspip->dma, rxbuf); + dmaStreamSetTransactionSize(wspip->dma, n); + dmaStreamSetMode(wspip->dma, wspip->dmamode | STM32_DMA_CR_DIR_P2M); + + wspip->ospi->CR = (wspip->ospi->CR & ~OCTOSPI_CR_FMODE) | OCTOSPI_CR_FMODE_0; + wspip->ospi->DLR = n - 1U; + wspip->ospi->TCR = cmdp->dummy; + wspip->ospi->CCR = cmdp->cfg; + wspip->ospi->ABR = cmdp->alt; + wspip->ospi->IR = cmdp->cmd; + if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) { + wspip->ospi->AR = cmdp->addr; + } + + dmaStreamEnable(wspip->dma); +} + +#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) +/** + * @brief Maps in memory space a WSPI flash device. + * @pre The memory flash device must be initialized appropriately + * before mapping it in memory space. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[out] addrp pointer to the memory start address of the mapped + * flash or @p NULL + * + * @notapi + */ +void wspi_lld_map_flash(WSPIDriver *wspip, + const wspi_command_t *cmdp, + uint8_t **addrp) { + + /* Starting memory mapped mode using the passed parameters.*/ + wspip->ospi->CR = OCTOSPI_CR_FMODE_1 | OCTOSPI_CR_FMODE_0 | OCTOSPI_CR_EN; + wspip->ospi->TCR = cmdp->dummy; + wspip->ospi->CCR = cmdp->cfg; + wspip->ospi->IR = cmdp->cmd; + wspip->ospi->ABR = 0U; + wspip->ospi->AR = 0U; + wspip->ospi->WTCR = 0U; + wspip->ospi->WCCR = 0U; + wspip->ospi->WIR = 0U; + wspip->ospi->WABR = 0U; + + /* Mapped flash absolute base address.*/ +#if STM32_WSPI_USE_OCTOSPI1 + if (&WSPID1 == wspip) { + if (addrp != NULL) { + *addrp = (uint8_t *)0x90000000U; + } + } +#endif +#if STM32_WSPI_USE_OCTOSPI2 + if (&WSPID2 == wspip) { + if (addrp != NULL) { + *addrp = (uint8_t *)0x70000000U; + } + } +#endif +} + +/** + * @brief Unmaps from memory space a WSPI flash device. + * @post The memory flash device must be re-initialized for normal + * commands exchange. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @notapi + */ +void wspi_lld_unmap_flash(WSPIDriver *wspip) { + + /* Aborting memory mapped mode.*/ + wspip->ospi->CR |= OCTOSPI_CR_ABORT; + while ((wspip->ospi->CR & OCTOSPI_CR_ABORT) != 0U) { + } + + /* Disabling memory mapped mode and re-enabling DMA and IRQs.*/ + wspip->ospi->CR = OCTOSPI_CR_TCIE | OCTOSPI_CR_DMAEN | OCTOSPI_CR_EN; +} +#endif /* WSPI_SUPPORTS_MEMMAP == TRUE */ + +#endif /* HAL_USE_WSPI */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.h new file mode 100644 index 0000000..35e5d80 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.h @@ -0,0 +1,334 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file OCTOSPIv1/hal_wspi_lld.h + * @brief STM32 WSPI subsystem low level driver header. + * + * @addtogroup WSPI + * @{ + */ + +#ifndef HAL_WSPI_LLD_H +#define HAL_WSPI_LLD_H + +#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name WSPI implementation capabilities + * @{ + */ +#define WSPI_SUPPORTS_MEMMAP TRUE +#define WSPI_DEFAULT_CFG_MASKS TRUE +/** @} */ + +/** + * @name DCR1 register options + * @{ + */ +#define STM32_DCR1_CK_MODE (1U << 0U) +#define STM32_DCR1_FRCK_MODE (1U << 1U) +#define STM32_DCR1_CSHT_MASK (7U << 8U) +#define STM32_DCR1_CSHT(n) ((n) << 8U) +#define STM32_DCR1_DEVSIZE_MASK (31U << 16U) +#define STM32_DCR1_DEVSIZE(n) ((n) << 16U) +#define STM32_DCR1_MTYP_MASK (7U << 16U) +#define STM32_DCR1_MTYP(n) ((n) << 24U) +/** @} */ + +/** + * @name DCR2 register options + * @{ + */ +#define STM32_DCR2_PRESCALER_MASK (255U << 0U) +#define STM32_DCR2_PRESCALER(n) ((n) << 0U) +#define STM32_DCR2_WRAPSIZE_MASK (7U << 16U) +#define STM32_DCR2_WRAPSIZE(n) ((n) << 16U) + +/** + * @name DCR3 register options + * @{ + */ +#define STM32_DCR3_MAXTRAN_MASK (255U << 0U) +#define STM32_DCR3_MAXTRAN(n) ((n) << 0U) +#define STM32_DCR3_CSBOUND_MASK (7U << 16U) +#define STM32_DCR3_CSBOUND(n) ((n) << 16U) + +/** + * @name DCR4 register options + * @{ + */ +#define STM32_DCR4_REFRESH_MASK (255U << 0U) +#define STM32_DCR4_REFRESH(n) ((n) << 0U) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief WSPID1 driver enable switch. + * @details If set to @p TRUE the support for OCTOSPI1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_WSPI_USE_OCTOSPI1) || defined(__DOXYGEN__) +#define STM32_WSPI_USE_OCTOSPI1 FALSE +#endif + +/** + * @brief WSPID2 driver enable switch. + * @details If set to @p TRUE the support for OCTOSPI2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_WSPI_USE_OCTOSPI2) || defined(__DOXYGEN__) +#define STM32_WSPI_USE_OCTOSPI2 FALSE +#endif + +/** + * @brief OCTOSPI1 prescaler setting. + * @note This is the prescaler divider value 1..256. The maximum frequency + * varies depending on the STM32 model and operating conditions, + * find the details in the data sheet. + */ +#if !defined(STM32_WSPI_OCTOSPI1_PRESCALER_VALUE) || defined(__DOXYGEN__) +#define STM32_WSPI_OCTOSPI1_PRESCALER_VALUE 1 +#endif + +/** + * @brief OCTOSPI2 prescaler setting. + * @note This is the prescaler divider value 1..256. The maximum frequency + * varies depending on the STM32 model and operating conditions, + * find the details in the data sheet. + */ +#if !defined(STM32_WSPI_OCTOSPI2_PRESCALER_VALUE) || defined(__DOXYGEN__) +#define STM32_WSPI_OCTOSPI2_PRESCALER_VALUE 1 +#endif + +/** + * @brief OCTOSPI1 interrupt priority level setting. + */ +#if !defined(STM32_WSPI_OCTOSPI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_OCTOSPI1_IRQ_PRIORITY 10 +#endif + +/** + * @brief OCTOSPI2 interrupt priority level setting. + */ +#if !defined(STM32_WSPI_OCTOSPI2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_OCTOSPI2_IRQ_PRIORITY 10 +#endif + +/** + * @brief OCTOSPI1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_WSPI_OCTOSPI1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_OCTOSPI1_DMA_PRIORITY 1 +#endif + +/** + * @brief OCTOSPI2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_WSPI_OCTOSPI2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_OCTOSPI2_DMA_PRIORITY 1 +#endif + +/** + * @brief OCTOSPI1 DMA interrupt priority level setting. + */ +#if !defined(STM32_WSPI_OCTOSPI1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_OCTOSPI1_DMA_IRQ_PRIORITY 10 +#endif + +/** + * @brief OCTOSPI2 DMA interrupt priority level setting. + */ +#if !defined(STM32_WSPI_OCTOSPI2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_OCTOSPI2_DMA_IRQ_PRIORITY 10 +#endif + +/** + * @brief OCTOSPI DMA error hook. + */ +#if !defined(STM32_WSPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_WSPI_DMA_ERROR_HOOK(qspip) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_OCTOSPI1) +#define STM32_HAS_OCTOSPI1 FALSE +#endif + +#if !defined(STM32_HAS_OCTOSPI2) +#define STM32_HAS_OCTOSPI2 FALSE +#endif + +#if STM32_WSPI_USE_OCTOSPI1 && !STM32_HAS_OCTOSPI1 +#error "OCTOSPI1 not present in the selected device" +#endif + +#if STM32_WSPI_USE_OCTOSPI2 && !STM32_HAS_OCTOSPI2 +#error "OCTOSPI2 not present in the selected device" +#endif + +#if !STM32_WSPI_USE_OCTOSPI1 && !STM32_WSPI_USE_OCTOSPI2 +#error "WSPI driver activated but no OCTOSPI peripheral assigned" +#endif + +/* Check on OCTOSPI prescaler setting.*/ +#if (STM32_WSPI_OCTOSPI1_PRESCALER_VALUE < 1) || \ + (STM32_WSPI_OCTOSPI1_PRESCALER_VALUE > 256) +#error "STM32_WSPI_OCTOSPI1_PRESCALER_VALUE not within 1..256" +#endif + +/* Check on IRQ priorities.*/ +#if STM32_WSPI_USE_OCTOSPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to OCTOSPI1" +#endif + +#if STM32_WSPI_USE_OCTOSPI2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to OCTOSPI2" +#endif + +#if STM32_WSPI_USE_OCTOSPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI1_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to OCTOSPI1 DMA" +#endif + +#if STM32_WSPI_USE_OCTOSPI2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI2_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to OCTOSPI2 DMA" +#endif + +/* Check on the presence of the DMA channels settings in mcuconf.h.*/ +#if STM32_WSPI_USE_OCTOSPI1 && !defined(STM32_WSPI_OCTOSPI1_DMA_STREAM) +#error "OCTOSPI1 DMA stream not defined" +#endif + +#if STM32_WSPI_USE_OCTOSPI2 && !defined(STM32_WSPI_OCTOSPI2_DMA_STREAM) +#error "OCTOSPI2 DMA stream not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_WSPI_USE_OCTOSPI1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_WSPI_OCTOSPI1_DMA_STREAM) +#error "invalid DMA stream associated to OCTOSPI1" +#endif + +#if STM32_WSPI_USE_OCTOSPI2 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_WSPI_OCTOSPI2_DMA_STREAM) +#error "invalid DMA stream associated to OCTOSPI2" +#endif + +/* Check on DMA channels priority.*/ +#if STM32_WSPI_USE_OCTOSPI1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to OCTOSPI1" +#endif + +#if STM32_WSPI_USE_OCTOSPI2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to OCTOSPI2" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the WSPI configuration structure. + */ +#define wspi_lld_config_fields \ + /* DCR1 register initialization data.*/ \ + uint32_t dcr1; \ + /* DCR2 register initialization data. The prescaler field is internally \ + ORed to this field, leave it to zero.*/ \ + uint32_t dcr2; \ + /* DCR3 register initialization data.*/ \ + uint32_t dcr3; \ + /* DCR4 register initialization data.*/ \ + uint32_t dcr4 + +/** + * @brief Low level fields of the WSPI driver structure. + */ +#define wspi_lld_driver_fields \ + /* Pointer to the OCTOSPIx registers block.*/ \ + OCTOSPI_TypeDef *ospi; \ + /* OCTOSPI DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + /* OCTOSPI DMA mode bit mask.*/ \ + uint32_t dmamode + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (STM32_WSPI_USE_OCTOSPI1 == TRUE) && !defined(__DOXYGEN__) +extern WSPIDriver WSPID1; +#endif + +#if (STM32_WSPI_USE_OCTOSPI2 == TRUE) && !defined(__DOXYGEN__) +extern WSPIDriver WSPID2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void wspi_lld_init(void); + void wspi_lld_start(WSPIDriver *wspip); + void wspi_lld_stop(WSPIDriver *wspip); + void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp); + void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, const uint8_t *txbuf); + void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, uint8_t *rxbuf); +#if WSPI_SUPPORTS_MEMMAP == TRUE + void wspi_lld_map_flash(WSPIDriver *wspip, + const wspi_command_t *cmdp, + uint8_t **addrp); + void wspi_lld_unmap_flash(WSPIDriver *wspip); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_WSPI */ + +#endif /* HAL_WSPI_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/driver.mk new file mode 100644 index 0000000..197c1d2 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_USB TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c new file mode 100644 index 0000000..0f48d1f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c @@ -0,0 +1,1265 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file OTGv1/hal_usb_lld.c + * @brief STM32 USB subsystem low level driver source. + * + * @addtogroup USB + * @{ + */ + +#include + +#include "hal.h" + +#if HAL_USE_USB || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define TRDT_VALUE_FS 5 +#define TRDT_VALUE_HS 9 + +#define EP0_MAX_INSIZE 64 +#define EP0_MAX_OUTSIZE 64 + +#if STM32_OTG_STEPPING == 1 +#if defined(BOARD_OTG_NOVBUSSENS) +#define GCCFG_INIT_VALUE (GCCFG_NOVBUSSENS | GCCFG_VBUSASEN | \ + GCCFG_VBUSBSEN | GCCFG_PWRDWN) +#else +#define GCCFG_INIT_VALUE (GCCFG_VBUSASEN | GCCFG_VBUSBSEN | \ + GCCFG_PWRDWN) +#endif + +#elif STM32_OTG_STEPPING == 2 +#if defined(BOARD_OTG_NOVBUSSENS) +#define GCCFG_INIT_VALUE GCCFG_PWRDWN +#else +#define GCCFG_INIT_VALUE (GCCFG_VBDEN | GCCFG_PWRDWN) +#endif + +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief OTG_FS driver identifier.*/ +#if STM32_USB_USE_OTG1 || defined(__DOXYGEN__) +USBDriver USBD1; +#endif + +/** @brief OTG_HS driver identifier.*/ +#if STM32_USB_USE_OTG2 || defined(__DOXYGEN__) +USBDriver USBD2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief EP0 state. + * @note It is an union because IN and OUT endpoints are never used at the + * same time for EP0. + */ +static union { + /** + * @brief IN EP0 state. + */ + USBInEndpointState in; + /** + * @brief OUT EP0 state. + */ + USBOutEndpointState out; +} ep0_state; + +/** + * @brief Buffer for the EP0 setup packets. + */ +static uint8_t ep0setup_buffer[8]; + +/** + * @brief EP0 initialization structure. + */ +static const USBEndpointConfig ep0config = { + USB_EP_MODE_TYPE_CTRL, + _usb_ep0setup, + _usb_ep0in, + _usb_ep0out, + 0x40, + 0x40, + &ep0_state.in, + &ep0_state.out, + 1, + ep0setup_buffer +}; + +#if STM32_USB_USE_OTG1 +static const stm32_otg_params_t fsparams = { + STM32_USB_OTG1_RX_FIFO_SIZE / 4, + STM32_OTG1_FIFO_MEM_SIZE, + STM32_OTG1_ENDPOINTS +}; +#endif + +#if STM32_USB_USE_OTG2 +static const stm32_otg_params_t hsparams = { + STM32_USB_OTG2_RX_FIFO_SIZE / 4, + STM32_OTG2_FIFO_MEM_SIZE, + STM32_OTG2_ENDPOINTS +}; +#endif + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static void otg_core_reset(USBDriver *usbp) { + stm32_otg_t *otgp = usbp->otg; + + /* Wait AHB idle condition.*/ + while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0) + ; + + /* Core reset and delay of at least 3 PHY cycles.*/ + otgp->GRSTCTL = GRSTCTL_CSRST; + osalSysPolledDelayX(12); + while ((otgp->GRSTCTL & GRSTCTL_CSRST) != 0) + ; + + osalSysPolledDelayX(18); + + /* Wait AHB idle condition again.*/ + while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0) + ; +} + +static void otg_disable_ep(USBDriver *usbp) { + stm32_otg_t *otgp = usbp->otg; + unsigned i; + + for (i = 0; i <= usbp->otgparams->num_endpoints; i++) { + + if ((otgp->ie[i].DIEPCTL & DIEPCTL_EPENA) != 0U) { + otgp->ie[i].DIEPCTL |= DIEPCTL_EPDIS; + } + + if ((otgp->oe[i].DOEPCTL & DIEPCTL_EPENA) != 0U) { + otgp->oe[i].DOEPCTL |= DIEPCTL_EPDIS; + } + + otgp->ie[i].DIEPINT = 0xFFFFFFFF; + otgp->oe[i].DOEPINT = 0xFFFFFFFF; + } + otgp->DAINTMSK = DAINTMSK_OEPM(0) | DAINTMSK_IEPM(0); +} + +static void otg_rxfifo_flush(USBDriver *usbp) { + stm32_otg_t *otgp = usbp->otg; + + otgp->GRSTCTL = GRSTCTL_RXFFLSH; + while ((otgp->GRSTCTL & GRSTCTL_RXFFLSH) != 0) + ; + /* Wait for 3 PHY Clocks.*/ + osalSysPolledDelayX(18); +} + +static void otg_txfifo_flush(USBDriver *usbp, uint32_t fifo) { + stm32_otg_t *otgp = usbp->otg; + + otgp->GRSTCTL = GRSTCTL_TXFNUM(fifo) | GRSTCTL_TXFFLSH; + while ((otgp->GRSTCTL & GRSTCTL_TXFFLSH) != 0) + ; + /* Wait for 3 PHY Clocks.*/ + osalSysPolledDelayX(18); +} + +/** + * @brief Resets the FIFO RAM memory allocator. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +static void otg_ram_reset(USBDriver *usbp) { + + usbp->pmnext = usbp->otgparams->rx_fifo_size; +} + +/** + * @brief Allocates a block from the FIFO RAM memory. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] size size of the packet buffer to allocate in words + * + * @notapi + */ +static uint32_t otg_ram_alloc(USBDriver *usbp, size_t size) { + uint32_t next; + + next = usbp->pmnext; + usbp->pmnext += size; + osalDbgAssert(usbp->pmnext <= usbp->otgparams->otg_ram_size, + "OTG FIFO memory overflow"); + return next; +} + +/** + * @brief Writes to a TX FIFO. + * + * @param[in] fifop pointer to the FIFO register + * @param[in] buf buffer where to copy the endpoint data + * @param[in] n maximum number of bytes to copy + * + * @notapi + */ +static void otg_fifo_write_from_buffer(volatile uint32_t *fifop, + const uint8_t *buf, + size_t n) { + + osalDbgAssert(n > 0, "is zero"); + + while (true) { + *fifop = *((uint32_t *)buf); + if (n <= 4) { + break; + } + n -= 4; + buf += 4; + } +} + +/** + * @brief Reads a packet from the RXFIFO. + * + * @param[in] fifop pointer to the FIFO register + * @param[out] buf buffer where to copy the endpoint data + * @param[in] n number of bytes to pull from the FIFO + * @param[in] max number of bytes to copy into the buffer + * + * @notapi + */ +static void otg_fifo_read_to_buffer(volatile uint32_t *fifop, + uint8_t *buf, + size_t n, + size_t max) { + uint32_t w = 0; + size_t i = 0; + + while (i < n) { + if ((i & 3) == 0) { + w = *fifop; + } + if (i < max) { + *buf++ = (uint8_t)w; + w >>= 8; + } + i++; + } +} + +/** + * @brief Incoming packets handler. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +static void otg_rxfifo_handler(USBDriver *usbp) { + uint32_t sts, cnt, ep; + + /* Popping the event word out of the RX FIFO.*/ + sts = usbp->otg->GRXSTSP; + + /* Event details.*/ + cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF; + ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF; + + switch (sts & GRXSTSP_PKTSTS_MASK) { + case GRXSTSP_SETUP_DATA: + otg_fifo_read_to_buffer(usbp->otg->FIFO[0], usbp->epc[ep]->setup_buf, + cnt, 8); + break; + case GRXSTSP_SETUP_COMP: + break; + case GRXSTSP_OUT_DATA: + otg_fifo_read_to_buffer(usbp->otg->FIFO[0], + usbp->epc[ep]->out_state->rxbuf, + cnt, + usbp->epc[ep]->out_state->rxsize - + usbp->epc[ep]->out_state->rxcnt); + usbp->epc[ep]->out_state->rxbuf += cnt; + usbp->epc[ep]->out_state->rxcnt += cnt; + break; + case GRXSTSP_OUT_COMP: + break; + case GRXSTSP_OUT_GLOBAL_NAK: + break; + default: + break; + } +} + +/** + * @brief Outgoing packets handler. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +static bool otg_txfifo_handler(USBDriver *usbp, usbep_t ep) { + + /* The TXFIFO is filled until there is space and data to be transmitted.*/ + while (true) { + uint32_t n; + + /* Transaction end condition.*/ + if (usbp->epc[ep]->in_state->txcnt >= usbp->epc[ep]->in_state->txsize) { +#if 1 + usbp->otg->DIEPEMPMSK &= ~DIEPEMPMSK_INEPTXFEM(ep); +#endif + return true; + } + + /* Number of bytes remaining in current transaction.*/ + n = usbp->epc[ep]->in_state->txsize - usbp->epc[ep]->in_state->txcnt; + if (n > usbp->epc[ep]->in_maxsize) + n = usbp->epc[ep]->in_maxsize; + + /* Checks if in the TXFIFO there is enough space to accommodate the + next packet.*/ + if (((usbp->otg->ie[ep].DTXFSTS & DTXFSTS_INEPTFSAV_MASK) * 4) < n) + return false; + +#if STM32_USB_OTGFIFO_FILL_BASEPRI + __set_BASEPRI(CORTEX_PRIO_MASK(STM32_USB_OTGFIFO_FILL_BASEPRI)); +#endif + otg_fifo_write_from_buffer(usbp->otg->FIFO[ep], + usbp->epc[ep]->in_state->txbuf, + n); + usbp->epc[ep]->in_state->txbuf += n; + usbp->epc[ep]->in_state->txcnt += n; +#if STM32_USB_OTGFIFO_FILL_BASEPRI + __set_BASEPRI(0); +#endif + } +} + +/** + * @brief Generic endpoint IN handler. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +static void otg_epin_handler(USBDriver *usbp, usbep_t ep) { + stm32_otg_t *otgp = usbp->otg; + uint32_t epint = otgp->ie[ep].DIEPINT; + + otgp->ie[ep].DIEPINT = epint; + + if (epint & DIEPINT_TOC) { + /* Timeouts not handled yet, not sure how to handle.*/ + } + if ((epint & DIEPINT_XFRC) && (otgp->DIEPMSK & DIEPMSK_XFRCM)) { + /* Transmit transfer complete.*/ + USBInEndpointState *isp = usbp->epc[ep]->in_state; + + if (isp->txsize < isp->totsize) { + /* In case the transaction covered only part of the total transfer + then another transaction is immediately started in order to + cover the remaining.*/ + isp->txsize = isp->totsize - isp->txsize; + isp->txcnt = 0; + osalSysLockFromISR(); + usb_lld_start_in(usbp, ep); + osalSysUnlockFromISR(); + } + else { + /* End on IN transfer.*/ + _usb_isr_invoke_in_cb(usbp, ep); + } + } + if ((epint & DIEPINT_TXFE) && + (otgp->DIEPEMPMSK & DIEPEMPMSK_INEPTXFEM(ep))) { + /* TX FIFO empty or emptying.*/ + otg_txfifo_handler(usbp, ep); + } +} + +/** + * @brief Generic endpoint OUT handler. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +static void otg_epout_handler(USBDriver *usbp, usbep_t ep) { + stm32_otg_t *otgp = usbp->otg; + uint32_t epint = otgp->oe[ep].DOEPINT; + + /* Resets all EP IRQ sources.*/ + otgp->oe[ep].DOEPINT = epint; + + if ((epint & DOEPINT_STUP) && (otgp->DOEPMSK & DOEPMSK_STUPM)) { + /* Setup packets handling, setup packets are handled using a + specific callback.*/ + _usb_isr_invoke_setup_cb(usbp, ep); + } + + if ((epint & DOEPINT_XFRC) && (otgp->DOEPMSK & DOEPMSK_XFRCM)) { + USBOutEndpointState *osp; + + /* OUT state structure pointer for this endpoint.*/ + osp = usbp->epc[ep]->out_state; + + /* EP0 requires special handling.*/ + if (ep == 0) { + +#if defined(STM32_OTG_SEQUENCE_WORKAROUND) + /* If an OUT transaction end interrupt is processed while the state + machine is not in an OUT state then it is ignored, this is caused + on some devices (L4) apparently injecting spurious data complete + words in the RX FIFO.*/ + if ((usbp->ep0state & USB_OUT_STATE) == 0) + return; +#endif + + /* In case the transaction covered only part of the total transfer + then another transaction is immediately started in order to + cover the remaining.*/ + if (((osp->rxcnt % usbp->epc[ep]->out_maxsize) == 0) && + (osp->rxsize < osp->totsize)) { + osp->rxsize = osp->totsize - osp->rxsize; + osp->rxcnt = 0; + osalSysLockFromISR(); + usb_lld_start_out(usbp, ep); + osalSysUnlockFromISR(); + return; + } + } + + /* End on OUT transfer.*/ + _usb_isr_invoke_out_cb(usbp, ep); + } +} + +/** + * @brief Isochronous IN transfer failed handler. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +static void otg_isoc_in_failed_handler(USBDriver *usbp) { + usbep_t ep; + stm32_otg_t *otgp = usbp->otg; + + for (ep = 0; ep <= usbp->otgparams->num_endpoints; ep++) { + if (((otgp->ie[ep].DIEPCTL & DIEPCTL_EPTYP_MASK) == DIEPCTL_EPTYP_ISO) && + ((otgp->ie[ep].DIEPCTL & DIEPCTL_EPENA) != 0)) { + /* Endpoint enabled -> ISOC IN transfer failed */ + /* Disable endpoint */ + otgp->ie[ep].DIEPCTL |= (DIEPCTL_EPDIS | DIEPCTL_SNAK); + while (otgp->ie[ep].DIEPCTL & DIEPCTL_EPENA) + ; + + /* Flush FIFO */ + otg_txfifo_flush(usbp, ep); + + /* Prepare data for next frame */ + _usb_isr_invoke_in_cb(usbp, ep); + + /* TX FIFO empty or emptying.*/ + otg_txfifo_handler(usbp, ep); + } + } +} + +/** + * @brief Isochronous OUT transfer failed handler. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +static void otg_isoc_out_failed_handler(USBDriver *usbp) { + usbep_t ep; + stm32_otg_t *otgp = usbp->otg; + + for (ep = 0; ep <= usbp->otgparams->num_endpoints; ep++) { + if (((otgp->oe[ep].DOEPCTL & DOEPCTL_EPTYP_MASK) == DOEPCTL_EPTYP_ISO) && + ((otgp->oe[ep].DOEPCTL & DOEPCTL_EPENA) != 0)) { + /* Endpoint enabled -> ISOC OUT transfer failed */ + /* Disable endpoint */ + /* CHTODO:: Core stucks here */ + /*otgp->oe[ep].DOEPCTL |= (DOEPCTL_EPDIS | DOEPCTL_SNAK); + while (otgp->oe[ep].DOEPCTL & DOEPCTL_EPENA) + ;*/ + /* Prepare transfer for next frame.*/ + _usb_isr_invoke_out_cb(usbp, ep); + } + } +} + +/** + * @brief OTG shared ISR. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +static void usb_lld_serve_interrupt(USBDriver *usbp) { + stm32_otg_t *otgp = usbp->otg; + uint32_t sts, src; + + sts = otgp->GINTSTS; + sts &= otgp->GINTMSK; + otgp->GINTSTS = sts; + + /* Reset interrupt handling.*/ + if (sts & GINTSTS_USBRST) { + /* Default reset action.*/ + _usb_reset(usbp); + + /* Preventing execution of more handlers, the core has been reset.*/ + return; + } + + /* Wake-up handling.*/ + if (sts & GINTSTS_WKUPINT) { + /* If clocks are gated off, turn them back on (may be the case if + coming out of suspend mode).*/ + if (otgp->PCGCCTL & (PCGCCTL_STPPCLK | PCGCCTL_GATEHCLK)) { + /* Set to zero to un-gate the USB core clocks.*/ + otgp->PCGCCTL &= ~(PCGCCTL_STPPCLK | PCGCCTL_GATEHCLK); + } + + /* Clear the Remote Wake-up Signaling.*/ + otgp->DCTL &= ~DCTL_RWUSIG; + + _usb_wakeup(usbp); + } + + /* Suspend handling.*/ + if (sts & GINTSTS_USBSUSP) { + /* Stopping all ongoing transfers.*/ + otg_disable_ep(usbp); + + /* Default suspend action.*/ + _usb_suspend(usbp); + } + + /* Enumeration done.*/ + if (sts & GINTSTS_ENUMDNE) { + /* Full or High speed timing selection.*/ + if ((otgp->DSTS & DSTS_ENUMSPD_MASK) == DSTS_ENUMSPD_HS_480) { + otgp->GUSBCFG = (otgp->GUSBCFG & ~(GUSBCFG_TRDT_MASK)) | + GUSBCFG_TRDT(TRDT_VALUE_HS); + } + else { + otgp->GUSBCFG = (otgp->GUSBCFG & ~(GUSBCFG_TRDT_MASK)) | + GUSBCFG_TRDT(TRDT_VALUE_FS); + } + } + + /* SOF interrupt handling.*/ + if (sts & GINTSTS_SOF) { + _usb_isr_invoke_sof_cb(usbp); + } + + /* Isochronous IN failed handling */ + if (sts & GINTSTS_IISOIXFR) { + otg_isoc_in_failed_handler(usbp); + } + + /* Isochronous OUT failed handling */ + if (sts & GINTSTS_IISOOXFR) { + otg_isoc_out_failed_handler(usbp); + } + + /* Performing the whole FIFO emptying in the ISR, it is advised to keep + this IRQ at a very low priority level.*/ + if ((sts & GINTSTS_RXFLVL) != 0U) { + otg_rxfifo_handler(usbp); + } + + /* IN/OUT endpoints event handling.*/ + src = otgp->DAINT; + if (sts & GINTSTS_OEPINT) { + if (src & (1 << 16)) + otg_epout_handler(usbp, 0); + if (src & (1 << 17)) + otg_epout_handler(usbp, 1); + if (src & (1 << 18)) + otg_epout_handler(usbp, 2); + if (src & (1 << 19)) + otg_epout_handler(usbp, 3); +#if USB_MAX_ENDPOINTS >= 4 + if (src & (1 << 20)) + otg_epout_handler(usbp, 4); +#endif +#if USB_MAX_ENDPOINTS >= 5 + if (src & (1 << 21)) + otg_epout_handler(usbp, 5); +#endif +#if USB_MAX_ENDPOINTS >= 6 + if (src & (1 << 22)) + otg_epout_handler(usbp, 6); +#endif +#if USB_MAX_ENDPOINTS >= 7 + if (src & (1 << 23)) + otg_epout_handler(usbp, 7); +#endif +#if USB_MAX_ENDPOINTS >= 8 + if (src & (1 << 24)) + otg_epout_handler(usbp, 8); +#endif + } + if (sts & GINTSTS_IEPINT) { + if (src & (1 << 0)) + otg_epin_handler(usbp, 0); + if (src & (1 << 1)) + otg_epin_handler(usbp, 1); + if (src & (1 << 2)) + otg_epin_handler(usbp, 2); + if (src & (1 << 3)) + otg_epin_handler(usbp, 3); +#if USB_MAX_ENDPOINTS >= 4 + if (src & (1 << 4)) + otg_epin_handler(usbp, 4); +#endif +#if USB_MAX_ENDPOINTS >= 5 + if (src & (1 << 5)) + otg_epin_handler(usbp, 5); +#endif +#if USB_MAX_ENDPOINTS >= 6 + if (src & (1 << 6)) + otg_epin_handler(usbp, 6); +#endif +#if USB_MAX_ENDPOINTS >= 7 + if (src & (1 << 7)) + otg_epin_handler(usbp, 7); +#endif +#if USB_MAX_ENDPOINTS >= 8 + if (src & (1 << 8)) + otg_epin_handler(usbp, 8); +#endif + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USB_USE_OTG1 || defined(__DOXYGEN__) +/** + * @brief OTG1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_OTG1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + usb_lld_serve_interrupt(&USBD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_USB_USE_OTG2 || defined(__DOXYGEN__) +/** + * @brief OTG2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_OTG2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + usb_lld_serve_interrupt(&USBD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level USB driver initialization. + * + * @notapi + */ +void usb_lld_init(void) { + + /* Driver initialization.*/ +#if STM32_USB_USE_OTG1 + usbObjectInit(&USBD1); + USBD1.otg = OTG_FS; + USBD1.otgparams = &fsparams; + +#endif + +#if STM32_USB_USE_OTG2 + usbObjectInit(&USBD2); + USBD2.otg = OTG_HS; + USBD2.otgparams = &hsparams; +#endif +} + +/** + * @brief Configures and activates the USB peripheral. + * @note Starting the OTG cell can be a slow operation carried out with + * interrupts disabled, perform it before starting time-critical + * operations. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_start(USBDriver *usbp) { + stm32_otg_t *otgp = usbp->otg; + + if (usbp->state == USB_STOP) { + /* Clock activation.*/ + +#if STM32_USB_USE_OTG1 + if (&USBD1 == usbp) { + /* OTG FS clock enable and reset.*/ + rccEnableOTG_FS(true); + rccResetOTG_FS(); + + /* Enables IRQ vector.*/ + nvicEnableVector(STM32_OTG1_NUMBER, STM32_USB_OTG1_IRQ_PRIORITY); + + /* - Forced device mode. + - USB turn-around time = TRDT_VALUE_FS. + - Full Speed 1.1 PHY.*/ + otgp->GUSBCFG = GUSBCFG_FDMOD | GUSBCFG_TRDT(TRDT_VALUE_FS) | + GUSBCFG_PHYSEL; + + /* 48MHz 1.1 PHY.*/ + otgp->DCFG = 0x02200000 | DCFG_DSPD_FS11; + } +#endif + +#if STM32_USB_USE_OTG2 + if (&USBD2 == usbp) { + /* OTG HS clock enable and reset.*/ + rccEnableOTG_HS(true); + rccResetOTG_HS(); + + /* ULPI clock is managed depending on the presence of an external + PHY.*/ +#if defined(BOARD_OTG2_USES_ULPI) + rccEnableOTG_HSULPI(true); +#else + /* Workaround for the problem described here: + http://forum.chibios.org/phpbb/viewtopic.php?f=16&t=1798.*/ + rccDisableOTG_HSULPI(); +#endif + + /* Enables IRQ vector.*/ + nvicEnableVector(STM32_OTG2_NUMBER, STM32_USB_OTG2_IRQ_PRIORITY); + + /* - Forced device mode. + - USB turn-around time = TRDT_VALUE_HS or TRDT_VALUE_FS.*/ +#if defined(BOARD_OTG2_USES_ULPI) + /* High speed ULPI PHY.*/ + otgp->GUSBCFG = GUSBCFG_FDMOD | GUSBCFG_TRDT(TRDT_VALUE_HS) | + GUSBCFG_SRPCAP | GUSBCFG_HNPCAP; +#else + otgp->GUSBCFG = GUSBCFG_FDMOD | GUSBCFG_TRDT(TRDT_VALUE_FS) | + GUSBCFG_PHYSEL; +#endif + +#if defined(BOARD_OTG2_USES_ULPI) +#if STM32_USE_USB_OTG2_HS + /* USB 2.0 High Speed PHY in HS mode.*/ + otgp->DCFG = 0x02200000 | DCFG_DSPD_HS; +#else + /* USB 2.0 High Speed PHY in FS mode.*/ + otgp->DCFG = 0x02200000 | DCFG_DSPD_HS_FS; +#endif +#else + /* 48MHz 1.1 PHY.*/ + otgp->DCFG = 0x02200000 | DCFG_DSPD_FS11; +#endif + } +#endif + + /* PHY enabled.*/ + otgp->PCGCCTL = 0; + + /* VBUS sensing and transceiver enabled.*/ + otgp->GOTGCTL = GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL; + +#if defined(BOARD_OTG2_USES_ULPI) +#if STM32_USB_USE_OTG1 + if (&USBD1 == usbp) { + otgp->GCCFG = GCCFG_INIT_VALUE; + } +#endif + +#if STM32_USB_USE_OTG2 + if (&USBD2 == usbp) { + otgp->GCCFG = 0; + } +#endif +#else + otgp->GCCFG = GCCFG_INIT_VALUE; +#endif + + /* Soft core reset.*/ + otg_core_reset(usbp); + + /* Interrupts on TXFIFOs half empty.*/ + otgp->GAHBCFG = 0; + + /* Endpoints re-initialization.*/ + otg_disable_ep(usbp); + + /* Clear all pending Device Interrupts, only the USB Reset interrupt + is required initially.*/ + otgp->DIEPMSK = 0; + otgp->DOEPMSK = 0; + otgp->DAINTMSK = 0; + if (usbp->config->sof_cb == NULL) + otgp->GINTMSK = GINTMSK_ENUMDNEM | GINTMSK_USBRSTM | GINTMSK_USBSUSPM | + GINTMSK_ESUSPM | GINTMSK_SRQM | GINTMSK_WKUM | + GINTMSK_IISOIXFRM | GINTMSK_IISOOXFRM; + else + otgp->GINTMSK = GINTMSK_ENUMDNEM | GINTMSK_USBRSTM | GINTMSK_USBSUSPM | + GINTMSK_ESUSPM | GINTMSK_SRQM | GINTMSK_WKUM | + GINTMSK_IISOIXFRM | GINTMSK_IISOOXFRM | + GINTMSK_SOFM; + + /* Clears all pending IRQs, if any. */ + otgp->GINTSTS = 0xFFFFFFFF; + + /* Global interrupts enable.*/ + otgp->GAHBCFG |= GAHBCFG_GINTMSK; + } +} + +/** + * @brief Deactivates the USB peripheral. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_stop(USBDriver *usbp) { + stm32_otg_t *otgp = usbp->otg; + + /* If in ready state then disables the USB clock.*/ + if (usbp->state != USB_STOP) { + + /* Disabling all endpoints in case the driver has been stopped while + active.*/ + otg_disable_ep(usbp); + + otgp->DAINTMSK = 0; + otgp->GAHBCFG = 0; + otgp->GCCFG = 0; + +#if STM32_USB_USE_OTG1 + if (&USBD1 == usbp) { + nvicDisableVector(STM32_OTG1_NUMBER); + rccDisableOTG_FS(); + } +#endif + +#if STM32_USB_USE_OTG2 + if (&USBD2 == usbp) { + nvicDisableVector(STM32_OTG2_NUMBER); + rccDisableOTG_HS(); +#if defined(BOARD_OTG2_USES_ULPI) + rccDisableOTG_HSULPI() +#endif + } +#endif + } +} + +/** + * @brief USB low level reset routine. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_reset(USBDriver *usbp) { + unsigned i; + stm32_otg_t *otgp = usbp->otg; + + /* Flush the Tx FIFO.*/ + otg_txfifo_flush(usbp, 0); + + /* Endpoint interrupts all disabled and cleared.*/ + otgp->DIEPEMPMSK = 0; + otgp->DAINTMSK = DAINTMSK_OEPM(0) | DAINTMSK_IEPM(0); + + /* All endpoints in NAK mode, interrupts cleared.*/ + for (i = 0; i <= usbp->otgparams->num_endpoints; i++) { + otgp->ie[i].DIEPCTL = DIEPCTL_SNAK; + otgp->oe[i].DOEPCTL = DOEPCTL_SNAK; + otgp->ie[i].DIEPINT = 0xFFFFFFFF; + otgp->oe[i].DOEPINT = 0xFFFFFFFF; + } + + /* Resets the FIFO memory allocator.*/ + otg_ram_reset(usbp); + + /* Receive FIFO size initialization, the address is always zero.*/ + otgp->GRXFSIZ = usbp->otgparams->rx_fifo_size; + otg_rxfifo_flush(usbp); + + /* Resets the device address to zero.*/ + otgp->DCFG = (otgp->DCFG & ~DCFG_DAD_MASK) | DCFG_DAD(0); + + /* Enables also EP-related interrupt sources.*/ + otgp->GINTMSK |= GINTMSK_RXFLVLM | GINTMSK_OEPM | GINTMSK_IEPM; + otgp->DIEPMSK = DIEPMSK_TOCM | DIEPMSK_XFRCM; + otgp->DOEPMSK = DOEPMSK_STUPM | DOEPMSK_XFRCM; + + /* EP0 initialization, it is a special case.*/ + usbp->epc[0] = &ep0config; + otgp->oe[0].DOEPTSIZ = DOEPTSIZ_STUPCNT(3); + otgp->oe[0].DOEPCTL = DOEPCTL_SD0PID | DOEPCTL_USBAEP | DOEPCTL_EPTYP_CTRL | + DOEPCTL_MPSIZ(ep0config.out_maxsize); + otgp->ie[0].DIEPTSIZ = 0; + otgp->ie[0].DIEPCTL = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_CTRL | + DIEPCTL_TXFNUM(0) | DIEPCTL_MPSIZ(ep0config.in_maxsize); + otgp->DIEPTXF0 = DIEPTXF_INEPTXFD(ep0config.in_maxsize / 4) | + DIEPTXF_INEPTXSA(otg_ram_alloc(usbp, + ep0config.in_maxsize / 4)); +} + +/** + * @brief Sets the USB address. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_set_address(USBDriver *usbp) { + stm32_otg_t *otgp = usbp->otg; + + otgp->DCFG = (otgp->DCFG & ~DCFG_DAD_MASK) | DCFG_DAD(usbp->address); +} + +/** + * @brief Enables an endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { + uint32_t ctl, fsize; + stm32_otg_t *otgp = usbp->otg; + + /* IN and OUT common parameters.*/ + switch (usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) { + case USB_EP_MODE_TYPE_CTRL: + ctl = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_CTRL; + break; + case USB_EP_MODE_TYPE_ISOC: + ctl = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_ISO; + break; + case USB_EP_MODE_TYPE_BULK: + ctl = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_BULK; + break; + case USB_EP_MODE_TYPE_INTR: + ctl = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_INTR; + break; + default: + return; + } + + /* OUT endpoint activation or deactivation.*/ + otgp->oe[ep].DOEPTSIZ = 0; + if (usbp->epc[ep]->out_state != NULL) { + otgp->oe[ep].DOEPCTL = ctl | DOEPCTL_MPSIZ(usbp->epc[ep]->out_maxsize); + otgp->DAINTMSK |= DAINTMSK_OEPM(ep); + } + else { + otgp->oe[ep].DOEPCTL &= ~DOEPCTL_USBAEP; + otgp->DAINTMSK &= ~DAINTMSK_OEPM(ep); + } + + /* IN endpoint activation or deactivation.*/ + otgp->ie[ep].DIEPTSIZ = 0; + if (usbp->epc[ep]->in_state != NULL) { + /* FIFO allocation for the IN endpoint.*/ + fsize = usbp->epc[ep]->in_maxsize / 4; + if (usbp->epc[ep]->in_multiplier > 1) + fsize *= usbp->epc[ep]->in_multiplier; + otgp->DIEPTXF[ep - 1] = DIEPTXF_INEPTXFD(fsize) | + DIEPTXF_INEPTXSA(otg_ram_alloc(usbp, fsize)); + otg_txfifo_flush(usbp, ep); + + otgp->ie[ep].DIEPCTL = ctl | + DIEPCTL_TXFNUM(ep) | + DIEPCTL_MPSIZ(usbp->epc[ep]->in_maxsize); + otgp->DAINTMSK |= DAINTMSK_IEPM(ep); + } + else { + otgp->DIEPTXF[ep - 1] = 0x02000400; /* Reset value.*/ + otg_txfifo_flush(usbp, ep); + otgp->ie[ep].DIEPCTL &= ~DIEPCTL_USBAEP; + otgp->DAINTMSK &= ~DAINTMSK_IEPM(ep); + } +} + +/** + * @brief Disables all the active endpoints except the endpoint zero. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_disable_endpoints(USBDriver *usbp) { + + /* Resets the FIFO memory allocator.*/ + otg_ram_reset(usbp); + + /* Disabling all endpoints.*/ + otg_disable_ep(usbp); +} + +/** + * @brief Returns the status of an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return The endpoint status. + * @retval EP_STATUS_DISABLED The endpoint is not active. + * @retval EP_STATUS_STALLED The endpoint is stalled. + * @retval EP_STATUS_ACTIVE The endpoint is active. + * + * @notapi + */ +usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) { + uint32_t ctl; + + (void)usbp; + + ctl = usbp->otg->oe[ep].DOEPCTL; + if (!(ctl & DOEPCTL_USBAEP)) + return EP_STATUS_DISABLED; + if (ctl & DOEPCTL_STALL) + return EP_STATUS_STALLED; + return EP_STATUS_ACTIVE; +} + +/** + * @brief Returns the status of an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return The endpoint status. + * @retval EP_STATUS_DISABLED The endpoint is not active. + * @retval EP_STATUS_STALLED The endpoint is stalled. + * @retval EP_STATUS_ACTIVE The endpoint is active. + * + * @notapi + */ +usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) { + uint32_t ctl; + + (void)usbp; + + ctl = usbp->otg->ie[ep].DIEPCTL; + if (!(ctl & DIEPCTL_USBAEP)) + return EP_STATUS_DISABLED; + if (ctl & DIEPCTL_STALL) + return EP_STATUS_STALLED; + return EP_STATUS_ACTIVE; +} + +/** + * @brief Reads a setup packet from the dedicated packet buffer. + * @details This function must be invoked in the context of the @p setup_cb + * callback in order to read the received setup packet. + * @pre In order to use this function the endpoint must have been + * initialized as a control endpoint. + * @post The endpoint is ready to accept another packet. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[out] buf buffer where to copy the packet data + * + * @notapi + */ +void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) { + + memcpy(buf, usbp->epc[ep]->setup_buf, 8); +} + +/** + * @brief Starts a receive operation on an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_start_out(USBDriver *usbp, usbep_t ep) { + uint32_t pcnt, rxsize; + USBOutEndpointState *osp = usbp->epc[ep]->out_state; + + /* Transfer initialization.*/ + osp->totsize = osp->rxsize; + if ((ep == 0) && (osp->rxsize > EP0_MAX_OUTSIZE)) + osp->rxsize = EP0_MAX_OUTSIZE; + + /* Transaction size is rounded to a multiple of packet size because the + following requirement in the RM: + "For OUT transfers, the transfer size field in the endpoint's transfer + size register must be a multiple of the maximum packet size of the + endpoint, adjusted to the Word boundary".*/ + pcnt = (osp->rxsize + usbp->epc[ep]->out_maxsize - 1U) / + usbp->epc[ep]->out_maxsize; + rxsize = (pcnt * usbp->epc[ep]->out_maxsize + 3U) & 0xFFFFFFFCU; + + /*Setting up transaction parameters in DOEPTSIZ.*/ + usbp->otg->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) | + DOEPTSIZ_XFRSIZ(rxsize); + + /* Special case of isochronous endpoint.*/ + if ((usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) { + /* Odd/even bit toggling for isochronous endpoint.*/ + if (usbp->otg->DSTS & DSTS_FNSOF_ODD) + usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_SEVNFRM; + else + usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_SODDFRM; + } + + /* Starting operation.*/ + usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_EPENA | DOEPCTL_CNAK; +} + +/** + * @brief Starts a transmit operation on an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_start_in(USBDriver *usbp, usbep_t ep) { + USBInEndpointState *isp = usbp->epc[ep]->in_state; + + /* Transfer initialization.*/ + isp->totsize = isp->txsize; + if (isp->txsize == 0) { + /* Special case, sending zero size packet.*/ + usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(1) | DIEPTSIZ_XFRSIZ(0); + } + else { + if ((ep == 0) && (isp->txsize > EP0_MAX_INSIZE)) + isp->txsize = EP0_MAX_INSIZE; + + /* Normal case.*/ + uint32_t pcnt = (isp->txsize + usbp->epc[ep]->in_maxsize - 1) / + usbp->epc[ep]->in_maxsize; + /* CHTODO: Support more than one packet per frame for isochronous transfers.*/ + usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_MCNT(1) | DIEPTSIZ_PKTCNT(pcnt) | + DIEPTSIZ_XFRSIZ(isp->txsize); + } + + /* Special case of isochronous endpoint.*/ + if ((usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) { + /* Odd/even bit toggling.*/ + if (usbp->otg->DSTS & DSTS_FNSOF_ODD) + usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_SEVNFRM; + else + usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_SODDFRM; + } + + /* Starting operation.*/ + usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_EPENA | DIEPCTL_CNAK; + usbp->otg->DIEPEMPMSK |= DIEPEMPMSK_INEPTXFEM(ep); +} + +/** + * @brief Brings an OUT endpoint in the stalled state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) { + + usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_STALL; +} + +/** + * @brief Brings an IN endpoint in the stalled state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) { + + usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_STALL; +} + +/** + * @brief Brings an OUT endpoint in the active state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) { + + usbp->otg->oe[ep].DOEPCTL &= ~DOEPCTL_STALL; +} + +/** + * @brief Brings an IN endpoint in the active state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) { + + usbp->otg->ie[ep].DIEPCTL &= ~DIEPCTL_STALL; +} + +#endif /* HAL_USE_USB */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.h new file mode 100644 index 0000000..08add51 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.h @@ -0,0 +1,610 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file OTGv1/hal_usb_lld.h + * @brief STM32 USB subsystem low level driver header. + * + * @addtogroup USB + * @{ + */ + +#ifndef HAL_USB_LLD_H +#define HAL_USB_LLD_H + +#if HAL_USE_USB || defined(__DOXYGEN__) + +#include "stm32_otg.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Status stage handling method. + */ +#define USB_EP0_STATUS_STAGE USB_EP0_STATUS_STAGE_SW + +/** + * @brief The address can be changed immediately upon packet reception. + */ +#define USB_SET_ADDRESS_MODE USB_EARLY_SET_ADDRESS + +/** + * @brief Method for set address acknowledge. + */ +#define USB_SET_ADDRESS_ACK_HANDLING USB_SET_ADDRESS_ACK_SW + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief OTG1 driver enable switch. + * @details If set to @p TRUE the support for OTG_FS is included. + * @note The default is @p FALSE + */ +#if !defined(STM32_USB_USE_OTG1) || defined(__DOXYGEN__) +#define STM32_USB_USE_OTG1 FALSE +#endif + +/** + * @brief OTG2 driver enable switch. + * @details If set to @p TRUE the support for OTG_HS is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_USB_USE_OTG2) || defined(__DOXYGEN__) +#define STM32_USB_USE_OTG2 FALSE +#endif + +/** + * @brief OTG1 interrupt priority level setting. + */ +#if !defined(STM32_USB_OTG1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_USB_OTG1_IRQ_PRIORITY 14 +#endif + +/** + * @brief OTG2 interrupt priority level setting. + */ +#if !defined(STM32_USB_OTG2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_USB_OTG2_IRQ_PRIORITY 14 +#endif + +/** + * @brief OTG1 RX shared FIFO size. + * @note Must be a multiple of 4. + */ +#if !defined(STM32_USB_OTG1_RX_FIFO_SIZE) || defined(__DOXYGEN__) +#define STM32_USB_OTG1_RX_FIFO_SIZE 512 +#endif + +/** + * @brief OTG2 RX shared FIFO size. + * @note Must be a multiple of 4. + */ +#if !defined(STM32_USB_OTG2_RX_FIFO_SIZE) || defined(__DOXYGEN__) +#define STM32_USB_OTG2_RX_FIFO_SIZE 1024 +#endif + +/** + * @brief Enables HS mode on OTG2 else FS mode. + * @note The default is @p TRUE. + * @note Has effect only if @p BOARD_OTG2_USES_ULPI is defined. + */ +#if !defined(STM32_USE_USB_OTG2_HS) || defined(__DOXYGEN__) +#define STM32_USE_USB_OTG2_HS TRUE +#endif + +/** + * @brief Exception priority level during TXFIFOs operations. + * @note Because an undocumented silicon behavior the operation of + * copying a packet into a TXFIFO must not be interrupted by + * any other operation on the OTG peripheral. + * This parameter represents the priority mask during copy + * operations. The default value only allows to call USB + * functions from callbacks invoked from USB ISR handlers. + * If you need to invoke USB functions from other handlers + * then raise this priority mast to the same level of the + * handler you need to use. + * @note The value zero means disabled, when disabled calling USB + * functions is only safe from thread level or from USB + * callbacks. + */ +#if !defined(STM32_USB_OTGFIFO_FILL_BASEPRI) || defined(__DOXYGEN__) +#define STM32_USB_OTGFIFO_FILL_BASEPRI 0 +#endif + +/** + * @brief Host wake-up procedure duration. + */ +#if !defined(STM32_USB_HOST_WAKEUP_DURATION) || defined(__DOXYGEN__) +#define STM32_USB_HOST_WAKEUP_DURATION 2 +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks.*/ +#if !defined(STM32_OTG_STEPPING) +#error "STM32_OTG_STEPPING not defined in registry" +#endif + +#if (STM32_OTG_STEPPING < 1) || (STM32_OTG_STEPPING > 2) +#error "unsupported STM32_OTG_STEPPING" +#endif + +#if !defined(STM32_HAS_OTG1) || !defined(STM32_HAS_OTG2) +#error "STM32_HAS_OTGx not defined in registry" +#endif + +#if STM32_HAS_OTG1 && !defined(STM32_OTG1_ENDPOINTS) +#error "STM32_OTG1_ENDPOINTS not defined in registry" +#endif + +#if STM32_HAS_OTG2 && !defined(STM32_OTG2_ENDPOINTS) +#error "STM32_OTG2_ENDPOINTS not defined in registry" +#endif + +#if STM32_HAS_OTG1 && !defined(STM32_OTG1_FIFO_MEM_SIZE) +#error "STM32_OTG1_FIFO_MEM_SIZE not defined in registry" +#endif + +#if STM32_HAS_OTG2 && !defined(STM32_OTG2_FIFO_MEM_SIZE) +#error "STM32_OTG2_FIFO_MEM_SIZE not defined in registry" +#endif + +#if (STM32_USB_USE_OTG1 && !defined(STM32_OTG1_HANDLER)) || \ + (STM32_USB_USE_OTG2 && !defined(STM32_OTG2_HANDLER)) +#error "STM32_OTGx_HANDLER not defined in registry" +#endif + +#if (STM32_USB_USE_OTG1 && !defined(STM32_OTG1_NUMBER)) || \ + (STM32_USB_USE_OTG2 && !defined(STM32_OTG2_NUMBER)) +#error "STM32_OTGx_NUMBER not defined in registry" +#endif + +/** + * @brief Maximum endpoint address. + */ +#if (STM32_HAS_OTG2 && STM32_USB_USE_OTG2) || defined(__DOXYGEN__) +#if (STM32_OTG1_ENDPOINTS < STM32_OTG2_ENDPOINTS) || defined(__DOXYGEN__) +#define USB_MAX_ENDPOINTS STM32_OTG2_ENDPOINTS +#else +#define USB_MAX_ENDPOINTS STM32_OTG1_ENDPOINTS +#endif +#else +#define USB_MAX_ENDPOINTS STM32_OTG1_ENDPOINTS +#endif + +#if STM32_USB_USE_OTG1 && !STM32_HAS_OTG1 +#error "OTG1 not present in the selected device" +#endif + +#if STM32_USB_USE_OTG2 && !STM32_HAS_OTG2 +#error "OTG2 not present in the selected device" +#endif + +#if !STM32_USB_USE_OTG1 && !STM32_USB_USE_OTG2 +#error "USB driver activated but no USB peripheral assigned" +#endif + +#if STM32_USB_USE_OTG1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_USB_OTG1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to OTG1" +#endif + +#if STM32_USB_USE_OTG2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_USB_OTG2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to OTG2" +#endif + +#if (STM32_USB_OTG1_RX_FIFO_SIZE & 3) != 0 +#error "OTG1 RX FIFO size must be a multiple of 4" +#endif + +#if (STM32_USB_OTG2_RX_FIFO_SIZE & 3) != 0 +#error "OTG2 RX FIFO size must be a multiple of 4" +#endif + +#if defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32F7XX) +#define STM32_USBCLK STM32_PLL48CLK +#elif defined(STM32F10X_CL) +#define STM32_USBCLK STM32_OTGFSCLK +#elif defined(STM32L4XX) || defined(STM32L4XXP) +#define STM32_USBCLK STM32_48CLK +#elif defined(STM32H7XX) +/* Defines directly STM32_USBCLK.*/ +#if !defined(STM32H723xx) +#define rccEnableOTG_FS rccEnableUSB2_OTG_HS +#define rccDisableOTG_FS rccDisableUSB2_OTG_HS +#define rccResetOTG_FS rccResetUSB2_OTG_HS +#else +#define rccEnableOTG_FS rccEnableUSB1_OTG_HS +#define rccDisableOTG_FS rccDisableUSB1_OTG_HS +#define rccResetOTG_FS rccResetUSB1_OTG_HS +#endif +#define rccEnableOTG_HS rccEnableUSB1_OTG_HS +#define rccDisableOTG_HS rccDisableUSB1_OTG_HS +#define rccResetOTG_HS rccResetUSB1_OTG_HS +#define rccEnableOTG_HSULPI rccEnableUSB1_HSULPI +#define rccDisableOTG_HSULPI rccDisableUSB1_HSULPI +#else +#error "unsupported STM32 platform for OTG functionality" +#endif + +/* Allowing for a small tolerance.*/ +#if STM32_USBCLK < 47880000 || STM32_USBCLK > 48120000 +#error "the USB OTG driver requires a 48MHz clock" +#endif + +#if (STM32_USB_HOST_WAKEUP_DURATION < 2) || (STM32_USB_HOST_WAKEUP_DURATION > 15) +#error "invalid STM32_USB_HOST_WAKEUP_DURATION setting, it must be between 2 and 15" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Peripheral-specific parameters block. + */ +typedef struct { + uint32_t rx_fifo_size; + uint32_t otg_ram_size; + uint32_t num_endpoints; +} stm32_otg_params_t; + +/** + * @brief Type of an IN endpoint state structure. + */ +typedef struct { + /** + * @brief Requested transmit transfer size. + */ + size_t txsize; + /** + * @brief Transmitted bytes so far. + */ + size_t txcnt; + /** + * @brief Pointer to the transmission linear buffer. + */ + const uint8_t *txbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif + /* End of the mandatory fields.*/ + /** + * @brief Total transmit transfer size. + */ + size_t totsize; +} USBInEndpointState; + +/** + * @brief Type of an OUT endpoint state structure. + */ +typedef struct { + /** + * @brief Requested receive transfer size. + */ + size_t rxsize; + /** + * @brief Received bytes so far. + */ + size_t rxcnt; + /** + * @brief Pointer to the receive linear buffer. + */ + uint8_t *rxbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif + /* End of the mandatory fields.*/ + /** + * @brief Total receive transfer size. + */ + size_t totsize; +} USBOutEndpointState; + +/** + * @brief Type of an USB endpoint configuration structure. + * @note Platform specific restrictions may apply to endpoints. + */ +typedef struct { + /** + * @brief Type and mode of the endpoint. + */ + uint32_t ep_mode; + /** + * @brief Setup packet notification callback. + * @details This callback is invoked when a setup packet has been + * received. + * @post The application must immediately call @p usbReadPacket() in + * order to access the received packet. + * @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL + * endpoints, it should be set to @p NULL for other endpoint + * types. + */ + usbepcallback_t setup_cb; + /** + * @brief IN endpoint notification callback. + * @details This field must be set to @p NULL if callback is not required. + */ + usbepcallback_t in_cb; + /** + * @brief OUT endpoint notification callback. + * @details This field must be set to @p NULL if callback is not required. + */ + usbepcallback_t out_cb; + /** + * @brief IN endpoint maximum packet size. + * @details This field must be set to zero if the IN endpoint is not used. + */ + uint16_t in_maxsize; + /** + * @brief OUT endpoint maximum packet size. + * @details This field must be set to zero if the OUT endpoint is not used. + */ + uint16_t out_maxsize; + /** + * @brief @p USBEndpointState associated to the IN endpoint. + * @details This field must be set to @p NULL if the IN endpoint is not + * used. + */ + USBInEndpointState *in_state; + /** + * @brief @p USBEndpointState associated to the OUT endpoint. + * @details This field must be set to @p NULL if the OUT endpoint is not + * used. + */ + USBOutEndpointState *out_state; + /* End of the mandatory fields.*/ + /** + * @brief Determines the space allocated for the TXFIFO as multiples of + * the packet size (@p in_maxsize). Note that zero is interpreted + * as one for simplicity and robustness. + */ + uint16_t in_multiplier; + /** + * @brief Pointer to a buffer for setup packets. + * @details Setup packets require a dedicated 8-bytes buffer, set this + * field to @p NULL for non-control endpoints. + */ + uint8_t *setup_buf; +} USBEndpointConfig; + +/** + * @brief Type of an USB driver configuration structure. + */ +typedef struct { + /** + * @brief USB events callback. + * @details This callback is invoked when an USB driver event is registered. + */ + usbeventcb_t event_cb; + /** + * @brief Device GET_DESCRIPTOR request callback. + * @note This callback is mandatory and cannot be set to @p NULL. + */ + usbgetdescriptor_t get_descriptor_cb; + /** + * @brief Requests hook callback. + * @details This hook allows to be notified of standard requests or to + * handle non standard requests. + */ + usbreqhandler_t requests_hook_cb; + /** + * @brief Start Of Frame callback. + */ + usbcallback_t sof_cb; + /* End of the mandatory fields.*/ +} USBConfig; + +/** + * @brief Structure representing an USB driver. + */ +struct USBDriver { + /** + * @brief Driver state. + */ + usbstate_t state; + /** + * @brief Current configuration data. + */ + const USBConfig *config; + /** + * @brief Bit map of the transmitting IN endpoints. + */ + uint16_t transmitting; + /** + * @brief Bit map of the receiving OUT endpoints. + */ + uint16_t receiving; + /** + * @brief Active endpoints configurations. + */ + const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1]; + /** + * @brief Fields available to user, it can be used to associate an + * application-defined handler to an IN endpoint. + * @note The base index is one, the endpoint zero does not have a + * reserved element in this array. + */ + void *in_params[USB_MAX_ENDPOINTS]; + /** + * @brief Fields available to user, it can be used to associate an + * application-defined handler to an OUT endpoint. + * @note The base index is one, the endpoint zero does not have a + * reserved element in this array. + */ + void *out_params[USB_MAX_ENDPOINTS]; + /** + * @brief Endpoint 0 state. + */ + usbep0state_t ep0state; + /** + * @brief Next position in the buffer to be transferred through endpoint 0. + */ + uint8_t *ep0next; + /** + * @brief Number of bytes yet to be transferred through endpoint 0. + */ + size_t ep0n; + /** + * @brief Endpoint 0 end transaction callback. + */ + usbcallback_t ep0endcb; + /** + * @brief Setup packet buffer. + */ + uint8_t setup[8]; + /** + * @brief Current USB device status. + */ + uint16_t status; + /** + * @brief Assigned USB address. + */ + uint8_t address; + /** + * @brief Current USB device configuration. + */ + uint8_t configuration; + /** + * @brief State of the driver when a suspend happened. + */ + usbstate_t saved_state; +#if defined(USB_DRIVER_EXT_FIELDS) + USB_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the OTG peripheral associated to this driver. + */ + stm32_otg_t *otg; + /** + * @brief Peripheral-specific parameters. + */ + const stm32_otg_params_t *otgparams; + /** + * @brief Pointer to the next address in the packet memory. + */ + uint32_t pmnext; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Returns the exact size of a receive transaction. + * @details The received size can be different from the size specified in + * @p usbStartReceiveI() because the last packet could have a size + * different from the expected one. + * @pre The OUT endpoint must have been configured in transaction mode + * in order to use this function. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return Received data size. + * + * @notapi + */ +#define usb_lld_get_transaction_size(usbp, ep) \ + ((usbp)->epc[ep]->out_state->rxcnt) + +/** + * @brief Connects the USB device. + * + * @notapi + */ +#if (STM32_OTG_STEPPING == 1) || defined(__DOXYGEN__) +#define usb_lld_connect_bus(usbp) ((usbp)->otg->GCCFG |= GCCFG_VBUSBSEN) +#else +#define usb_lld_connect_bus(usbp) ((usbp)->otg->DCTL &= ~DCTL_SDIS) +#endif + +/** + * @brief Disconnect the USB device. + * + * @notapi + */ +#if (STM32_OTG_STEPPING == 1) || defined(__DOXYGEN__) +#define usb_lld_disconnect_bus(usbp) ((usbp)->otg->GCCFG &= ~GCCFG_VBUSBSEN) +#else +#define usb_lld_disconnect_bus(usbp) ((usbp)->otg->DCTL |= DCTL_SDIS) +#endif + +/** + * @brief Start of host wake-up procedure. + * + * @notapi + */ +#define usb_lld_wakeup_host(usbp) \ + do { \ + (usbp)->otg->DCTL |= DCTL_RWUSIG; \ + osalThreadSleepMilliseconds(STM32_USB_HOST_WAKEUP_DURATION); \ + (usbp)->otg->DCTL &= ~DCTL_RWUSIG; \ + } while (false) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_USB_USE_OTG1 && !defined(__DOXYGEN__) +extern USBDriver USBD1; +#endif + +#if STM32_USB_USE_OTG2 && !defined(__DOXYGEN__) +extern USBDriver USBD2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void usb_lld_init(void); + void usb_lld_start(USBDriver *usbp); + void usb_lld_stop(USBDriver *usbp); + void usb_lld_reset(USBDriver *usbp); + void usb_lld_set_address(USBDriver *usbp); + void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep); + void usb_lld_disable_endpoints(USBDriver *usbp); + usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep); + usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep); + void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf); + void usb_lld_start_out(USBDriver *usbp, usbep_t ep); + void usb_lld_start_in(USBDriver *usbp, usbep_t ep); + void usb_lld_stall_out(USBDriver *usbp, usbep_t ep); + void usb_lld_stall_in(USBDriver *usbp, usbep_t ep); + void usb_lld_clear_out(USBDriver *usbp, usbep_t ep); + void usb_lld_clear_in(USBDriver *usbp, usbep_t ep); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_USB */ + +#endif /* HAL_USB_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/stm32_otg.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/stm32_otg.h new file mode 100644 index 0000000..0ea7314 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/stm32_otg.h @@ -0,0 +1,927 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file OTGv1/stm32_otg.h + * @brief STM32 OTG registers layout header. + * + * @addtogroup USB + * @{ + */ + +#ifndef STM32_OTG_H +#define STM32_OTG_H + +/** + * @brief OTG_FS FIFO memory size in words. + */ +#define STM32_OTG1_FIFO_MEM_SIZE 320 + +/** + * @brief OTG_HS FIFO memory size in words. + */ +#define STM32_OTG2_FIFO_MEM_SIZE 1024 + +/** + * @brief Host channel registers group. + */ +typedef struct { + volatile uint32_t HCCHAR; /**< @brief Host channel characteristics + register. */ + volatile uint32_t resvd8; + volatile uint32_t HCINT; /**< @brief Host channel interrupt register.*/ + volatile uint32_t HCINTMSK; /**< @brief Host channel interrupt mask + register. */ + volatile uint32_t HCTSIZ; /**< @brief Host channel transfer size + register. */ + volatile uint32_t resvd14; + volatile uint32_t resvd18; + volatile uint32_t resvd1c; +} stm32_otg_host_chn_t; + +/** + * @brief Device input endpoint registers group. + */ +typedef struct { + volatile uint32_t DIEPCTL; /**< @brief Device control IN endpoint + control register. */ + volatile uint32_t resvd4; + volatile uint32_t DIEPINT; /**< @brief Device IN endpoint interrupt + register. */ + volatile uint32_t resvdC; + volatile uint32_t DIEPTSIZ; /**< @brief Device IN endpoint transfer size + register. */ + volatile uint32_t resvd14; + volatile uint32_t DTXFSTS; /**< @brief Device IN endpoint transmit FIFO + status register. */ + volatile uint32_t resvd1C; +} stm32_otg_in_ep_t; + +/** + * @brief Device output endpoint registers group. + */ +typedef struct { + volatile uint32_t DOEPCTL; /**< @brief Device control OUT endpoint + control register. */ + volatile uint32_t resvd4; + volatile uint32_t DOEPINT; /**< @brief Device OUT endpoint interrupt + register. */ + volatile uint32_t resvdC; + volatile uint32_t DOEPTSIZ; /**< @brief Device OUT endpoint transfer + size register. */ + volatile uint32_t resvd14; + volatile uint32_t resvd18; + volatile uint32_t resvd1C; +} stm32_otg_out_ep_t; + +/** + * @brief USB registers memory map. + */ +typedef struct { + volatile uint32_t GOTGCTL; /**< @brief OTG control and status register.*/ + volatile uint32_t GOTGINT; /**< @brief OTG interrupt register. */ + volatile uint32_t GAHBCFG; /**< @brief AHB configuration register. */ + volatile uint32_t GUSBCFG; /**< @brief USB configuration register. */ + volatile uint32_t GRSTCTL; /**< @brief Reset register size. */ + volatile uint32_t GINTSTS; /**< @brief Interrupt register. */ + volatile uint32_t GINTMSK; /**< @brief Interrupt mask register. */ + volatile uint32_t GRXSTSR; /**< @brief Receive status debug read + register. */ + volatile uint32_t GRXSTSP; /**< @brief Receive status read/pop + register. */ + volatile uint32_t GRXFSIZ; /**< @brief Receive FIFO size register. */ + volatile uint32_t DIEPTXF0; /**< @brief Endpoint 0 transmit FIFO size + register. */ + volatile uint32_t HNPTXSTS; /**< @brief Non-periodic transmit FIFO/queue + status register. */ + volatile uint32_t resvd30; + volatile uint32_t resvd34; + volatile uint32_t GCCFG; /**< @brief General core configuration. */ + volatile uint32_t CID; /**< @brief Core ID register. */ + volatile uint32_t resvd58[48]; + volatile uint32_t HPTXFSIZ; /**< @brief Host periodic transmit FIFO size + register. */ + volatile uint32_t DIEPTXF[15];/**< @brief Device IN endpoint transmit FIFO + size registers. */ + volatile uint32_t resvd140[176]; + volatile uint32_t HCFG; /**< @brief Host configuration register. */ + volatile uint32_t HFIR; /**< @brief Host frame interval register. */ + volatile uint32_t HFNUM; /**< @brief Host frame number/frame time + Remaining register. */ + volatile uint32_t resvd40C; + volatile uint32_t HPTXSTS; /**< @brief Host periodic transmit FIFO/queue + status register. */ + volatile uint32_t HAINT; /**< @brief Host all channels interrupt + register. */ + volatile uint32_t HAINTMSK; /**< @brief Host all channels interrupt mask + register. */ + volatile uint32_t resvd41C[9]; + volatile uint32_t HPRT; /**< @brief Host port control and status + register. */ + volatile uint32_t resvd444[47]; + stm32_otg_host_chn_t hc[16]; /**< @brief Host channels array. */ + volatile uint32_t resvd700[64]; + volatile uint32_t DCFG; /**< @brief Device configuration register. */ + volatile uint32_t DCTL; /**< @brief Device control register. */ + volatile uint32_t DSTS; /**< @brief Device status register. */ + volatile uint32_t resvd80C; + volatile uint32_t DIEPMSK; /**< @brief Device IN endpoint common + interrupt mask register. */ + volatile uint32_t DOEPMSK; /**< @brief Device OUT endpoint common + interrupt mask register. */ + volatile uint32_t DAINT; /**< @brief Device all endpoints interrupt + register. */ + volatile uint32_t DAINTMSK; /**< @brief Device all endpoints interrupt + mask register. */ + volatile uint32_t resvd820; + volatile uint32_t resvd824; + volatile uint32_t DVBUSDIS; /**< @brief Device VBUS discharge time + register. */ + volatile uint32_t DVBUSPULSE; /**< @brief Device VBUS pulsing time + register. */ + volatile uint32_t resvd830; + volatile uint32_t DIEPEMPMSK; /**< @brief Device IN endpoint FIFO empty + interrupt mask register. */ + volatile uint32_t resvd838; + volatile uint32_t resvd83C; + volatile uint32_t resvd840[16]; + volatile uint32_t resvd880[16]; + volatile uint32_t resvd8C0[16]; + stm32_otg_in_ep_t ie[16]; /**< @brief Input endpoints. */ + stm32_otg_out_ep_t oe[16]; /**< @brief Output endpoints. */ + volatile uint32_t resvdD00[64]; + volatile uint32_t PCGCCTL; /**< @brief Power and clock gating control + register. */ + volatile uint32_t resvdE04[127]; + volatile uint32_t FIFO[16][1024]; +} stm32_otg_t; + +/** + * @name GOTGCTL register bit definitions + * @{ + */ +#define GOTGCTL_BSVLD (1U<<19) /**< B-Session Valid. */ +#define GOTGCTL_ASVLD (1U<<18) /**< A-Session Valid. */ +#define GOTGCTL_DBCT (1U<<17) /**< Long/Short debounce time. */ +#define GOTGCTL_CIDSTS (1U<<16) /**< Connector ID status. */ +#define GOTGCTL_EHEN (1U<<12) +#define GOTGCTL_DHNPEN (1U<<11) /**< Device HNP enabled. */ +#define GOTGCTL_HSHNPEN (1U<<10) /**< Host Set HNP enable. */ +#define GOTGCTL_HNPRQ (1U<<9) /**< HNP request. */ +#define GOTGCTL_HNGSCS (1U<<8) /**< Host negotiation success. */ +#define GOTGCTL_BVALOVAL (1U<<7) +#define GOTGCTL_BVALOEN (1U<<6) +#define GOTGCTL_AVALOVAL (1U<<5) +#define GOTGCTL_AVALOEN (1U<<4) +#define GOTGCTL_VBVALOVAL (1U<<3) +#define GOTGCTL_VBVALOEN (1U<<2) +#define GOTGCTL_SRQ (1U<<1) /**< Session request. */ +#define GOTGCTL_SRQSCS (1U<<0) /**< Session request success. */ +/** @} */ + +/** + * @name GOTGINT register bit definitions + * @{ + */ +#define GOTGINT_DBCDNE (1U<<19) /**< Debounce done. */ +#define GOTGINT_ADTOCHG (1U<<18) /**< A-Device timeout change. */ +#define GOTGINT_HNGDET (1U<<17) /**< Host negotiation detected. */ +#define GOTGINT_HNSSCHG (1U<<9) /**< Host negotiation success + status change. */ +#define GOTGINT_SRSSCHG (1U<<8) /**< Session request success + status change. */ +#define GOTGINT_SEDET (1U<<2) /**< Session end detected. */ +/** @} */ + +/** + * @name GAHBCFG register bit definitions + * @{ + */ +#define GAHBCFG_PTXFELVL (1U<<8) /**< Periodic TxFIFO empty + level. */ +#define GAHBCFG_TXFELVL (1U<<7) /**< Non-periodic TxFIFO empty + level. */ +#define GAHBCFG_DMAEN (1U<<5) /**< DMA enable (HS only). */ +#define GAHBCFG_HBSTLEN_MASK (15U<<1) /**< Burst length/type mask (HS + only). */ +#define GAHBCFG_HBSTLEN(n) ((n)<<1) /**< Burst length/type (HS + only). */ +#define GAHBCFG_GINTMSK (1U<<0) /**< Global interrupt mask. */ +/** @} */ + +/** + * @name GUSBCFG register bit definitions + * @{ + */ +#define GUSBCFG_CTXPKT (1U<<31) /**< Corrupt Tx packet. */ +#define GUSBCFG_FDMOD (1U<<30) /**< Force Device Mode. */ +#define GUSBCFG_FHMOD (1U<<29) /**< Force Host Mode. */ +#define GUSBCFG_TRDT_MASK (15U<<10) /**< USB Turnaround time field + mask. */ +#define GUSBCFG_TRDT(n) ((n)<<10) /**< USB Turnaround time field + value. */ +#define GUSBCFG_HNPCAP (1U<<9) /**< HNP-Capable. */ +#define GUSBCFG_SRPCAP (1U<<8) /**< SRP-Capable. */ +#define GUSBCFG_PHYSEL (1U<<6) /**< USB 2.0 High-Speed PHY or + USB 1.1 Full-Speed serial + transceiver Select. */ +#define GUSBCFG_TOCAL_MASK (7U<<0) /**< HS/FS timeout calibration + field mask. */ +#define GUSBCFG_TOCAL(n) ((n)<<0) /**< HS/FS timeout calibration + field value. */ +/** @} */ + +/** + * @name GRSTCTL register bit definitions + * @{ + */ +#define GRSTCTL_AHBIDL (1U<<31) /**< AHB Master Idle. */ +#define GRSTCTL_TXFNUM_MASK (31U<<6) /**< TxFIFO number field mask. */ +#define GRSTCTL_TXFNUM(n) ((n)<<6) /**< TxFIFO number field value. */ +#define GRSTCTL_TXFFLSH (1U<<5) /**< TxFIFO flush. */ +#define GRSTCTL_RXFFLSH (1U<<4) /**< RxFIFO flush. */ +#define GRSTCTL_FCRST (1U<<2) /**< Host frame counter reset. */ +#define GRSTCTL_HSRST (1U<<1) /**< HClk soft reset. */ +#define GRSTCTL_CSRST (1U<<0) /**< Core soft reset. */ +/** @} */ + +/** + * @name GINTSTS register bit definitions + * @{ + */ +#define GINTSTS_WKUPINT (1U<<31) /**< Resume/Remote wakeup + detected interrupt. */ +#define GINTSTS_SRQINT (1U<<30) /**< Session request/New session + detected interrupt. */ +#define GINTSTS_DISCINT (1U<<29) /**< Disconnect detected + interrupt. */ +#define GINTSTS_CIDSCHG (1U<<28) /**< Connector ID status change.*/ +#define GINTSTS_PTXFE (1U<<26) /**< Periodic TxFIFO empty. */ +#define GINTSTS_HCINT (1U<<25) /**< Host channels interrupt. */ +#define GINTSTS_HPRTINT (1U<<24) /**< Host port interrupt. */ +#define GINTSTS_IPXFR (1U<<21) /**< Incomplete periodic + transfer. */ +#define GINTSTS_IISOOXFR (1U<<21) /**< Incomplete isochronous OUT + transfer. */ +#define GINTSTS_IISOIXFR (1U<<20) /**< Incomplete isochronous IN + transfer. */ +#define GINTSTS_OEPINT (1U<<19) /**< OUT endpoints interrupt. */ +#define GINTSTS_IEPINT (1U<<18) /**< IN endpoints interrupt. */ +#define GINTSTS_EOPF (1U<<15) /**< End of periodic frame + interrupt. */ +#define GINTSTS_ISOODRP (1U<<14) /**< Isochronous OUT packet + dropped interrupt. */ +#define GINTSTS_ENUMDNE (1U<<13) /**< Enumeration done. */ +#define GINTSTS_USBRST (1U<<12) /**< USB reset. */ +#define GINTSTS_USBSUSP (1U<<11) /**< USB suspend. */ +#define GINTSTS_ESUSP (1U<<10) /**< Early suspend. */ +#define GINTSTS_GONAKEFF (1U<<7) /**< Global OUT NAK effective. */ +#define GINTSTS_GINAKEFF (1U<<6) /**< Global IN non-periodic NAK + effective. */ +#define GINTSTS_NPTXFE (1U<<5) /**< Non-periodic TxFIFO empty. */ +#define GINTSTS_RXFLVL (1U<<4) /**< RxFIFO non-empty. */ +#define GINTSTS_SOF (1U<<3) /**< Start of frame. */ +#define GINTSTS_OTGINT (1U<<2) /**< OTG interrupt. */ +#define GINTSTS_MMIS (1U<<1) /**< Mode Mismatch interrupt. */ +#define GINTSTS_CMOD (1U<<0) /**< Current mode of operation. */ +/** @} */ + +/** + * @name GINTMSK register bit definitions + * @{ + */ +#define GINTMSK_WKUM (1U<<31) /**< Resume/remote wakeup + detected interrupt mask. */ +#define GINTMSK_SRQM (1U<<30) /**< Session request/New session + detected interrupt mask. */ +#define GINTMSK_DISCM (1U<<29) /**< Disconnect detected + interrupt mask. */ +#define GINTMSK_CIDSCHGM (1U<<28) /**< Connector ID status change + mask. */ +#define GINTMSK_PTXFEM (1U<<26) /**< Periodic TxFIFO empty mask.*/ +#define GINTMSK_HCM (1U<<25) /**< Host channels interrupt + mask. */ +#define GINTMSK_HPRTM (1U<<24) /**< Host port interrupt mask. */ +#define GINTMSK_IPXFRM (1U<<21) /**< Incomplete periodic + transfer mask. */ +#define GINTMSK_IISOOXFRM (1U<<21) /**< Incomplete isochronous OUT + transfer mask. */ +#define GINTMSK_IISOIXFRM (1U<<20) /**< Incomplete isochronous IN + transfer mask. */ +#define GINTMSK_OEPM (1U<<19) /**< OUT endpoints interrupt + mask. */ +#define GINTMSK_IEPM (1U<<18) /**< IN endpoints interrupt + mask. */ +#define GINTMSK_EOPFM (1U<<15) /**< End of periodic frame + interrupt mask. */ +#define GINTMSK_ISOODRPM (1U<<14) /**< Isochronous OUT packet + dropped interrupt mask. */ +#define GINTMSK_ENUMDNEM (1U<<13) /**< Enumeration done mask. */ +#define GINTMSK_USBRSTM (1U<<12) /**< USB reset mask. */ +#define GINTMSK_USBSUSPM (1U<<11) /**< USB suspend mask. */ +#define GINTMSK_ESUSPM (1U<<10) /**< Early suspend mask. */ +#define GINTMSK_GONAKEFFM (1U<<7) /**< Global OUT NAK effective + mask. */ +#define GINTMSK_GINAKEFFM (1U<<6) /**< Global non-periodic IN NAK + effective mask. */ +#define GINTMSK_NPTXFEM (1U<<5) /**< Non-periodic TxFIFO empty + mask. */ +#define GINTMSK_RXFLVLM (1U<<4) /**< Receive FIFO non-empty + mask. */ +#define GINTMSK_SOFM (1U<<3) /**< Start of (micro)frame mask.*/ +#define GINTMSK_OTGM (1U<<2) /**< OTG interrupt mask. */ +#define GINTMSK_MMISM (1U<<1) /**< Mode Mismatch interrupt + mask. */ +/** @} */ + +/** + * @name GRXSTSR register bit definitions + * @{ + */ +#define GRXSTSR_PKTSTS_MASK (15U<<17) /**< Packet status mask. */ +#define GRXSTSR_PKTSTS(n) ((n)<<17) /**< Packet status value. */ +#define GRXSTSR_OUT_GLOBAL_NAK GRXSTSR_PKTSTS(1) +#define GRXSTSR_OUT_DATA GRXSTSR_PKTSTS(2) +#define GRXSTSR_OUT_COMP GRXSTSR_PKTSTS(3) +#define GRXSTSR_SETUP_COMP GRXSTSR_PKTSTS(4) +#define GRXSTSR_SETUP_DATA GRXSTSR_PKTSTS(6) +#define GRXSTSR_DPID_MASK (3U<<15) /**< Data PID mask. */ +#define GRXSTSR_DPID(n) ((n)<<15) /**< Data PID value. */ +#define GRXSTSR_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */ +#define GRXSTSR_BCNT(n) ((n)<<4) /**< Byte count value. */ +#define GRXSTSR_CHNUM_MASK (15U<<0) /**< Channel number mask. */ +#define GRXSTSR_CHNUM(n) ((n)<<0) /**< Channel number value. */ +#define GRXSTSR_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */ +#define GRXSTSR_EPNUM(n) ((n)<<0) /**< Endpoint number value. */ +/** @} */ + +/** + * @name GRXSTSP register bit definitions + * @{ + */ +#define GRXSTSP_PKTSTS_MASK (15<<17) /**< Packet status mask. */ +#define GRXSTSP_PKTSTS(n) ((n)<<17) /**< Packet status value. */ +#define GRXSTSP_OUT_GLOBAL_NAK GRXSTSP_PKTSTS(1) +#define GRXSTSP_OUT_DATA GRXSTSP_PKTSTS(2) +#define GRXSTSP_OUT_COMP GRXSTSP_PKTSTS(3) +#define GRXSTSP_SETUP_COMP GRXSTSP_PKTSTS(4) +#define GRXSTSP_SETUP_DATA GRXSTSP_PKTSTS(6) +#define GRXSTSP_DPID_MASK (3U<<15) /**< Data PID mask. */ +#define GRXSTSP_DPID(n) ((n)<<15) /**< Data PID value. */ +#define GRXSTSP_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */ +#define GRXSTSP_BCNT_OFF 4 /**< Byte count offset. */ +#define GRXSTSP_BCNT(n) ((n)<<4) /**< Byte count value. */ +#define GRXSTSP_CHNUM_MASK (15U<<0) /**< Channel number mask. */ +#define GRXSTSP_CHNUM(n) ((n)<<0) /**< Channel number value. */ +#define GRXSTSP_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */ +#define GRXSTSP_EPNUM_OFF 0 /**< Endpoint number offset. */ +#define GRXSTSP_EPNUM(n) ((n)<<0) /**< Endpoint number value. */ +/** @} */ + +/** + * @name GRXFSIZ register bit definitions + * @{ + */ +#define GRXFSIZ_RXFD_MASK (0xFFFF<<0) /**< RxFIFO depth mask. */ +#define GRXFSIZ_RXFD(n) ((n)<<0) /**< RxFIFO depth value. */ +/** @} */ + +/** + * @name DIEPTXFx register bit definitions + * @{ + */ +#define DIEPTXF_INEPTXFD_MASK (0xFFFFU<<16)/**< IN endpoint TxFIFO depth + mask. */ +#define DIEPTXF_INEPTXFD(n) ((n)<<16) /**< IN endpoint TxFIFO depth + value. */ +#define DIEPTXF_INEPTXSA_MASK (0xFFFF<<0) /**< IN endpoint FIFOx transmit + RAM start address mask. */ +#define DIEPTXF_INEPTXSA(n) ((n)<<0) /**< IN endpoint FIFOx transmit + RAM start address value. */ +/** @} */ + +/** + * @name GCCFG register bit definitions + * @{ + */ +/* Definitions for stepping 1.*/ +#define GCCFG_NOVBUSSENS (1U<<21) /**< VBUS sensing disable. */ +#define GCCFG_SOFOUTEN (1U<<20) /**< SOF output enable. */ +#define GCCFG_VBUSBSEN (1U<<19) /**< Enable the VBUS sensing "B" + device. */ +#define GCCFG_VBUSASEN (1U<<18) /**< Enable the VBUS sensing "A" + device. */ + +/* Definitions for stepping 2.*/ +#define GCCFG_VBDEN (1U<<21) /**< VBUS sensing enable. */ +#define GCCFG_PWRDWN (1U<<16) /**< Power down. */ +/** @} */ + +/** + * @name HPTXFSIZ register bit definitions + * @{ + */ +#define HPTXFSIZ_PTXFD_MASK (0xFFFFU<<16)/**< Host periodic TxFIFO + depth mask. */ +#define HPTXFSIZ_PTXFD(n) ((n)<<16) /**< Host periodic TxFIFO + depth value. */ +#define HPTXFSIZ_PTXSA_MASK (0xFFFFU<<0)/**< Host periodic TxFIFO + Start address mask. */ +#define HPTXFSIZ_PTXSA(n) ((n)<<0) /**< Host periodic TxFIFO + start address value. */ +/** @} */ + +/** + * @name HCFG register bit definitions + * @{ + */ +#define HCFG_FSLSS (1U<<2) /**< FS- and LS-only support. */ +#define HCFG_FSLSPCS_MASK (3U<<0) /**< FS/LS PHY clock select + mask. */ +#define HCFG_FSLSPCS_48 (1U<<0) /**< PHY clock is running at + 48 MHz. */ +#define HCFG_FSLSPCS_6 (2U<<0) /**< PHY clock is running at + 6 MHz. */ +/** @} */ + +/** + * @name HFIR register bit definitions + * @{ + */ +#define HFIR_FRIVL_MASK (0xFFFFU<<0)/**< Frame interval mask. */ +#define HFIR_FRIVL(n) ((n)<<0) /**< Frame interval value. */ +/** @} */ + +/** + * @name HFNUM register bit definitions + * @{ + */ +#define HFNUM_FTREM_MASK (0xFFFFU<<16)/**< Frame time Remaining mask.*/ +#define HFNUM_FTREM(n) ((n)<<16) /**< Frame time Remaining value.*/ +#define HFNUM_FRNUM_MASK (0xFFFFU<<0)/**< Frame number mask. */ +#define HFNUM_FRNUM(n) ((n)<<0) /**< Frame number value. */ +/** @} */ + +/** + * @name HPTXSTS register bit definitions + * @{ + */ +#define HPTXSTS_PTXQTOP_MASK (0xFFU<<24) /**< Top of the periodic + transmit request queue + mask. */ +#define HPTXSTS_PTXQTOP(n) ((n)<<24) /**< Top of the periodic + transmit request queue + value. */ +#define HPTXSTS_PTXQSAV_MASK (0xFF<<16) /**< Periodic transmit request + queue Space Available + mask. */ +#define HPTXSTS_PTXQSAV(n) ((n)<<16) /**< Periodic transmit request + queue Space Available + value. */ +#define HPTXSTS_PTXFSAVL_MASK (0xFFFF<<0) /**< Periodic transmit Data + FIFO Space Available + mask. */ +#define HPTXSTS_PTXFSAVL(n) ((n)<<0) /**< Periodic transmit Data + FIFO Space Available + value. */ +/** @} */ + +/** + * @name HAINT register bit definitions + * @{ + */ +#define HAINT_HAINT_MASK (0xFFFFU<<0)/**< Channel interrupts mask. */ +#define HAINT_HAINT(n) ((n)<<0) /**< Channel interrupts value. */ +/** @} */ + +/** + * @name HAINTMSK register bit definitions + * @{ + */ +#define HAINTMSK_HAINTM_MASK (0xFFFFU<<0)/**< Channel interrupt mask + mask. */ +#define HAINTMSK_HAINTM(n) ((n)<<0) /**< Channel interrupt mask + value. */ +/** @} */ + +/** + * @name HPRT register bit definitions + * @{ + */ +#define HPRT_PSPD_MASK (3U<<17) /**< Port speed mask. */ +#define HPRT_PSPD_FS (1U<<17) /**< Full speed value. */ +#define HPRT_PSPD_LS (2U<<17) /**< Low speed value. */ +#define HPRT_PTCTL_MASK (15<<13) /**< Port Test control mask. */ +#define HPRT_PTCTL(n) ((n)<<13) /**< Port Test control value. */ +#define HPRT_PPWR (1U<<12) /**< Port power. */ +#define HPRT_PLSTS_MASK (3U<<11) /**< Port Line status mask. */ +#define HPRT_PLSTS_DM (1U<<11) /**< Logic level of D-. */ +#define HPRT_PLSTS_DP (1U<<10) /**< Logic level of D+. */ +#define HPRT_PRST (1U<<8) /**< Port reset. */ +#define HPRT_PSUSP (1U<<7) /**< Port suspend. */ +#define HPRT_PRES (1U<<6) /**< Port Resume. */ +#define HPRT_POCCHNG (1U<<5) /**< Port overcurrent change. */ +#define HPRT_POCA (1U<<4) /**< Port overcurrent active. */ +#define HPRT_PENCHNG (1U<<3) /**< Port enable/disable change.*/ +#define HPRT_PENA (1U<<2) /**< Port enable. */ +#define HPRT_PCDET (1U<<1) /**< Port Connect detected. */ +#define HPRT_PCSTS (1U<<0) /**< Port connect status. */ +/** @} */ + +/** + * @name HCCHAR register bit definitions + * @{ + */ +#define HCCHAR_CHENA (1U<<31) /**< Channel enable. */ +#define HCCHAR_CHDIS (1U<<30) /**< Channel Disable. */ +#define HCCHAR_ODDFRM (1U<<29) /**< Odd frame. */ +#define HCCHAR_DAD_MASK (0x7FU<<22) /**< Device Address mask. */ +#define HCCHAR_DAD(n) ((n)<<22) /**< Device Address value. */ +#define HCCHAR_MCNT_MASK (3U<<20) /**< Multicount mask. */ +#define HCCHAR_MCNT(n) ((n)<<20) /**< Multicount value. */ +#define HCCHAR_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */ +#define HCCHAR_EPTYP(n) ((n)<<18) /**< Endpoint type value. */ +#define HCCHAR_EPTYP_CTL (0U<<18) /**< Control endpoint value. */ +#define HCCHAR_EPTYP_ISO (1U<<18) /**< Isochronous endpoint value.*/ +#define HCCHAR_EPTYP_BULK (2U<<18) /**< Bulk endpoint value. */ +#define HCCHAR_EPTYP_INTR (3U<<18) /**< Interrupt endpoint value. */ +#define HCCHAR_LSDEV (1U<<17) /**< Low-Speed device. */ +#define HCCHAR_EPDIR (1U<<15) /**< Endpoint direction. */ +#define HCCHAR_EPNUM_MASK (15U<<11) /**< Endpoint number mask. */ +#define HCCHAR_EPNUM(n) ((n)<<11) /**< Endpoint number value. */ +#define HCCHAR_MPS_MASK (0x7FFU<<0) /**< Maximum packet size mask. */ +#define HCCHAR_MPS(n) ((n)<<0) /**< Maximum packet size value. */ +/** @} */ + +/** + * @name HCINT register bit definitions + * @{ + */ +#define HCINT_DTERR (1U<<10) /**< Data toggle error. */ +#define HCINT_FRMOR (1U<<9) /**< Frame overrun. */ +#define HCINT_BBERR (1U<<8) /**< Babble error. */ +#define HCINT_TRERR (1U<<7) /**< Transaction Error. */ +#define HCINT_ACK (1U<<5) /**< ACK response + received/transmitted + interrupt. */ +#define HCINT_NAK (1U<<4) /**< NAK response received + interrupt. */ +#define HCINT_STALL (1U<<3) /**< STALL response received + interrupt. */ +#define HCINT_AHBERR (1U<<2) /**< AHB error interrupt. */ +#define HCINT_CHH (1U<<1) /**< Channel halted. */ +#define HCINT_XFRC (1U<<0) /**< Transfer completed. */ +/** @} */ + +/** + * @name HCINTMSK register bit definitions + * @{ + */ +#define HCINTMSK_DTERRM (1U<<10) /**< Data toggle error mask. */ +#define HCINTMSK_FRMORM (1U<<9) /**< Frame overrun mask. */ +#define HCINTMSK_BBERRM (1U<<8) /**< Babble error mask. */ +#define HCINTMSK_TRERRM (1U<<7) /**< Transaction error mask. */ +#define HCINTMSK_NYET (1U<<6) /**< NYET response received + interrupt mask. */ +#define HCINTMSK_ACKM (1U<<5) /**< ACK Response + received/transmitted + interrupt mask. */ +#define HCINTMSK_NAKM (1U<<4) /**< NAK response received + interrupt mask. */ +#define HCINTMSK_STALLM (1U<<3) /**< STALL response received + interrupt mask. */ +#define HCINTMSK_AHBERRM (1U<<2) /**< AHB error interrupt mask. */ +#define HCINTMSK_CHHM (1U<<1) /**< Channel halted mask. */ +#define HCINTMSK_XFRCM (1U<<0) /**< Transfer completed mask. */ +/** @} */ + +/** + * @name HCTSIZ register bit definitions + * @{ + */ +#define HCTSIZ_DPID_MASK (3U<<29) /**< PID mask. */ +#define HCTSIZ_DPID_DATA0 (0U<<29) /**< DATA0. */ +#define HCTSIZ_DPID_DATA2 (1U<<29) /**< DATA2. */ +#define HCTSIZ_DPID_DATA1 (2U<<29) /**< DATA1. */ +#define HCTSIZ_DPID_MDATA (3U<<29) /**< MDATA. */ +#define HCTSIZ_DPID_SETUP (3U<<29) /**< SETUP. */ +#define HCTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */ +#define HCTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ +#define HCTSIZ_XFRSIZ_MASK (0x7FFFF<<0)/**< Transfer size mask. */ +#define HCTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ +/** @} */ + +/** + * @name DCFG register bit definitions + * @{ + */ +#define DCFG_PFIVL_MASK (3U<<11) /**< Periodic frame interval + mask. */ +#define DCFG_PFIVL(n) ((n)<<11) /**< Periodic frame interval + value. */ +#define DCFG_DAD_MASK (0x7FU<<4) /**< Device address mask. */ +#define DCFG_DAD(n) ((n)<<4) /**< Device address value. */ +#define DCFG_NZLSOHSK (1U<<2) /**< Non-Zero-Length status + OUT handshake. */ +#define DCFG_DSPD_MASK (3U<<0) /**< Device speed mask. */ +#define DCFG_DSPD_HS (0U<<0) /**< High speed (USB 2.0). */ +#define DCFG_DSPD_HS_FS (1U<<0) /**< High speed (USB 2.0) in FS + mode. */ +#define DCFG_DSPD_FS11 (3U<<0) /**< Full speed (USB 1.1 + transceiver clock is 48 + MHz). */ +/** @} */ + +/** + * @name DCTL register bit definitions + * @{ + */ +#define DCTL_POPRGDNE (1U<<11) /**< Power-on programming done. */ +#define DCTL_CGONAK (1U<<10) /**< Clear global OUT NAK. */ +#define DCTL_SGONAK (1U<<9) /**< Set global OUT NAK. */ +#define DCTL_CGINAK (1U<<8) /**< Clear global non-periodic + IN NAK. */ +#define DCTL_SGINAK (1U<<7) /**< Set global non-periodic + IN NAK. */ +#define DCTL_TCTL_MASK (7U<<4) /**< Test control mask. */ +#define DCTL_TCTL(n) ((n)<<4 /**< Test control value. */ +#define DCTL_GONSTS (1U<<3) /**< Global OUT NAK status. */ +#define DCTL_GINSTS (1U<<2) /**< Global non-periodic IN + NAK status. */ +#define DCTL_SDIS (1U<<1) /**< Soft disconnect. */ +#define DCTL_RWUSIG (1U<<0) /**< Remote wakeup signaling. */ +/** @} */ + +/** + * @name DSTS register bit definitions + * @{ + */ +#define DSTS_FNSOF_MASK (0x3FFU<<8) /**< Frame number of the received + SOF mask. */ +#define DSTS_FNSOF(n) ((n)<<8) /**< Frame number of the received + SOF value. */ +#define DSTS_FNSOF_ODD (1U<<8) /**< Frame parity of the received + SOF value. */ +#define DSTS_EERR (1U<<3) /**< Erratic error. */ +#define DSTS_ENUMSPD_MASK (3U<<1) /**< Enumerated speed mask. */ +#define DSTS_ENUMSPD_FS_48 (3U<<1) /**< Full speed (PHY clock is + running at 48 MHz). */ +#define DSTS_ENUMSPD_HS_480 (0U<<1) /**< High speed. */ +#define DSTS_SUSPSTS (1U<<0) /**< Suspend status. */ +/** @} */ + +/** + * @name DIEPMSK register bit definitions + * @{ + */ +#define DIEPMSK_TXFEM (1U<<6) /**< Transmit FIFO empty mask. */ +#define DIEPMSK_INEPNEM (1U<<6) /**< IN endpoint NAK effective + mask. */ +#define DIEPMSK_ITTXFEMSK (1U<<4) /**< IN token received when + TxFIFO empty mask. */ +#define DIEPMSK_TOCM (1U<<3) /**< Timeout condition mask. */ +#define DIEPMSK_EPDM (1U<<1) /**< Endpoint disabled + interrupt mask. */ +#define DIEPMSK_XFRCM (1U<<0) /**< Transfer completed + interrupt mask. */ +/** @} */ + +/** + * @name DOEPMSK register bit definitions + * @{ + */ +#define DOEPMSK_OTEPDM (1U<<4) /**< OUT token received when + endpoint disabled mask. */ +#define DOEPMSK_STUPM (1U<<3) /**< SETUP phase done mask. */ +#define DOEPMSK_EPDM (1U<<1) /**< Endpoint disabled + interrupt mask. */ +#define DOEPMSK_XFRCM (1U<<0) /**< Transfer completed + interrupt mask. */ +/** @} */ + +/** + * @name DAINT register bit definitions + * @{ + */ +#define DAINT_OEPINT_MASK (0xFFFFU<<16)/**< OUT endpoint interrupt + bits mask. */ +#define DAINT_OEPINT(n) ((n)<<16) /**< OUT endpoint interrupt + bits value. */ +#define DAINT_IEPINT_MASK (0xFFFFU<<0)/**< IN endpoint interrupt + bits mask. */ +#define DAINT_IEPINT(n) ((n)<<0) /**< IN endpoint interrupt + bits value. */ +/** @} */ + +/** + * @name DAINTMSK register bit definitions + * @{ + */ +#define DAINTMSK_OEPM_MASK (0xFFFFU<<16)/**< OUT EP interrupt mask + bits mask. */ +#define DAINTMSK_OEPM(n) (1U<<(16+(n)))/**< OUT EP interrupt mask + bits value. */ +#define DAINTMSK_IEPM_MASK (0xFFFFU<<0)/**< IN EP interrupt mask + bits mask. */ +#define DAINTMSK_IEPM(n) (1U<<(n)) /**< IN EP interrupt mask + bits value. */ +/** @} */ + +/** + * @name DVBUSDIS register bit definitions + * @{ + */ +#define DVBUSDIS_VBUSDT_MASK (0xFFFFU<<0)/**< Device VBUS discharge + time mask. */ +#define DVBUSDIS_VBUSDT(n) ((n)<<0) /**< Device VBUS discharge + time value. */ +/** @} */ + +/** + * @name DVBUSPULSE register bit definitions + * @{ + */ +#define DVBUSPULSE_DVBUSP_MASK (0xFFFU<<0) /**< Device VBUSpulsing time + mask. */ +#define DVBUSPULSE_DVBUSP(n) ((n)<<0) /**< Device VBUS pulsing time + value. */ +/** @} */ + +/** + * @name DIEPEMPMSK register bit definitions + * @{ + */ +#define DIEPEMPMSK_INEPTXFEM(n) (1U<<(n)) /**< IN EP Tx FIFO empty + interrupt mask bit. */ +/** @} */ + +/** + * @name DIEPCTL register bit definitions + * @{ + */ +#define DIEPCTL_EPENA (1U<<31) /**< Endpoint enable. */ +#define DIEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */ +#define DIEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */ +#define DIEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */ +#define DIEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */ +#define DIEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */ +#define DIEPCTL_SNAK (1U<<27) /**< Set NAK. */ +#define DIEPCTL_CNAK (1U<<26) /**< Clear NAK. */ +#define DIEPCTL_TXFNUM_MASK (15U<<22) /**< TxFIFO number mask. */ +#define DIEPCTL_TXFNUM(n) ((n)<<22) /**< TxFIFO number value. */ +#define DIEPCTL_STALL (1U<<21) /**< STALL handshake. */ +#define DIEPCTL_SNPM (1U<<20) /**< Snoop mode. */ +#define DIEPCTL_EPTYP_MASK (3<<18) /**< Endpoint type mask. */ +#define DIEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */ +#define DIEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */ +#define DIEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */ +#define DIEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */ +#define DIEPCTL_NAKSTS (1U<<17) /**< NAK status. */ +#define DIEPCTL_EONUM (1U<<16) /**< Even/odd frame. */ +#define DIEPCTL_DPID (1U<<16) /**< Endpoint data PID. */ +#define DIEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */ +#define DIEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */ +#define DIEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */ +/** @} */ + +/** + * @name DIEPINT register bit definitions + * @{ + */ +#define DIEPINT_TXFE (1U<<7) /**< Transmit FIFO empty. */ +#define DIEPINT_INEPNE (1U<<6) /**< IN endpoint NAK effective. */ +#define DIEPINT_ITTXFE (1U<<4) /**< IN Token received when + TxFIFO is empty. */ +#define DIEPINT_TOC (1U<<3) /**< Timeout condition. */ +#define DIEPINT_EPDISD (1U<<1) /**< Endpoint disabled + interrupt. */ +#define DIEPINT_XFRC (1U<<0) /**< Transfer completed. */ +/** @} */ + +/** + * @name DIEPTSIZ register bit definitions + * @{ + */ +#define DIEPTSIZ_MCNT_MASK (3U<<29) /**< Multi count mask. */ +#define DIEPTSIZ_MCNT(n) ((n)<<29) /**< Multi count value. */ +#define DIEPTSIZ_PKTCNT_MASK (0x3FF<<19) /**< Packet count mask. */ +#define DIEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ +#define DIEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */ +#define DIEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ +/** @} */ + +/** + * @name DTXFSTS register bit definitions. + * @{ + */ +#define DTXFSTS_INEPTFSAV_MASK (0xFFFF<<0) /**< IN endpoint TxFIFO space + available. */ +/** @} */ + +/** + * @name DOEPCTL register bit definitions. + * @{ + */ +#define DOEPCTL_EPENA (1U<<31) /**< Endpoint enable. */ +#define DOEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */ +#define DOEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */ +#define DOEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */ +#define DOEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */ +#define DOEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */ +#define DOEPCTL_SNAK (1U<<27) /**< Set NAK. */ +#define DOEPCTL_CNAK (1U<<26) /**< Clear NAK. */ +#define DOEPCTL_STALL (1U<<21) /**< STALL handshake. */ +#define DOEPCTL_SNPM (1U<<20) /**< Snoop mode. */ +#define DOEPCTL_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */ +#define DOEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */ +#define DOEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */ +#define DOEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */ +#define DOEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */ +#define DOEPCTL_NAKSTS (1U<<17) /**< NAK status. */ +#define DOEPCTL_EONUM (1U<<16) /**< Even/odd frame. */ +#define DOEPCTL_DPID (1U<<16) /**< Endpoint data PID. */ +#define DOEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */ +#define DOEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */ +#define DOEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */ +/** @} */ + +/** + * @name DOEPINT register bit definitions + * @{ + */ +#define DOEPINT_SETUP_RCVD (1U<<15) /**< SETUP packet received. */ +#define DOEPINT_B2BSTUP (1U<<6) /**< Back-to-back SETUP packets + received. */ +#define DOEPINT_OTEPDIS (1U<<4) /**< OUT token received when + endpoint disabled. */ +#define DOEPINT_STUP (1U<<3) /**< SETUP phase done. */ +#define DOEPINT_EPDISD (1U<<1) /**< Endpoint disabled + interrupt. */ +#define DOEPINT_XFRC (1U<<0) /**< Transfer completed + interrupt. */ +/** @} */ + +/** + * @name DOEPTSIZ register bit definitions + * @{ + */ +#define DOEPTSIZ_RXDPID_MASK (3U<<29) /**< Received data PID mask. */ +#define DOEPTSIZ_RXDPID(n) ((n)<<29) /**< Received data PID value. */ +#define DOEPTSIZ_STUPCNT_MASK (3U<<29) /**< SETUP packet count mask. */ +#define DOEPTSIZ_STUPCNT(n) ((n)<<29) /**< SETUP packet count value. */ +#define DOEPTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */ +#define DOEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ +#define DOEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */ +#define DOEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ +/** @} */ + +/** + * @name PCGCCTL register bit definitions + * @{ + */ +#define PCGCCTL_PHYSUSP (1U<<4) /**< PHY Suspended. */ +#define PCGCCTL_GATEHCLK (1U<<1) /**< Gate HCLK. */ +#define PCGCCTL_STPPCLK (1U<<0) /**< Stop PCLK. */ +/** @} */ + +#if defined(STM32H7XX) || defined(__DOXYGEN__) +/** + * @brief OTG_FS registers block memory address. + */ +#define OTG_FS_ADDR 0x40080000 + +/** + * @brief OTG_HS registers block memory address. + */ +#define OTG_HS_ADDR 0x40040000 +#else +#define OTG_FS_ADDR 0x50000000 +#define OTG_HS_ADDR 0x40040000 +#endif + +/** + * @brief Accesses to the OTG_FS registers block. + */ +#define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR) + +/** + * @brief Accesses to the OTG_HS registers block. + */ +#define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR) + +#endif /* STM32_OTG_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/driver.mk new file mode 100644 index 0000000..e59aec0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_WSPI TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c new file mode 100644 index 0000000..678339a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c @@ -0,0 +1,375 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file QUADSPIv1//hal_wspi_lld.c + * @brief STM32 WSPI subsystem low level driver source. + * + * @addtogroup WSPI + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define QUADSPI1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_WSPI_QUADSPI1_DMA_STREAM, \ + STM32_QUADSPI1_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief QUADSPI1 driver identifier.*/ +#if STM32_WSPI_USE_QUADSPI1 || defined(__DOXYGEN__) +WSPIDriver WSPID1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Waits for completion of previous operation. + */ +static inline void wspi_lld_sync(WSPIDriver *wspip) { + + while ((wspip->qspi->SR & QUADSPI_SR_BUSY) != 0U) { + } +} + +/** + * @brief Shared service routine. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void wspi_lld_serve_dma_interrupt(WSPIDriver *wspip, uint32_t flags) { + + (void)wspip; + (void)flags; + + /* DMA errors handling.*/ +#if defined(STM32_WSPI_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_WSPI_DMA_ERROR_HOOK(wspip); + } +#endif +} + +/** + * @brief Shared service routine. + * + * @param[in] wspip pointer to the @p WSPIDriver object + */ +static void wspi_lld_serve_interrupt(WSPIDriver *wspip) { + + /* Portable WSPI ISR code defined in the high level driver, note, it is + a macro.*/ + _wspi_isr_code(wspip); + + /* Stop everything, we need to give DMA enough time to complete the ongoing + operation. Race condition hidden here.*/ + while (dmaStreamGetTransactionSize(wspip->dma) > 0U) + ; + + /* Handling of errata: Extra data written in the FIFO at the end of a + read transfer.*/ + if (wspip->state == WSPI_RECEIVE) { + while ((wspip->qspi->SR & QUADSPI_SR_BUSY) != 0U) { + (void) wspip->qspi->DR; + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_WSPI_USE_QUADSPI1 || defined(__DOXYGEN__) +#if !defined(STM32_QUADSPI1_SUPPRESS_ISR) +#if !defined(STM32_QUADSPI1_HANDLER) +#error "STM32_QUADSPI1_HANDLER not defined" +#endif +/** + * @brief STM32_QUADSPI1_HANDLER interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_QUADSPI1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + QUADSPI->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF | + QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF; + + wspi_lld_serve_interrupt(&WSPID1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_QUADSPI1_SUPPRESS_ISR) */ +#endif /* STM32_WSPI_USE_QUADSPI1 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level WSPI driver initialization. + * + * @notapi + */ +void wspi_lld_init(void) { + +#if STM32_WSPI_USE_QUADSPI1 + wspiObjectInit(&WSPID1); + WSPID1.qspi = QUADSPI; + WSPID1.dma = NULL; + WSPID1.dmamode = STM32_DMA_CR_CHSEL(QUADSPI1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_WSPI_QUADSPI1_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_BYTE | + STM32_DMA_CR_MSIZE_BYTE | + STM32_DMA_CR_MINC | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + nvicEnableVector(STM32_QUADSPI1_NUMBER, STM32_WSPI_QUADSPI1_IRQ_PRIORITY); +#endif +} + +/** + * @brief Configures and activates the WSPI peripheral. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @notapi + */ +void wspi_lld_start(WSPIDriver *wspip) { + + /* If in stopped state then full initialization.*/ + if (wspip->state == WSPI_STOP) { +#if STM32_WSPI_USE_QUADSPI1 + if (&WSPID1 == wspip) { + wspip->dma = dmaStreamAllocI(STM32_WSPI_QUADSPI1_DMA_STREAM, + STM32_WSPI_QUADSPI1_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)wspi_lld_serve_dma_interrupt, + (void *)wspip); + osalDbgAssert(wspip->dma != NULL, "unable to allocate stream"); + rccEnableQUADSPI1(true); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(wspip->dma, STM32_DMAMUX1_QUADSPI); +#endif + } +#endif + + /* Common initializations.*/ + dmaStreamSetPeripheral(wspip->dma, &wspip->qspi->DR); + } + + /* WSPI setup and enable.*/ + wspip->qspi->DCR = wspip->config->dcr; + wspip->qspi->CR = ((STM32_WSPI_QUADSPI1_PRESCALER_VALUE - 1U) << 24U) | + QUADSPI_CR_TCIE | QUADSPI_CR_DMAEN | QUADSPI_CR_EN; + wspip->qspi->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF | + QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF; +} + +/** + * @brief Deactivates the WSPI peripheral. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @notapi + */ +void wspi_lld_stop(WSPIDriver *wspip) { + + /* If in ready state then disables the QUADSPI clock.*/ + if (wspip->state == WSPI_READY) { + + /* WSPI disable.*/ + wspip->qspi->CR = 0U; + + /* Releasing the DMA.*/ + dmaStreamFreeI(wspip->dma); + wspip->dma = NULL; + + /* Stopping involved clocks.*/ +#if STM32_WSPI_USE_QUADSPI1 + if (&WSPID1 == wspip) { + rccDisableQUADSPI1(); + } +#endif + } +} + +/** + * @brief Sends a command without data phase. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * + * @notapi + */ +void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp) { + +#if STM32_USE_STM32_D1_WORKAROUND == TRUE + /* If it is a command without address and alternate phases then the command + is sent as an alternate byte, the command phase is suppressed.*/ + if ((cmdp->cfg & (WSPI_CFG_ADDR_MODE_MASK | WSPI_CFG_ALT_MODE_MASK)) == 0U) { + /* The command mode field is copied in the alternate mode field. All + other fields are not used in this scenario.*/ + wspip->qspi->DLR = 0U; + wspip->qspi->ABR = cmdp->cmd; + wspip->qspi->CCR = (cmdp->cfg & WSPI_CFG_CMD_MODE_MASK) << 6U; + return; + } +#endif + wspip->qspi->DLR = 0U; + wspip->qspi->ABR = cmdp->alt; + wspip->qspi->CCR = cmdp->cmd | cmdp->cfg; + if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) { + wspip->qspi->AR = cmdp->addr; + } + + /* Waiting for the previous operation to complete.*/ + wspi_lld_sync(wspip); +} + +/** + * @brief Sends a command with data over the WSPI bus. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, const uint8_t *txbuf) { + + dmaStreamSetMemory0(wspip->dma, txbuf); + dmaStreamSetTransactionSize(wspip->dma, n); + dmaStreamSetMode(wspip->dma, wspip->dmamode | STM32_DMA_CR_DIR_M2P); + + wspip->qspi->DLR = n - 1; + wspip->qspi->ABR = cmdp->alt; + wspip->qspi->CCR = cmdp->cmd | cmdp->cfg; + if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) { + wspip->qspi->AR = cmdp->addr; + } + + dmaStreamEnable(wspip->dma); +} + +/** + * @brief Sends a command then receives data over the WSPI bus. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, uint8_t *rxbuf) { + + dmaStreamSetMemory0(wspip->dma, rxbuf); + dmaStreamSetTransactionSize(wspip->dma, n); + dmaStreamSetMode(wspip->dma, wspip->dmamode | STM32_DMA_CR_DIR_P2M); + + wspip->qspi->DLR = n - 1; + wspip->qspi->ABR = cmdp->alt; + wspip->qspi->CCR = cmdp->cmd | cmdp->cfg | + QUADSPI_CCR_DUMMY_CYCLES(cmdp->dummy) | + QUADSPI_CCR_FMODE_0; + if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) { + wspip->qspi->AR = cmdp->addr; + } + + dmaStreamEnable(wspip->dma); +} + +#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) +/** + * @brief Maps in memory space a WSPI flash device. + * @pre The memory flash device must be initialized appropriately + * before mapping it in memory space. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[out] addrp pointer to the memory start address of the mapped + * flash or @p NULL + * + * @notapi + */ +void wspi_lld_map_flash(WSPIDriver *wspip, + const wspi_command_t *cmdp, + uint8_t **addrp) { + + /* Disabling the DMA request while in memory mapped mode.*/ + wspip->qspi->CR &= ~QUADSPI_CR_DMAEN; + + /* Starting memory mapped mode using the passed parameters.*/ + wspip->qspi->DLR = 0; + wspip->qspi->ABR = 0; + wspip->qspi->AR = 0; + wspip->qspi->CCR = cmdp->cmd | cmdp->cfg | + QUADSPI_CCR_DUMMY_CYCLES(cmdp->dummy) | + QUADSPI_CCR_FMODE_1 | QUADSPI_CCR_FMODE_0; + + /* Mapped flash absolute base address.*/ + if (addrp != NULL) { + *addrp = (uint8_t *)0x90000000; + } +} + +/** + * @brief Unmaps from memory space a WSPI flash device. + * @post The memory flash device must be re-initialized for normal + * commands exchange. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @notapi + */ +void wspi_lld_unmap_flash(WSPIDriver *wspip) { + + /* Aborting memory mapped mode.*/ + wspip->qspi->CR |= QUADSPI_CR_ABORT; + while ((wspip->qspi->CR & QUADSPI_CR_ABORT) != 0U) { + } + + /* Re-enabling DMA request, we are going back to indirect mode.*/ + wspip->qspi->CR |= QUADSPI_CR_DMAEN; +} +#endif /* WSPI_SUPPORTS_MEMMAP == TRUE */ + +#endif /* HAL_USE_WSPI */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.h new file mode 100644 index 0000000..5ebbd06 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.h @@ -0,0 +1,313 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file QUADSPIv1/hal_wspi_lld.h + * @brief STM32 WSPI subsystem low level driver header. + * + * @addtogroup WSPI + * @{ + */ + +#ifndef HAL_WSPI_LLD_H +#define HAL_WSPI_LLD_H + +#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name WSPI implementation capabilities + * @{ + */ +#define WSPI_SUPPORTS_MEMMAP TRUE +#define WSPI_DEFAULT_CFG_MASKS FALSE +/** @} */ + +/** + * @name Transfer options + * @note The low level driver has the option to override the following + * definitions and use its own ones. In must take care to use + * the same name for the same function or compatibility is not + * ensured. + * @note There are the following limitations in this implementation: + * - Eight lines are not supported. + * - DDR mode is only supported for the whole command, separate + * masks are defined but all define the same bit. + * - Only 8 bits instructions are supported. + * . + * @{ + */ +#define WSPI_CFG_CMD_MODE_MASK (3LU << 8LU) +#define WSPI_CFG_CMD_MODE_NONE (0LU << 8LU) +#define WSPI_CFG_CMD_MODE_ONE_LINE (1LU << 8LU) +#define WSPI_CFG_CMD_MODE_TWO_LINES (2LU << 8LU) +#define WSPI_CFG_CMD_MODE_FOUR_LINES (3LU << 8LU) + +#define WSPI_CFG_CMD_DDR (1LU << 31LU) + +#define WSPI_CFG_CMD_SIZE_MASK 0LU +#define WSPI_CFG_CMD_SIZE_8 0LU + +#define WSPI_CFG_ADDR_MODE_MASK (3LU << 10LU) +#define WSPI_CFG_ADDR_MODE_NONE (0LU << 10LU) +#define WSPI_CFG_ADDR_MODE_ONE_LINE (1LU << 10LU) +#define WSPI_CFG_ADDR_MODE_TWO_LINES (2LU << 10LU) +#define WSPI_CFG_ADDR_MODE_FOUR_LINES (3LU << 10LU) + +#define WSPI_CFG_ADDR_DDR (1LU << 31LU) + +#define WSPI_CFG_ADDR_SIZE_MASK (3LU << 12LU) +#define WSPI_CFG_ADDR_SIZE_8 (0LU << 12LU) +#define WSPI_CFG_ADDR_SIZE_16 (1LU << 12LU) +#define WSPI_CFG_ADDR_SIZE_24 (2LU << 12LU) +#define WSPI_CFG_ADDR_SIZE_32 (3LU << 12LU) + +#define WSPI_CFG_ALT_MODE_MASK (3LU << 14LU) +#define WSPI_CFG_ALT_MODE_NONE (0LU << 14LU) +#define WSPI_CFG_ALT_MODE_ONE_LINE (1LU << 14LU) +#define WSPI_CFG_ALT_MODE_TWO_LINES (2LU << 14LU) +#define WSPI_CFG_ALT_MODE_FOUR_LINES (3LU << 14LU) + +#define WSPI_CFG_ALT_DDR (1LU << 31LU) + +#define WSPI_CFG_ALT_SIZE_MASK (3LU << 16LU) +#define WSPI_CFG_ALT_SIZE_8 (0LU << 16LU) +#define WSPI_CFG_ALT_SIZE_16 (1LU << 16LU) +#define WSPI_CFG_ALT_SIZE_24 (2LU << 16LU) +#define WSPI_CFG_ALT_SIZE_32 (3LU << 16LU) + +#define WSPI_CFG_DATA_MODE_MASK (3LU << 24LU) +#define WSPI_CFG_DATA_MODE_NONE (0LU << 24LU) +#define WSPI_CFG_DATA_MODE_ONE_LINE (1LU << 24LU) +#define WSPI_CFG_DATA_MODE_TWO_LINES (2LU << 24LU) +#define WSPI_CFG_DATA_MODE_FOUR_LINES (3LU << 24LU) + +#define WSPI_CFG_DATA_DDR (1LU << 31LU) + +#define WSPI_CFG_SIOO (1LU << 28LU) +/** @} */ + +/** + * @name Helpers for CCR register. + * @{ + */ +#define QUADSPI_CCR_DUMMY_CYCLES_MASK (0x1FLU << 18LU) +#define QUADSPI_CCR_DUMMY_CYCLES(n) ((n) << 18LU) +/** @} */ + +/** + * @name DCR register options + * @{ + */ +#define STM32_DCR_CK_MODE (1U << 0U) +#define STM32_DCR_CSHT_MASK (7U << 8U) +#define STM32_DCR_CSHT(n) ((n) << 8U) +#define STM32_DCR_FSIZE_MASK (31U << 16U) +#define STM32_DCR_FSIZE(n) ((n) << 16U) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief WSPID1 driver enable switch. + * @details If set to @p TRUE the support for QUADSPI1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_WSPI_USE_QUADSPI1) || defined(__DOXYGEN__) +#define STM32_WSPI_USE_QUADSPI1 FALSE +#endif + +/** + * @brief QUADSPI1 prescaler setting. + * @note This is the prescaler divider value 1..256. The maximum frequency + * varies depending on the STM32 model and operating conditions, + * find the details in the data sheet. + */ +#if !defined(STM32_WSPI_QUADSPI1_PRESCALER_VALUE) || defined(__DOXYGEN__) +#define STM32_WSPI_QUADSPI1_PRESCALER_VALUE 1 +#endif + +/** + * @brief QUADSPI1 interrupt priority level setting. + */ +#if !defined(STM32_WSPI_QUADSPI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_QUADSPI1_IRQ_PRIORITY 10 +#endif + +/** + * @brief QUADSPI1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_WSPI_QUADSPI1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_QUADSPI1_DMA_PRIORITY 1 +#endif + +/** + * @brief QUADSPI1 DMA interrupt priority level setting. + */ +#if !defined(STM32_WSPI_QUADSPI1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_QUADSPI1_DMA_IRQ_PRIORITY 10 +#endif + +/** + * @brief QUADSPI DMA error hook. + */ +#if !defined(STM32_WSPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_WSPI_DMA_ERROR_HOOK(qspip) osalSysHalt("DMA failure") +#endif + +/** + * @brief Enables a workaround for a STM32L476 QUADSPI errata. + * @details The document DM00111498 states: "QUADSPI_BK1_IO1 is always an + * input when the command is sent in dual or quad SPI mode". + * This workaround makes commands without address or data phases + * to be sent as alternate bytes. + */ +#if !defined(STM32_USE_STM32_D1_WORKAROUND) || defined(__DOXYGEN__) +#define STM32_USE_STM32_D1_WORKAROUND TRUE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_QUADSPI1) +#define STM32_HAS_QUADSPI1 FALSE +#endif + +#if STM32_WSPI_USE_QUADSPI1 && !STM32_HAS_QUADSPI1 +#error "QUADSPI1 not present in the selected device" +#endif + +#if !STM32_WSPI_USE_QUADSPI1 +#error "WSPI driver activated but no QUADSPI peripheral assigned" +#endif + +#if STM32_WSPI_USE_QUADSPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_QUADSPI1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to QUADSPI1" +#endif + +#if STM32_WSPI_USE_QUADSPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_QUADSPI1_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to QUADSPI1 DMA" +#endif + +#if STM32_WSPI_USE_QUADSPI1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_WSPI_QUADSPI1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to QUADSPI1" +#endif + +#if (STM32_WSPI_QUADSPI1_PRESCALER_VALUE < 1) || \ + (STM32_WSPI_QUADSPI1_PRESCALER_VALUE > 256) +#error "STM32_WSPI_QUADSPI1_PRESCALER_VALUE not within 1..256" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_WSPI_USE_QUADSPI1 && !defined(STM32_WSPI_QUADSPI1_DMA_STREAM) +#error "QUADSPI1 DMA stream not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_WSPI_USE_QUADSPI1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_WSPI_QUADSPI1_DMA_STREAM) +#error "invalid DMA stream associated to QUADSPI1" +#endif + +/* Devices without DMAMUX require an additional check.*/ +#if !STM32_DMA_SUPPORTS_DMAMUX + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_WSPI_USE_QUADSPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_WSPI_QUADSPI1_DMA_STREAM, STM32_QUADSPI1_DMA_MSK) +#error "invalid DMA stream associated to QUADSPI1" +#endif + +#endif /* !STM32_DMA_SUPPORTS_DMAMUX */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the WSPI configuration structure. + */ +#define wspi_lld_config_fields \ + /* DCR register initialization data.*/ \ + uint32_t dcr + +/** + * @brief Low level fields of the WSPI driver structure. + */ +#define wspi_lld_driver_fields \ + /* Pointer to the QUADSPIx registers block.*/ \ + QUADSPI_TypeDef *qspi; \ + /* QUADSPI DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + /* QUADSPI DMA mode bit mask.*/ \ + uint32_t dmamode + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (STM32_WSPI_USE_QUADSPI1 == TRUE) && !defined(__DOXYGEN__) +extern WSPIDriver WSPID1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void wspi_lld_init(void); + void wspi_lld_start(WSPIDriver *wspip); + void wspi_lld_stop(WSPIDriver *wspip); + void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp); + void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, const uint8_t *txbuf); + void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, uint8_t *rxbuf); +#if WSPI_SUPPORTS_MEMMAP == TRUE + void wspi_lld_map_flash(WSPIDriver *wspip, + const wspi_command_t *cmdp, + uint8_t **addrp); + void wspi_lld_unmap_flash(WSPIDriver *wspip); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_WSPI */ + +#endif /* HAL_WSPI_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk new file mode 100644 index 0000000..0a9e099 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_WSPI TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv2 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c new file mode 100644 index 0000000..118556b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c @@ -0,0 +1,356 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file QUADSPIv2//hal_wspi_lld.c + * @brief STM32 WSPI subsystem low level driver source. + * + * @addtogroup WSPI + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief QUADSPI1 driver identifier.*/ +#if STM32_WSPI_USE_QUADSPI1 || defined(__DOXYGEN__) +WSPIDriver WSPID1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Waits for completion of previous operation. + */ +static inline void wspi_lld_sync(WSPIDriver *wspip) { + + while ((wspip->qspi->SR & QUADSPI_SR_BUSY) != 0U) { + } +} + +/** + * @brief Shared service routine. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] flags content of the CISR register + */ +static void wspi_lld_serve_mdma_interrupt(WSPIDriver *wspip, uint32_t flags) { + + (void)wspip; + (void)flags; + + /* DMA errors handling.*/ +#if defined(STM32_WSPI_MDMA_ERROR_HOOK) + if ((flags & STM32_MDMA_CISR_TEIF) != 0) { + STM32_WSPI_MDMA_ERROR_HOOK(wspip); + } +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level WSPI driver initialization. + * + * @notapi + */ +void wspi_lld_init(void) { + +#if STM32_WSPI_USE_QUADSPI1 + wspiObjectInit(&WSPID1); + WSPID1.qspi = QUADSPI; + WSPID1.mdma = NULL; +#endif +} + +/** + * @brief Configures and activates the WSPI peripheral. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @notapi + */ +void wspi_lld_start(WSPIDriver *wspip) { + + /* If in stopped state then full initialization.*/ + if (wspip->state == WSPI_STOP) { +#if STM32_WSPI_USE_QUADSPI1 + if (&WSPID1 == wspip) { + wspip->mdma = mdmaChannelAllocI(STM32_WSPI_QUADSPI1_MDMA_CHANNEL, + (stm32_mdmaisr_t)wspi_lld_serve_mdma_interrupt, + (void *)wspip); + osalDbgAssert(wspip->mdma != NULL, "unable to allocate MDMA channel"); + rccEnableQUADSPI1(true); + } +#endif + } + + /* WSPI setup and enable.*/ + wspip->qspi->DCR = wspip->config->dcr; + wspip->qspi->CR = ((STM32_WSPI_QUADSPI1_PRESCALER_VALUE - 1U) << 24U) | + QUADSPI_CR_TCIE | QUADSPI_CR_DMAEN | QUADSPI_CR_EN; + wspip->qspi->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF | + QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF; +} + +/** + * @brief Deactivates the WSPI peripheral. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @notapi + */ +void wspi_lld_stop(WSPIDriver *wspip) { + + /* If in ready state then disables the QUADSPI clock.*/ + if (wspip->state == WSPI_READY) { + + /* WSPI disable.*/ + wspip->qspi->CR = 0U; + + /* Releasing the DMA.*/ + mdmaChannelFreeI(wspip->mdma); + wspip->mdma = NULL; + + /* Stopping involved clocks.*/ +#if STM32_WSPI_USE_QUADSPI1 + if (&WSPID1 == wspip) { + rccDisableQUADSPI1(); + } +#endif + } +} + +/** + * @brief Sends a command without data phase. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * + * @notapi + */ +void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp) { + +#if STM32_USE_STM32_D1_WORKAROUND == TRUE + /* If it is a command without address and alternate phases then the command + is sent as an alternate byte, the command phase is suppressed.*/ + if ((cmdp->cfg & (WSPI_CFG_ADDR_MODE_MASK | WSPI_CFG_ALT_MODE_MASK)) == 0U) { + /* The command mode field is copied in the alternate mode field. All + other fields are not used in this scenario.*/ + wspip->qspi->DLR = 0U; + wspip->qspi->ABR = cmdp->cmd; + wspip->qspi->CCR = (cmdp->cfg & WSPI_CFG_CMD_MODE_MASK) << 6U; + return; + } +#endif + wspip->qspi->DLR = 0U; + wspip->qspi->ABR = cmdp->alt; + wspip->qspi->CCR = cmdp->cmd | cmdp->cfg; + if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) { + wspip->qspi->AR = cmdp->addr; + } + + /* Waiting for the previous operation to complete.*/ + wspi_lld_sync(wspip); +} + +/** + * @brief Sends a command with data over the WSPI bus. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, const uint8_t *txbuf) { + uint32_t ctcr = STM32_MDMA_CTCR_BWM_NON_BUFF | /* Dest. non-cacheable. */ + STM32_MDMA_CTCR_TRGM_BUFFER | /* Trigger on buffer. */ + STM32_MDMA_CTCR_TLEN(0U) | /* One byte buffer. */ + STM32_MDMA_CTCR_DBURST_16 | /* Assuming AXI bus. */ + STM32_MDMA_CTCR_SBURST_16 | /* Assuming AXI bus. */ + STM32_MDMA_CTCR_DINCOS_BYTE | /* Byte increment. */ + STM32_MDMA_CTCR_SINCOS_BYTE | /* Byte increment. */ + STM32_MDMA_CTCR_DSIZE_BYTE | /* Destination size. */ + STM32_MDMA_CTCR_SSIZE_BYTE | /* Source size. */ + STM32_MDMA_CTCR_DINC_FIXED | /* Destination fixed. */ + STM32_MDMA_CTCR_SINC_INC; /* Source incremented. */ + uint32_t ccr = STM32_MDMA_CCR_PL(STM32_WSPI_QUADSPI1_MDMA_PRIORITY) | + STM32_MDMA_CCR_CTCIE | /* On transfer complete.*/ + STM32_MDMA_CCR_TCIE; /* On transfer error. */ + + /* MDMA initializations.*/ + mdmaChannelSetSourceX(wspip->mdma, &wspip->qspi->DR); + mdmaChannelSetDestinationX(wspip->mdma, txbuf); + mdmaChannelSetTransactionSizeX(wspip->mdma, n, 0, 0); + mdmaChannelSetModeX(wspip->mdma, ctcr, ccr); + + wspip->qspi->DLR = n - 1; + wspip->qspi->ABR = cmdp->alt; + wspip->qspi->CCR = cmdp->cmd | cmdp->cfg; + if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) { + wspip->qspi->AR = cmdp->addr; + } + + mdmaChannelEnableX(wspip->mdma); +} + +/** + * @brief Sends a command then receives data over the WSPI bus. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, uint8_t *rxbuf) { + uint32_t ctcr = STM32_MDMA_CTCR_BWM_NON_BUFF | /* Dest. non-cacheable. */ + STM32_MDMA_CTCR_TRGM_BUFFER | /* Trigger on buffer. */ + STM32_MDMA_CTCR_TLEN(0U) | /* One byte buffer. */ + STM32_MDMA_CTCR_DBURST_16 | /* Assuming AXI bus. */ + STM32_MDMA_CTCR_SBURST_16 | /* Assuming AXI bus. */ + STM32_MDMA_CTCR_DINCOS_BYTE | /* Byte increment. */ + STM32_MDMA_CTCR_SINCOS_BYTE | /* Byte increment. */ + STM32_MDMA_CTCR_DSIZE_BYTE | /* Destination size. */ + STM32_MDMA_CTCR_SSIZE_BYTE | /* Source size. */ + STM32_MDMA_CTCR_DINC_INC | /* Destination incr. */ + STM32_MDMA_CTCR_SINC_FIXED; /* Source fixed. */ + uint32_t ccr = STM32_MDMA_CCR_PL(STM32_WSPI_QUADSPI1_MDMA_PRIORITY) | + STM32_MDMA_CCR_CTCIE | /* On transfer complete.*/ + STM32_MDMA_CCR_TCIE; /* On transfer error. */ + + /* MDMA initializations.*/ + mdmaChannelSetSourceX(wspip->mdma, rxbuf); + mdmaChannelSetDestinationX(wspip->mdma, &wspip->qspi->DR); + mdmaChannelSetTransactionSizeX(wspip->mdma, n, 0, 0); + mdmaChannelSetModeX(wspip->mdma, ctcr, ccr); + + wspip->qspi->DLR = n - 1; + wspip->qspi->ABR = cmdp->alt; + wspip->qspi->CCR = cmdp->cmd | cmdp->cfg | + QUADSPI_CCR_DUMMY_CYCLES(cmdp->dummy) | + QUADSPI_CCR_FMODE_0; + if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) { + wspip->qspi->AR = cmdp->addr; + } + + mdmaChannelEnableX(wspip->mdma); +} + +#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) +/** + * @brief Maps in memory space a WSPI flash device. + * @pre The memory flash device must be initialized appropriately + * before mapping it in memory space. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[out] addrp pointer to the memory start address of the mapped + * flash or @p NULL + * + * @notapi + */ +void wspi_lld_map_flash(WSPIDriver *wspip, + const wspi_command_t *cmdp, + uint8_t **addrp) { + + /* Disabling the DMA request while in memory mapped mode.*/ + wspip->qspi->CR &= ~QUADSPI_CR_DMAEN; + + /* Starting memory mapped mode using the passed parameters.*/ + wspip->qspi->DLR = 0; + wspip->qspi->ABR = 0; + wspip->qspi->AR = 0; + wspip->qspi->CCR = cmdp->cmd | cmdp->cfg | + QUADSPI_CCR_DUMMY_CYCLES(cmdp->dummy) | + QUADSPI_CCR_FMODE_1 | QUADSPI_CCR_FMODE_0; + + /* Mapped flash absolute base address.*/ + if (addrp != NULL) { + *addrp = (uint8_t *)0x90000000; + } +} + +/** + * @brief Unmaps from memory space a WSPI flash device. + * @post The memory flash device must be re-initialized for normal + * commands exchange. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @notapi + */ +void wspi_lld_unmap_flash(WSPIDriver *wspip) { + + /* Aborting memory mapped mode.*/ + wspip->qspi->CR |= QUADSPI_CR_ABORT; + while ((wspip->qspi->CR & QUADSPI_CR_ABORT) != 0U) { + } + + /* Re-enabling DMA request, we are going back to indirect mode.*/ + wspip->qspi->CR |= QUADSPI_CR_DMAEN; +} +#endif /* WSPI_SUPPORTS_MEMMAP == TRUE */ + +/** + * @brief Shared service routine. + * + * @param[in] wspip pointer to the @p WSPIDriver object + */ +void wspi_lld_serve_interrupt(WSPIDriver *wspip) { + + wspip->qspi->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF | + QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF; + + /* Portable WSPI ISR code defined in the high level driver, note, it is + a macro.*/ + _wspi_isr_code(wspip); + + mdmaChannelDisableX(wspip->mdma); +} + +#endif /* HAL_USE_WSPI */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.h new file mode 100644 index 0000000..cf97200 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.h @@ -0,0 +1,279 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file QUADSPIv2/hal_wspi_lld.h + * @brief STM32 WSPI subsystem low level driver header. + * + * @addtogroup WSPI + * @{ + */ + +#ifndef HAL_WSPI_LLD_H +#define HAL_WSPI_LLD_H + +#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name WSPI implementation capabilities + * @{ + */ +#define WSPI_SUPPORTS_MEMMAP TRUE +#define WSPI_DEFAULT_CFG_MASKS FALSE +/** @} */ + +/** + * @name Transfer options + * @note The low level driver has the option to override the following + * definitions and use its own ones. In must take care to use + * the same name for the same function or compatibility is not + * ensured. + * @note There are the following limitations in this implementation: + * - Eight lines are not supported. + * - DDR mode is only supported for the whole command, separate + * masks are defined but all define the same bit. + * - Only 8 bits instructions are supported. + * . + * @{ + */ +#define WSPI_CFG_CMD_MODE_MASK (3LU << 8LU) +#define WSPI_CFG_CMD_MODE_NONE (0LU << 8LU) +#define WSPI_CFG_CMD_MODE_ONE_LINE (1LU << 8LU) +#define WSPI_CFG_CMD_MODE_TWO_LINES (2LU << 8LU) +#define WSPI_CFG_CMD_MODE_FOUR_LINES (3LU << 8LU) + +#define WSPI_CFG_CMD_DDR (1LU << 31LU) + +#define WSPI_CFG_CMD_SIZE_MASK 0LU +#define WSPI_CFG_CMD_SIZE_8 0LU + +#define WSPI_CFG_ADDR_MODE_MASK (3LU << 10LU) +#define WSPI_CFG_ADDR_MODE_NONE (0LU << 10LU) +#define WSPI_CFG_ADDR_MODE_ONE_LINE (1LU << 10LU) +#define WSPI_CFG_ADDR_MODE_TWO_LINES (2LU << 10LU) +#define WSPI_CFG_ADDR_MODE_FOUR_LINES (3LU << 10LU) + +#define WSPI_CFG_ADDR_DDR (1LU << 31LU) + +#define WSPI_CFG_ADDR_SIZE_MASK (3LU << 12LU) +#define WSPI_CFG_ADDR_SIZE_8 (0LU << 12LU) +#define WSPI_CFG_ADDR_SIZE_16 (1LU << 12LU) +#define WSPI_CFG_ADDR_SIZE_24 (2LU << 12LU) +#define WSPI_CFG_ADDR_SIZE_32 (3LU << 12LU) + +#define WSPI_CFG_ALT_MODE_MASK (3LU << 14LU) +#define WSPI_CFG_ALT_MODE_NONE (0LU << 14LU) +#define WSPI_CFG_ALT_MODE_ONE_LINE (1LU << 14LU) +#define WSPI_CFG_ALT_MODE_TWO_LINES (2LU << 14LU) +#define WSPI_CFG_ALT_MODE_FOUR_LINES (3LU << 14LU) + +#define WSPI_CFG_ALT_DDR (1LU << 31LU) + +#define WSPI_CFG_ALT_SIZE_MASK (3LU << 16LU) +#define WSPI_CFG_ALT_SIZE_8 (0LU << 16LU) +#define WSPI_CFG_ALT_SIZE_16 (1LU << 16LU) +#define WSPI_CFG_ALT_SIZE_24 (2LU << 16LU) +#define WSPI_CFG_ALT_SIZE_32 (3LU << 16LU) + +#define WSPI_CFG_DATA_MODE_MASK (3LU << 24LU) +#define WSPI_CFG_DATA_MODE_NONE (0LU << 24LU) +#define WSPI_CFG_DATA_MODE_ONE_LINE (1LU << 24LU) +#define WSPI_CFG_DATA_MODE_TWO_LINES (2LU << 24LU) +#define WSPI_CFG_DATA_MODE_FOUR_LINES (3LU << 24LU) + +#define WSPI_CFG_DATA_DDR (1LU << 31LU) + +#define WSPI_CFG_SIOO (1LU << 28LU) +/** @} */ + +/** + * @name Helpers for CCR register. + * @{ + */ +#define QUADSPI_CCR_DUMMY_CYCLES_MASK (0x1FLU << 18LU) +#define QUADSPI_CCR_DUMMY_CYCLES(n) ((n) << 18LU) +/** @} */ + +/** + * @name DCR register options + * @{ + */ +#define STM32_DCR_CK_MODE (1U << 0U) +#define STM32_DCR_CSHT_MASK (7U << 8U) +#define STM32_DCR_CSHT(n) ((n) << 8U) +#define STM32_DCR_FSIZE_MASK (31U << 16U) +#define STM32_DCR_FSIZE(n) ((n) << 16U) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief WSPID1 driver enable switch. + * @details If set to @p TRUE the support for QUADSPI1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_WSPI_USE_QUADSPI1) || defined(__DOXYGEN__) +#define STM32_WSPI_USE_QUADSPI1 FALSE +#endif + +/** + * @brief QUADSPI1 prescaler setting. + * @note This is the prescaler divider value 1..256. The maximum frequency + * varies depending on the STM32 model and operating conditions, + * find the details in the data sheet. + */ +#if !defined(STM32_WSPI_QUADSPI1_PRESCALER_VALUE) || defined(__DOXYGEN__) +#define STM32_WSPI_QUADSPI1_PRESCALER_VALUE 1 +#endif + +/** + * @brief QUADSPI1 MDMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_WSPI_QUADSPI1_MDMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_WSPI_QUADSPI1_MDMA_PRIORITY 1 +#endif + +/** + * @brief QUADSPI MDMA error hook. + */ +#if !defined(STM32_WSPI_MDMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_WSPI_MDMA_ERROR_HOOK(qspip) osalSysHalt("MDMA failure") +#endif + +/** + * @brief Enables a workaround for a STM32L476 QUADSPI errata. + * @details The document DM00111498 states: "QUADSPI_BK1_IO1 is always an + * input when the command is sent in dual or quad SPI mode". + * This workaround makes commands without address or data phases + * to be sent as alternate bytes. + */ +#if !defined(STM32_USE_STM32_D1_WORKAROUND) || defined(__DOXYGEN__) +#define STM32_USE_STM32_D1_WORKAROUND TRUE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_QUADSPI1) +#define STM32_HAS_QUADSPI1 FALSE +#endif + +#if STM32_WSPI_USE_QUADSPI1 && !STM32_HAS_QUADSPI1 +#error "QUADSPI1 not present in the selected device" +#endif + +#if !STM32_WSPI_USE_QUADSPI1 +#error "WSPI driver activated but no QUADSPI peripheral assigned" +#endif + +/* MDMA-related checks.*/ +#if STM32_WSPI_USE_QUADSPI1 && \ + !STM32_MDMA_IS_VALID_PRIORITY(STM32_WSPI_QUADSPI1_MDMA_PRIORITY) +#error "Invalid MDMA priority assigned to QUADSPI1" +#endif + +/* Checks on prescaler setting.*/ +#if (STM32_WSPI_QUADSPI1_PRESCALER_VALUE < 1) || \ + (STM32_WSPI_QUADSPI1_PRESCALER_VALUE > 256) +#error "STM32_WSPI_QUADSPI1_PRESCALER_VALUE not within 1..256" +#endif + +/* Check on the presence of the DMA channels settings in mcuconf.h.*/ +#if STM32_WSPI_USE_QUADSPI1 && !defined(STM32_WSPI_QUADSPI1_MDMA_CHANNEL) +#error "QUADSPI1 MDMA channel not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_WSPI_USE_QUADSPI1 && \ + !STM32_MDMA_IS_VALID_CHANNEL(STM32_WSPI_QUADSPI1_MDMA_CHANNEL) +#error "invalid MDMA channel associated to QUADSPI1" +#endif + +#if !defined(STM32_MDMA_REQUIRED) +#define STM32_MDMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the WSPI configuration structure. + */ +#define wspi_lld_config_fields \ + /* DCR register initialization data.*/ \ + uint32_t dcr + +/** + * @brief Low level fields of the WSPI driver structure. + */ +#define wspi_lld_driver_fields \ + /* Pointer to the QUADSPIx registers block.*/ \ + QUADSPI_TypeDef *qspi; \ + /* QUADSPI MDMA channel.*/ \ + const stm32_mdma_channel_t *mdma + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (STM32_WSPI_USE_QUADSPI1 == TRUE) && !defined(__DOXYGEN__) +extern WSPIDriver WSPID1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void wspi_lld_init(void); + void wspi_lld_start(WSPIDriver *wspip); + void wspi_lld_stop(WSPIDriver *wspip); + void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp); + void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, const uint8_t *txbuf); + void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, uint8_t *rxbuf); +#if WSPI_SUPPORTS_MEMMAP == TRUE + void wspi_lld_map_flash(WSPIDriver *wspip, + const wspi_command_t *cmdp, + uint8_t **addrp); + void wspi_lld_unmap_flash(WSPIDriver *wspip); +#endif + void wspi_lld_serve_interrupt(WSPIDriver *wspip); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_WSPI */ + +#endif /* HAL_WSPI_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/stm32_quadspi1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/stm32_quadspi1.inc new file mode 100644 index 0000000..371bf77 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/stm32_quadspi1.inc @@ -0,0 +1,110 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file QUADSPIv2/stm32_quadspi1.inc + * @brief Shared QUADSPI1 handler. + * + * @addtogroup STM32_QUADSPI1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_QUADSPI1) +#error "STM32_HAS_QUADSPI1 not defined in registry" +#endif + +#if STM32_HAS_QUADSPI1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_QUADSPI1_PRIORITY) +#error "STM32_IRQ_QUADSPI1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_QUADSPI1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_QUADSPI1_PRIORITY" +#endif + +#endif /* STM32_HAS_QUADSPI1 */ + +/* Other checks.*/ +#if (HAL_USE_WSPI && STM32_WSPI_USE_QUADSPI1) +#define STM32_QUADSPI1_IS_USED TRUE +#else +#define STM32_QUADSPI1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void quadspi1_irq_init(void) { +#if STM32_QUADSPI1_IS_USED + nvicEnableVector(STM32_QUADSPI1_NUMBER, STM32_IRQ_QUADSPI1_PRIORITY); +#endif +} + +static inline void quadspi1_irq_deinit(void) { +#if STM32_QUADSPI1_IS_USED + nvicDisableVector(STM32_QUADSPI1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_QUADSPI1_IS_USED|| defined(__DOXYGEN__) +/** + * @brief QUADSPI1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_QUADSPI1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_WSPI +#if STM32_WSPI_USE_QUADSPI1 + wspi_lld_serve_interrupt(&WSPID1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/driver.mk new file mode 100644 index 0000000..3c90500 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_TRNG TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RNGv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c new file mode 100644 index 0000000..c81e433 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c @@ -0,0 +1,179 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file hal_trng_lld.c + * @brief STM32 TRNG subsystem low level driver source. + * + * @addtogroup TRNG + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief TRNGD1 driver identifier. + */ +#if (STM32_TRNG_USE_RNG1 == TRUE) || defined(__DOXYGEN__) +TRNGDriver TRNGD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const TRNGConfig default_cfg = {.cr = 0}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level TRNG driver initialization. + * + * @notapi + */ +void trng_lld_init(void) { + +#if STM32_TRNG_USE_RNG1 == TRUE + /* Driver initialization.*/ + trngObjectInit(&TRNGD1); + TRNGD1.rng = RNG; +#endif +} + +/** + * @brief Configures and activates the TRNG peripheral. + * + * @param[in] trngp pointer to the @p TRNGDriver object + * + * @notapi + */ +void trng_lld_start(TRNGDriver *trngp) { + + /* There is no real configuration but setting up a valid pointer anyway.*/ + if (trngp->config == NULL) { + trngp->config = &default_cfg; + } + + if (trngp->state == TRNG_STOP) { + /* Enables the peripheral.*/ +#if STM32_TRNG_USE_RNG1 == TRUE + if (&TRNGD1 == trngp) { + rccEnableRNG(false); + } +#endif + } + /* Configures the peripheral.*/ + trngp->rng->CR |= RNG_CR_RNGEN; +} + +/** + * @brief Deactivates the TRNG peripheral. + * + * @param[in] trngp pointer to the @p TRNGDriver object + * + * @notapi + */ +void trng_lld_stop(TRNGDriver *trngp) { + + if (trngp->state == TRNG_READY) { + /* Resets the peripheral.*/ + trngp->rng->CR &= ~RNG_CR_RNGEN; + + /* Disables the peripheral.*/ +#if STM32_TRNG_USE_RNG1 == TRUE + if (&TRNGD1 == trngp) { + rccDisableRNG(); + } +#endif + } +} + +/** + * @brief True random numbers generator. + * @note The function is blocking and likely performs polled waiting + * inside the low level implementation. + * + * @param[in] trngp pointer to the @p TRNGDriver object + * @param[in] size size of output buffer + * @param[out] out output buffer + * @return The operation status. + * @retval false if a random number has been generated. + * @retval true if an HW error occurred. + * + * @api + */ +bool trng_lld_generate(TRNGDriver *trngp, size_t size, uint8_t *out) { + + while (true) { + uint32_t r, tmo; + size_t i; + + /* Waiting for error conditions to be cleared.*/ + tmo = STM32_TRNG_ERROR_CLEAR_ATTEMPTS; + while ((tmo > 0) && ((trngp->rng->SR & (RNG_SR_CECS | RNG_SR_SECS)) != 0)) { + tmo--; + if (tmo == 0) { + return true; + } + } + + /* Waiting for a random number in data register.*/ + tmo = STM32_DATA_FETCH_ATTEMPTS; + while ((tmo > 0) && ((trngp->rng->SR & RNG_SR_DRDY) == 0)) { + tmo--; + if (tmo == 0) { + return true; + } + } + + /* Getting the generated random number.*/ + r = trngp->rng->DR; + + /* Writing in the output buffer.*/ + for (i = 0; i < sizeof (uint32_t) / sizeof (uint8_t); i++) { + *out++ = (uint8_t)r; + r = r >> 8; + size--; + if (size == 0) { + return false; + } + } + } +} + +#endif /* HAL_USE_TRNG == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.h new file mode 100644 index 0000000..2a1e9ba --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.h @@ -0,0 +1,141 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file hal_trng_lld.h + * @brief STM32 TRNG subsystem low level driver header. + * + * @addtogroup TRNG + * @{ + */ + +#ifndef HAL_TRNG_LLD_H +#define HAL_TRNG_LLD_H + +#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name STM32 configuration options + * @{ + */ +/** + * @brief TRNGD1 driver enable switch. + * @details If set to @p TRUE the support for TRNGD1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_TRNG_USE_RNG1) || defined(__DOXYGEN__) +#define STM32_TRNG_USE_RNG1 FALSE +#endif + +/** + * @brief TRNGD1 error clear timeout counter. + * @details Number of status register fetches before failing. + */ +#if !defined(STM32_TRNG_ERROR_CLEAR_ATTEMPTS) || defined(__DOXYGEN__) +#define STM32_TRNG_ERROR_CLEAR_ATTEMPTS 1000 +#endif + +/** + * @brief TRNGD1 data available timeout counter. + * @details Number of status register fetches before failing. + */ +#if !defined(STM32_DATA_FETCH_ATTEMPTS) || defined(__DOXYGEN__) +#define STM32_DATA_FETCH_ATTEMPTS 1000 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_RNG1) +#define STM32_HAS_RNG1 FALSE +#endif + +#if STM32_TRNG_USE_RNG1 && !STM32_HAS_RNG1 +#error "RNG1 not present in the selected device" +#endif + +#if !STM32_TRNG_USE_RNG1 +#error "TRNG driver activated but no RNG peripheral assigned" +#endif + +#if !defined(STM32_RNGCLK) +#error "STM32_RNGCLK not defined in this HAL" +#endif + +#if ((STM32_RNGCLK < 47000000) || (STM32_RNGCLK > 49000000)) && \ + ((STM32_RNGCLK < 3500000) || (STM32_RNGCLK > 4500000)) +#if !defined(STM32_DISABLE_RNG_CLOCK_CHECK) +#error "STM32_RNGCLK is not within a tested clock range" +#error "define STM32_DISABLE_RNG_CLOCK_CHECK to override this check" +#endif +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the TRNG configuration structure. + */ +#define trng_lld_config_fields \ + /* CR register initialization value.*/ \ + uint32_t cr + +/** + * @brief Low level fields of the TRNG driver structure. + */ +#define trng_lld_driver_fields \ + /* Pointer to the RNG registers block.*/ \ + RNG_TypeDef *rng + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (STM32_TRNG_USE_RNG1 == TRUE) && !defined(__DOXYGEN__) +extern TRNGDriver TRNGD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void trng_lld_init(void); + void trng_lld_start(TRNGDriver *trngp); + void trng_lld_stop(TRNGDriver *trngp); + bool trng_lld_generate(TRNGDriver *trngp, size_t size, uint8_t *out); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_TRNG == TRUE */ + +#endif /* HAL_TRNG_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/notes.txt new file mode 100644 index 0000000..8e0c8e5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/notes.txt @@ -0,0 +1,10 @@ +STM32 RNGv1 driver. + +Driver capability: + +- Supports the STM32 TRNGv1 found on STM32L4 and STM32L4+ families. + +The file registry must export: + +STM32_HAS_RNG1 - RNG presence flag. + diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/driver.mk new file mode 100644 index 0000000..972b475 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c new file mode 100644 index 0000000..248a9c3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c @@ -0,0 +1,447 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file RTCv1/hal_rtc_lld.c + * @brief STM32 RTC subsystem low level driver header. + * + * @addtogroup RTC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief RTC driver identifier. + */ +RTCDriver RTCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Wait for synchronization of RTC registers with APB1 bus. + * @details This function must be invoked before trying to read RTC registers + * in the backup domain: DIV, CNT, ALR. CR registers can always + * be read. + * + * @notapi + */ +static void rtc_apb1_sync(void) { + + while ((RTC->CRL & RTC_CRL_RSF) == 0) + ; +} + +/** + * @brief Wait for for previous write operation complete. + * @details This function must be invoked before writing to any RTC registers + * + * @notapi + */ +static void rtc_wait_write_completed(void) { + + while ((RTC->CRL & RTC_CRL_RTOFF) == 0) + ; +} + +/** + * @brief Acquires write access to RTC registers. + * @details Before writing to the backup domain RTC registers the previous + * write operation must be completed. Use this function before + * writing to PRL, CNT, ALR registers. + * + * @notapi + */ +static void rtc_acquire_access(void) { + + rtc_wait_write_completed(); + RTC->CRL |= RTC_CRL_CNF; +} + +/** + * @brief Releases write access to RTC registers. + * + * @notapi + */ +static void rtc_release_access(void) { + + RTC->CRL &= ~RTC_CRL_CNF; +} + +/** + * @brief Converts time from timespec to seconds counter. + * + * @param[in] timespec pointer to a @p RTCDateTime structure + * @return the TR register encoding. + * + * @notapi + */ +static time_t rtc_encode(const RTCDateTime *timespec) { + struct tm tim; + + rtcConvertDateTimeToStructTm(timespec, &tim, NULL); + return mktime(&tim); +} + +/** + * @brief Converts time from seconds/milliseconds to timespec. + * + * @param[in] tv_sec seconds value + * @param[in] tv_msec milliseconds value + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +static void rtc_decode(uint32_t tv_sec, + uint32_t tv_msec, + RTCDateTime *timespec) { + struct tm tim; + struct tm *t; + const time_t time = (const time_t)tv_sec; /* Could be 64 bits.*/ + + /* If the conversion is successful the function returns a pointer + to the object the result was written into.*/ +#if defined(__GNUC__) || defined(__CC_ARM) + t = localtime_r(&time, &tim); + osalDbgAssert(t != NULL, "conversion failed"); +#else + t = localtime(&time); + memcpy(&tim, t, sizeof(struct tm)); +#endif + + rtcConvertStructTmToDateTime(&tim, tv_msec, timespec); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief RTC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC1_HANDLER) { + uint16_t flags; + + OSAL_IRQ_PROLOGUE(); + + /* Code hits this wait only when AHB1 bus was previously powered off by any + reason (standby, reset, etc). In other cases there is no waiting.*/ + rtc_apb1_sync(); + + /* Mask of all enabled and pending sources.*/ + flags = RTCD1.rtc->CRH & RTCD1.rtc->CRL; + RTCD1.rtc->CRL &= ~(RTC_CRL_SECF | RTC_CRL_ALRF | RTC_CRL_OWF); + + if (flags & RTC_CRL_SECF) + RTCD1.callback(&RTCD1, RTC_EVENT_SECOND); + + if (flags & RTC_CRL_ALRF) + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM); + + if (flags & RTC_CRL_OWF) + RTCD1.callback(&RTCD1, RTC_EVENT_OVERFLOW); + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Load value of RTCCLK to prescaler registers. + * @note The pre-scaler must not be set on every reset as RTC clock + * counts are lost when it is set. + * @note This function designed to be called from + * hal_lld_backup_domain_init(). Because there is only place + * where possible to detect BKP domain reset event reliably. + * + * @notapi + */ +void rtc_lld_set_prescaler(void) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + rtc_acquire_access(); + RTC->PRLH = (uint16_t)((STM32_RTCCLK - 1) >> 16) & 0x000F; + RTC->PRLL = (uint16_t)(((STM32_RTCCLK - 1)) & 0xFFFF); + rtc_release_access(); + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Initialize RTC. + * + * @notapi + */ +void rtc_lld_init(void) { + + /* RTC object initialization.*/ + rtcObjectInit(&RTCD1); + + /* RTC pointer initialization.*/ + RTCD1.rtc = RTC; + + /* RSF bit must be cleared by software after an APB1 reset or an APB1 clock + stop. Otherwise its value will not be actual. */ + RTCD1.rtc->CRL &= ~RTC_CRL_RSF; + + /* Required because access to PRL.*/ + rtc_apb1_sync(); + + /* All interrupts initially disabled.*/ + rtc_wait_write_completed(); + RTCD1.rtc->CRH = 0; + + /* Callback initially disabled.*/ + RTCD1.callback = NULL; + + /* IRQ vector permanently assigned to this driver.*/ + nvicEnableVector(STM32_RTC1_NUMBER, STM32_RTC_IRQ_PRIORITY); +} + +/** + * @brief Set current time. + * @note Fractional part will be silently ignored. There is no possibility + * to change it on STM32F1xx platform. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec) { + time_t tv_sec = rtc_encode(timespec); + + rtcSTM32SetSec(rtcp, tv_sec); +} + +/** + * @brief Get current time. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec) { + uint32_t tv_sec, tv_msec; + + rtcSTM32GetSecMsec(rtcp, &tv_sec, &tv_msec); + rtc_decode(tv_sec, tv_msec, timespec); +} + +/** + * @brief Set alarm time. + * + * @note Default value after BKP domain reset is 0xFFFFFFFF + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] alarm alarm identifier + * @param[in] alarmspec pointer to a @p RTCAlarm structure + * + * @notapi + */ +void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm_number, + const RTCAlarm *alarmspec) { + syssts_t sts; + (void)alarm_number; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + rtc_acquire_access(); + if (alarmspec != NULL) { + rtcp->rtc->ALRH = (uint16_t)(alarmspec->tv_sec >> 16); + rtcp->rtc->ALRL = (uint16_t)(alarmspec->tv_sec & 0xFFFF); + } + else { + rtcp->rtc->ALRH = 0; + rtcp->rtc->ALRL = 0; + } + rtc_release_access(); + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Get current alarm. + * @note If an alarm has not been set then the returned alarm specification + * is not meaningful. + * @note The function can be called from any context. + * @note Default value after BKP domain reset is 0xFFFFFFFF. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] alarm alarm identifier + * @param[out] alarmspec pointer to a @p RTCAlarm structure + * + * @notapi + */ +void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm_number, + RTCAlarm *alarmspec) { + syssts_t sts; + (void)alarm_number; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + /* Required because access to ALR.*/ + rtc_apb1_sync(); + + alarmspec->tv_sec = ((rtcp->rtc->ALRH << 16) + rtcp->rtc->ALRL); + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Enables or disables RTC callbacks. + * @details This function enables or disables callbacks, use a @p NULL pointer + * in order to disable a callback. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] callback callback function pointer or @p NULL + * + * @notapi + */ +void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + if (callback != NULL) { + + /* IRQ sources enabled only after setting up the callback.*/ + rtcp->callback = callback; + + rtc_wait_write_completed(); + rtcp->rtc->CRL &= ~(RTC_CRL_OWF | RTC_CRL_ALRF | RTC_CRL_SECF); + rtcp->rtc->CRH = RTC_CRH_OWIE | RTC_CRH_ALRIE | RTC_CRH_SECIE; + } + else { + rtc_wait_write_completed(); + rtcp->rtc->CRH = 0; + + /* Callback set to NULL only after disabling the IRQ sources.*/ + rtcp->callback = NULL; + } + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Get seconds and (optionally) milliseconds from RTC. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] tv_sec pointer to seconds value + * @param[out] tv_msec pointer to milliseconds value, set it + * to @p NULL if not needed + * + * @api + */ +void rtcSTM32GetSecMsec(RTCDriver *rtcp, uint32_t *tv_sec, uint32_t *tv_msec) { + uint32_t time_frac; + syssts_t sts; + + osalDbgCheck((NULL != tv_sec) && (NULL != rtcp)); + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + /* Required because access to CNT and DIV.*/ + rtc_apb1_sync(); + + /* wait for previous write accesses to complete.*/ + rtc_wait_write_completed(); + + /* Loops until two consecutive read returning the same value.*/ + do { + *tv_sec = ((uint32_t)(rtcp->rtc->CNTH) << 16) + rtcp->rtc->CNTL; + time_frac = (((uint32_t)rtcp->rtc->DIVH) << 16) + (uint32_t)rtcp->rtc->DIVL; + } while ((*tv_sec) != (((uint32_t)(rtcp->rtc->CNTH) << 16) + rtcp->rtc->CNTL)); + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); + + if (NULL != tv_msec) + *tv_msec = (((uint32_t)STM32_RTCCLK - 1 - time_frac) * 1000) / STM32_RTCCLK; +} + +/** + * @brief Set seconds in RTC. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] tv_sec seconds value + * + * @api + */ +void rtcSTM32SetSec(RTCDriver *rtcp, uint32_t tv_sec) { + syssts_t sts; + + osalDbgCheck(NULL != rtcp); + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + rtc_acquire_access(); + rtcp->rtc->CNTH = (uint16_t)(tv_sec >> 16); + rtcp->rtc->CNTL = (uint16_t)(tv_sec & 0xFFFF); + rtc_release_access(); + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +#endif /* HAL_USE_RTC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.h new file mode 100644 index 0000000..0926315 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.h @@ -0,0 +1,152 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file RTCv1/hal_rtc_lld.h + * @brief STM32 RTC subsystem low level driver header. + * + * @addtogroup RTC + * @{ + */ + +#ifndef HAL_RTC_LLD_H +#define HAL_RTC_LLD_H + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Implementation capabilities + */ +/** + * @brief This RTC implementation supports callbacks. + */ +#define RTC_SUPPORTS_CALLBACKS TRUE + +/** + * @brief One alarm comparator available. + */ +#define RTC_ALARMS 1 + +/** + * @brief Presence of a local persistent storage. + */ +#define RTC_HAS_STORAGE FALSE +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/* + * RTC driver system settings. + */ +#define STM32_RTC_IRQ_PRIORITY 15 +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if HAL_USE_RTC && !STM32_HAS_RTC +#error "RTC not present in the selected device" +#endif + +#if STM32_RTCCLK == 0 +#error "RTC clock not enabled" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of an RTC event. + */ +typedef enum { + RTC_EVENT_SECOND = 0, /** Triggered every second. */ + RTC_EVENT_ALARM = 1, /** Triggered on alarm. */ + RTC_EVENT_OVERFLOW = 2 /** Triggered on counter overflow. */ +} rtcevent_t; + +/** + * @brief Type of a generic RTC callback. + */ +typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event); + +/** + * @brief Type of a structure representing an RTC alarm time stamp. + */ +typedef struct hal_rtc_alarm { + /** + * @brief Seconds since UNIX epoch. + */ + uint32_t tv_sec; +} RTCAlarm; + +/** + * @brief Implementation-specific @p RTCDriver fields. + */ +#define rtc_lld_driver_fields \ + /* Pointer to the RTC registers block.*/ \ + RTC_TypeDef *rtc; \ + /* Callback pointer.*/ \ + rtccb_t callback + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void rtc_lld_set_prescaler(void); + void rtc_lld_init(void); + void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec); + void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec); + void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm_number, + const RTCAlarm *alarmspec); + void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm_number, + RTCAlarm *alarmspec); + void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback); + void rtcSTM32GetSecMsec(RTCDriver *rtcp, uint32_t *tv_sec, uint32_t *tv_msec); + void rtcSTM32SetSec(RTCDriver *rtcp, uint32_t tv_sec); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_RTC */ + +#endif /* HAL_RTC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/driver.mk new file mode 100644 index 0000000..25ef11d --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c new file mode 100644 index 0000000..aa8bb5e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c @@ -0,0 +1,843 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file RTCv2/hal_rtc_lld.c + * @brief STM32 RTC low level driver. + * + * @addtogroup RTC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define RTC_TR_PM_OFFSET 22 +#define RTC_TR_HT_OFFSET 20 +#define RTC_TR_HU_OFFSET 16 +#define RTC_TR_MNT_OFFSET 12 +#define RTC_TR_MNU_OFFSET 8 +#define RTC_TR_ST_OFFSET 4 +#define RTC_TR_SU_OFFSET 0 + +#define RTC_DR_YT_OFFSET 20 +#define RTC_DR_YU_OFFSET 16 +#define RTC_DR_WDU_OFFSET 13 +#define RTC_DR_MT_OFFSET 12 +#define RTC_DR_MU_OFFSET 8 +#define RTC_DR_DT_OFFSET 4 +#define RTC_DR_DU_OFFSET 0 + +#define RTC_CR_BKP_OFFSET 18 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief RTC driver identifier. + */ +RTCDriver RTCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Beginning of configuration procedure. + * + * @notapi + */ +static void rtc_enter_init(void) { + + RTCD1.rtc->ISR |= RTC_ISR_INIT; + while ((RTCD1.rtc->ISR & RTC_ISR_INITF) == 0) + ; +} + +/** + * @brief Finalizing of configuration procedure. + * + * @notapi + */ +static inline void rtc_exit_init(void) { + + RTCD1.rtc->ISR &= ~RTC_ISR_INIT; +} + +/** + * @brief Converts time from TR register encoding to timespec. + * + * @param[in] tr TR register value + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +static void rtc_decode_time(uint32_t tr, RTCDateTime *timespec) { + uint32_t n; + + n = ((tr >> RTC_TR_HT_OFFSET) & 3) * 36000000; + n += ((tr >> RTC_TR_HU_OFFSET) & 15) * 3600000; + n += ((tr >> RTC_TR_MNT_OFFSET) & 7) * 600000; + n += ((tr >> RTC_TR_MNU_OFFSET) & 15) * 60000; + n += ((tr >> RTC_TR_ST_OFFSET) & 7) * 10000; + n += ((tr >> RTC_TR_SU_OFFSET) & 15) * 1000; + timespec->millisecond = n; +} + +/** + * @brief Converts date from DR register encoding to timespec. + * + * @param[in] dr DR register value + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +static void rtc_decode_date(uint32_t dr, RTCDateTime *timespec) { + + timespec->year = (((dr >> RTC_DR_YT_OFFSET) & 15) * 10) + + ((dr >> RTC_DR_YU_OFFSET) & 15); + timespec->month = (((dr >> RTC_TR_MNT_OFFSET) & 1) * 10) + + ((dr >> RTC_TR_MNU_OFFSET) & 15); + timespec->day = (((dr >> RTC_DR_DT_OFFSET) & 3) * 10) + + ((dr >> RTC_DR_DU_OFFSET) & 15); + timespec->dayofweek = (dr >> RTC_DR_WDU_OFFSET) & 7; +} + +/** + * @brief Converts time from timespec to TR register encoding. + * + * @param[in] timespec pointer to a @p RTCDateTime structure + * @return the TR register encoding. + * + * @notapi + */ +static uint32_t rtc_encode_time(const RTCDateTime *timespec) { + uint32_t n, tr = 0; + + /* Subseconds cannot be set.*/ + n = timespec->millisecond / 1000; + + /* Seconds conversion.*/ + tr = tr | ((n % 10) << RTC_TR_SU_OFFSET); + n /= 10; + tr = tr | ((n % 6) << RTC_TR_ST_OFFSET); + n /= 6; + + /* Minutes conversion.*/ + tr = tr | ((n % 10) << RTC_TR_MNU_OFFSET); + n /= 10; + tr = tr | ((n % 6) << RTC_TR_MNT_OFFSET); + n /= 6; + + /* Hours conversion.*/ + tr = tr | ((n % 10) << RTC_TR_HU_OFFSET); + n /= 10; + tr = tr | (n << RTC_TR_HT_OFFSET); + + return tr; +} + +/** + * @brief Converts a date from timespec to DR register encoding. + * + * @param[in] timespec pointer to a @p RTCDateTime structure + * @return the DR register encoding. + * + * @notapi + */ +static uint32_t rtc_encode_date(const RTCDateTime *timespec) { + uint32_t n, dr = 0; + + /* Year conversion. Note, only years last two digits are considered.*/ + n = timespec->year; + dr = dr | ((n % 10) << RTC_DR_YU_OFFSET); + n /= 10; + dr = dr | ((n % 10) << RTC_DR_YT_OFFSET); + + /* Months conversion.*/ + n = timespec->month; + dr = dr | ((n % 10) << RTC_DR_MU_OFFSET); + n /= 10; + dr = dr | ((n % 10) << RTC_DR_MT_OFFSET); + + /* Days conversion.*/ + n = timespec->day; + dr = dr | ((n % 10) << RTC_DR_DU_OFFSET); + n /= 10; + dr = dr | ((n % 10) << RTC_DR_DT_OFFSET); + + /* Days of week conversion.*/ + dr = dr | (timespec->dayofweek << RTC_DR_WDU_OFFSET); + + return dr; +} + +#if RTC_HAS_STORAGE == TRUE +static size_t _getsize(void *instance) { + + (void)instance; + + return (size_t)STM32_RTC_STORAGE_SIZE; +} + +static ps_error_t _read(void *instance, ps_offset_t offset, + size_t n, uint8_t *rp) { + volatile uint32_t *bkpr = &((RTCDriver *)instance)->rtc->BKP0R; + unsigned i; + + chDbgCheck((instance != NULL) && (rp != NULL)); + chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE)); + chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) && + (offset + n <= STM32_RTC_STORAGE_SIZE)); + + for (i = 0; i < (unsigned)n; i++) { + unsigned index = ((unsigned)offset + i) / sizeof (uint32_t); + unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t); + *rp++ = (uint8_t)(bkpr[index] >> (shift * 8U)); + } + + return PS_NO_ERROR; +} + +static ps_error_t _write(void *instance, ps_offset_t offset, + size_t n, const uint8_t *wp) { + volatile uint32_t *bkpr = &((RTCDriver *)instance)->rtc->BKP0R; + unsigned i; + + chDbgCheck((instance != NULL) && (wp != NULL)); + chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE)); + chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) && + (offset + n <= STM32_RTC_STORAGE_SIZE)); + + for (i = 0; i < (unsigned)n; i++) { + unsigned index = ((unsigned)offset + i) / sizeof (uint32_t); + unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t); + uint32_t regval = bkpr[index]; + regval &= ~(0xFFU << (shift * 8U)); + regval |= (uint32_t)*wp++ << (shift * 8U); + bkpr[index] = regval; + } + + return PS_NO_ERROR; +} + +/** + * @brief VMT for the RTC storage file interface. + */ +struct RTCDriverVMT _rtc_lld_vmt = { + (size_t)0, + _getsize, _read, _write +}; +#endif /* RTC_HAS_STORAGE == TRUE */ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_RTC_COMMON_HANDLER) +#if !defined(STM32_RTC_SUPPRESS_COMMON_ISR) +/** + * @brief RTC common interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC_COMMON_HANDLER) { + uint32_t isr, clear; + + OSAL_IRQ_PROLOGUE(); + + clear = (0U + | RTC_ISR_TSF + | RTC_ISR_TSOVF +#if defined(RTC_ISR_TAMP1F) + | RTC_ISR_TAMP1F +#endif +#if defined(RTC_ISR_TAMP2F) + | RTC_ISR_TAMP2F +#endif +#if defined(RTC_ISR_TAMP3F) + | RTC_ISR_TAMP3F +#endif +#if defined(RTC_ISR_WUTF) + | RTC_ISR_WUTF +#endif +#if defined(RTC_ISR_ALRAF) + | RTC_ISR_ALRAF +#endif +#if defined(RTC_ISR_ALRBF) + | RTC_ISR_ALRBF +#endif + ); + + isr = RTCD1.rtc->ISR; + RTCD1.rtc->ISR = isr & ~clear; + + extiClearGroup1(EXTI_MASK1(STM32_RTC_ALARM_EXTI) | + EXTI_MASK1(STM32_RTC_TAMP_STAMP_EXTI) | + EXTI_MASK1(STM32_RTC_WKUP_EXTI)); + + if (RTCD1.callback != NULL) { + uint32_t cr = RTCD1.rtc->CR; + uint32_t tcr; + +#if defined(RTC_ISR_WUTF) + if (((cr & RTC_CR_WUTIE) != 0U) && ((isr & RTC_ISR_WUTF) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_WAKEUP); + } +#endif + +#if defined(RTC_ISR_ALRAF) + if (((cr & RTC_CR_ALRAIE) != 0U) && ((isr & RTC_ISR_ALRAF) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_A); + } +#endif +#if defined(RTC_ISR_ALRBF) + if (((cr & RTC_CR_ALRBIE) != 0U) && ((isr & RTC_ISR_ALRBF) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_B); + } +#endif + + if ((cr & RTC_CR_TSIE) != 0U) { + if ((isr & RTC_ISR_TSF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TS); + } + if ((isr & RTC_ISR_TSOVF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TS_OVF); + } + } + + /* This part is different depending on if the RTC has a TAMPCR or TAFCR + register.*/ +#if defined(RTC_TAFCR_TAMP1E) + tcr = RTCD1.rtc->TAFCR; + if ((tcr & RTC_TAFCR_TAMPIE) != 0U) { +#if defined(RTC_ISR_TAMP1F) + if ((isr & RTC_ISR_TAMP1F) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1); + } +#endif +#if defined(RTC_ISR_TAMP2F) + if ((isr & RTC_ISR_TAMP2F) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2); + } +#endif + } + +#else /* !defined(RTC_TAFCR_TAMP1E) */ + tcr = RTCD1.rtc->TAMPCR; +#if defined(RTC_ISR_TAMP1F) + if (((tcr & RTC_TAMPCR_TAMP1IE) != 0U) && + ((isr & RTC_ISR_TAMP1F) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1); + } +#endif +#if defined(RTC_ISR_TAMP2F) + if (((tcr & RTC_TAMPCR_TAMP2IE) != 0U) && + ((isr & RTC_ISR_TAMP2F) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2); + } +#endif +#if defined(RTC_ISR_TAMP3F) + if (((tcr & RTC_TAMPCR_TAMP3IE) != 0U) && + ((isr & RTC_ISR_TAMP3F) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP3); + } +#endif +#endif /* !defined(RTC_TAFCR_TAMP1E) */ + } + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_RTC_SUPPRESS_COMMON_ISR) */ + +#elif defined(STM32_RTC_TAMP_STAMP_HANDLER) && \ + defined(STM32_RTC_WKUP_HANDLER) && \ + defined(STM32_RTC_ALARM_HANDLER) +/** + * @brief RTC TAMP/STAMP interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC_TAMP_STAMP_HANDLER) { + uint32_t isr, clear; + + OSAL_IRQ_PROLOGUE(); + + clear = (0U + | RTC_ISR_TSF + | RTC_ISR_TSOVF +#if defined(RTC_ISR_TAMP1F) + | RTC_ISR_TAMP1F +#endif +#if defined(RTC_ISR_TAMP2F) + | RTC_ISR_TAMP2F +#endif +#if defined(RTC_ISR_TAMP3F) + | RTC_ISR_TAMP3F +#endif + ); + + isr = RTCD1.rtc->ISR; + RTCD1.rtc->ISR = isr & ~clear; + + extiClearGroup1(EXTI_MASK1(STM32_RTC_TAMP_STAMP_EXTI)); + + if (RTCD1.callback != NULL) { + uint32_t cr, tcr; + + cr = RTCD1.rtc->CR; + if ((cr & RTC_CR_TSIE) != 0U) { + if ((isr & RTC_ISR_TSF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TS); + } + if ((isr & RTC_ISR_TSOVF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TS_OVF); + } + } + + /* This part is different depending on if the RTC has a TAMPCR or TAFCR + register.*/ +#if defined(RTC_TAFCR_TAMP1E) + tcr = RTCD1.rtc->TAFCR; + if ((tcr & RTC_TAFCR_TAMPIE) != 0U) { +#if defined(RTC_ISR_TAMP1F) + if ((isr & RTC_ISR_TAMP1F) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1); + } +#endif +#if defined(RTC_ISR_TAMP2F) + if ((isr & RTC_ISR_TAMP2F) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2); + } +#endif + } + +#else /* !defined(RTC_TAFCR_TAMP1E) */ + tcr = RTCD1.rtc->TAMPCR; +#if defined(RTC_ISR_TAMP1F) + if (((tcr & RTC_TAMPCR_TAMP1IE) != 0U) && + ((isr & RTC_ISR_TAMP1F) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1); + } +#endif +#if defined(RTC_ISR_TAMP2F) + if (((tcr & RTC_TAMPCR_TAMP2IE) != 0U) && + ((isr & RTC_ISR_TAMP2F) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2); + } +#endif +#if defined(RTC_ISR_TAMP3F) + if (((tcr & RTC_TAMPCR_TAMP3IE) != 0U) && + ((isr & RTC_ISR_TAMP3F) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP3); + } +#endif +#endif /* !defined(RTC_TAFCR_TAMP1E) */ + } + + OSAL_IRQ_EPILOGUE(); +} +/** + * @brief RTC wakeup interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC_WKUP_HANDLER) { + uint32_t isr; + + OSAL_IRQ_PROLOGUE(); + + isr = RTCD1.rtc->ISR; + RTCD1.rtc->ISR = isr & ~RTC_ISR_WUTF; + + extiClearGroup1(EXTI_MASK1(STM32_RTC_WKUP_EXTI)); + + if (RTCD1.callback != NULL) { + uint32_t cr = RTCD1.rtc->CR; + + if (((cr & RTC_CR_WUTIE) != 0U) && ((isr & RTC_ISR_WUTF) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_WAKEUP); + } + } + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief RTC alarm interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC_ALARM_HANDLER) { + uint32_t isr, clear; + + OSAL_IRQ_PROLOGUE(); + + clear = (0U +#if defined(RTC_ISR_ALRAF) + | RTC_ISR_ALRAF +#endif +#if defined(RTC_ISR_ALRBF) + | RTC_ISR_ALRBF +#endif + ); + + isr = RTCD1.rtc->ISR; + RTCD1.rtc->ISR = isr & ~clear; + + extiClearGroup1(EXTI_MASK1(STM32_RTC_ALARM_EXTI)); + + if (RTCD1.callback != NULL) { + uint32_t cr = RTCD1.rtc->CR; +#if defined(RTC_ISR_ALRAF) + if (((cr & RTC_CR_ALRAIE) != 0U) && ((isr & RTC_ISR_ALRAF) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_A); + } +#endif +#if defined(RTC_ISR_ALRBF) + if (((cr & RTC_CR_ALRBIE) != 0U) && ((isr & RTC_ISR_ALRBF) != 0U)) { + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_B); + } +#endif + } + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "missing required RTC handlers definitions in registry" +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Enable access to registers. + * + * @notapi + */ +void rtc_lld_init(void) { + + /* RTC object initialization.*/ + rtcObjectInit(&RTCD1); + + /* RTC pointer initialization.*/ + RTCD1.rtc = RTC; + + /* Disable write protection. */ + RTCD1.rtc->WPR = 0xCA; + RTCD1.rtc->WPR = 0x53; + + /* If calendar has not been initialized yet then proceed with the + initial setup.*/ + if (!(RTCD1.rtc->ISR & RTC_ISR_INITS)) { + + rtc_enter_init(); + + RTCD1.rtc->CR = STM32_RTC_CR_INIT; +#if defined(RTC_TAFCR_TAMP1E) + RTCD1.rtc->TAFCR = STM32_RTC_TAMPCR_INIT; +#else + RTCD1.rtc->TAMPCR = STM32_RTC_TAMPCR_INIT; +#endif + RTCD1.rtc->ISR = RTC_ISR_INIT; /* Clearing all but RTC_ISR_INIT. */ + RTCD1.rtc->PRER = STM32_RTC_PRER_BITS; + RTCD1.rtc->PRER = STM32_RTC_PRER_BITS; + + rtc_exit_init(); + } + else { + RTCD1.rtc->ISR &= ~RTC_ISR_RSF; + } + + /* Callback initially disabled.*/ + RTCD1.callback = NULL; + + /* Enabling RTC-related EXTI lines.*/ + extiEnableGroup1(EXTI_MASK1(STM32_RTC_ALARM_EXTI) | + EXTI_MASK1(STM32_RTC_TAMP_STAMP_EXTI) | + EXTI_MASK1(STM32_RTC_WKUP_EXTI), + EXTI_MODE_RISING_EDGE | EXTI_MODE_ACTION_INTERRUPT); + + /* IRQ vectors permanently assigned to this driver.*/ + STM32_RTC_IRQ_ENABLE(); +} + +/** + * @brief Set current time. + * @note Fractional part will be silently ignored. There is no possibility + * to set it on STM32 platform. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec) { + uint32_t dr, tr; + syssts_t sts; + + tr = rtc_encode_time(timespec); + dr = rtc_encode_date(timespec); + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + /* Writing the registers.*/ + rtc_enter_init(); + rtcp->rtc->TR = tr; + rtcp->rtc->DR = dr; + rtcp->rtc->CR = (rtcp->rtc->CR & ~(1U << RTC_CR_BKP_OFFSET)) | + (timespec->dstflag << RTC_CR_BKP_OFFSET); + rtc_exit_init(); + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Get current time. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec) { + uint32_t dr, tr, cr; + uint32_t subs; +#if STM32_RTC_HAS_SUBSECONDS + uint32_t ssr; +#endif /* STM32_RTC_HAS_SUBSECONDS */ + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + /* Synchronization with the RTC and reading the registers, note + DR must be read last.*/ + while ((rtcp->rtc->ISR & RTC_ISR_RSF) == 0) + ; +#if STM32_RTC_HAS_SUBSECONDS + ssr = rtcp->rtc->SSR; +#endif /* STM32_RTC_HAS_SUBSECONDS */ + tr = rtcp->rtc->TR; + dr = rtcp->rtc->DR; + cr = rtcp->rtc->CR; + rtcp->rtc->ISR &= ~RTC_ISR_RSF; + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); + + /* Decoding day time, this starts the atomic read sequence, see "Reading + the calendar" in the RTC documentation.*/ + rtc_decode_time(tr, timespec); + + /* If the RTC is capable of sub-second counting then the value is + normalized in milliseconds and added to the time.*/ +#if STM32_RTC_HAS_SUBSECONDS + subs = (((STM32_RTC_PRESS_VALUE - 1U) - ssr) * 1000U) / STM32_RTC_PRESS_VALUE; +#else + subs = 0; +#endif /* STM32_RTC_HAS_SUBSECONDS */ + timespec->millisecond += subs; + + /* Decoding date, this concludes the atomic read sequence.*/ + rtc_decode_date(dr, timespec); + + /* Retrieving the DST bit.*/ + timespec->dstflag = (cr >> RTC_CR_BKP_OFFSET) & 1; +} + +#if (RTC_ALARMS > 0) || defined(__DOXYGEN__) +/** + * @brief Set alarm time. + * @note Default value after BKP domain reset for both comparators is 0. + * @note Function does not performs any checks of alarm time validity. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure. + * @param[in] alarm alarm identifier. Can be 0 or 1. + * @param[in] alarmspec pointer to a @p RTCAlarm structure. + * + * @notapi + */ +void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + if (alarm == 0) { + if (alarmspec != NULL) { + rtcp->rtc->CR &= ~RTC_CR_ALRAE; + while (!(rtcp->rtc->ISR & RTC_ISR_ALRAWF)) + ; + rtcp->rtc->ALRMAR = alarmspec->alrmr; + rtcp->rtc->CR |= RTC_CR_ALRAE; + rtcp->rtc->CR |= RTC_CR_ALRAIE; + } + else { + rtcp->rtc->CR &= ~RTC_CR_ALRAIE; + rtcp->rtc->CR &= ~RTC_CR_ALRAE; + } + } +#if RTC_ALARMS > 1 + else { + if (alarmspec != NULL) { + rtcp->rtc->CR &= ~RTC_CR_ALRBE; + while (!(rtcp->rtc->ISR & RTC_ISR_ALRBWF)) + ; + rtcp->rtc->ALRMBR = alarmspec->alrmr; + rtcp->rtc->CR |= RTC_CR_ALRBE; + rtcp->rtc->CR |= RTC_CR_ALRBIE; + } + else { + rtcp->rtc->CR &= ~RTC_CR_ALRBIE; + rtcp->rtc->CR &= ~RTC_CR_ALRBE; + } + } +#endif /* RTC_ALARMS > 1 */ + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Get alarm time. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] alarm alarm identifier. Can be 0 or 1. + * @param[out] alarmspec pointer to a @p RTCAlarm structure + * + * @notapi + */ +void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec) { + + if (alarm == 0) + alarmspec->alrmr = rtcp->rtc->ALRMAR; +#if RTC_ALARMS > 1 + else + alarmspec->alrmr = rtcp->rtc->ALRMBR; +#endif /* RTC_ALARMS > 1 */ +} +#endif /* RTC_ALARMS > 0 */ + +/** + * @brief Enables or disables RTC callbacks. + * @details This function enables or disables callbacks, use a @p NULL pointer + * in order to disable a callback. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] callback callback function pointer or @p NULL + * + * @notapi + */ +void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) { + + rtcp->callback = callback; +} + +#if STM32_RTC_HAS_PERIODIC_WAKEUPS || defined(__DOXYGEN__) +/** + * @brief Sets time of periodic wakeup. + * @note Default value after BKP domain reset is 0x0000FFFF + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] wakeupspec pointer to a @p RTCWakeup structure + * + * @api + */ +void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + if (wakeupspec != NULL) { + osalDbgCheck(wakeupspec->wutr != 0x30000); + + rtcp->rtc->CR &= ~RTC_CR_WUTE; + rtcp->rtc->CR &= ~RTC_CR_WUTIE; + while (!(rtcp->rtc->ISR & RTC_ISR_WUTWF)) + ; + rtcp->rtc->WUTR = wakeupspec->wutr & 0xFFFF; + rtcp->rtc->CR &= ~RTC_CR_WUCKSEL; + rtcp->rtc->CR |= (wakeupspec->wutr >> 16) & RTC_CR_WUCKSEL; + rtcp->rtc->CR |= RTC_CR_WUTIE; + rtcp->rtc->CR |= RTC_CR_WUTE; + } + else { + rtcp->rtc->CR &= ~RTC_CR_WUTE; + rtcp->rtc->CR &= ~RTC_CR_WUTIE; + } + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Gets time of periodic wakeup. + * @note Default value after BKP domain reset is 0x0000FFFF + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] wakeupspec pointer to a @p RTCWakeup structure + * + * @api + */ +void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + wakeupspec->wutr = 0; + wakeupspec->wutr |= rtcp->rtc->WUTR; + wakeupspec->wutr |= (((uint32_t)rtcp->rtc->CR) & 0x7) << 16; + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} +#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */ + +#endif /* HAL_USE_RTC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.h new file mode 100644 index 0000000..f60e798 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.h @@ -0,0 +1,249 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file RTCv2/hal_rtc_lld.h + * @brief STM32 RTC low level driver header. + * + * @addtogroup RTC + * @{ + */ + +#ifndef HAL_RTC_LLD_H +#define HAL_RTC_LLD_H + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Implementation capabilities + */ +/** + * @brief Callback support int the driver. + */ +#define RTC_SUPPORTS_CALLBACKS TRUE + +/** + * @brief Number of alarms available. + */ +#define RTC_ALARMS STM32_RTC_NUM_ALARMS + +/** + * @brief Presence of a local persistent storage. + */ +#define RTC_HAS_STORAGE (STM32_RTC_STORAGE_SIZE > 0) +/** @} */ + +/** + * @brief RTC PRER register initializer. + */ +#define RTC_PRER(a, s) ((((a) - 1) << 16) | ((s) - 1)) + +/** + * @name Alarm helper macros + * @{ + */ +#define RTC_ALRM_MSK4 (1U << 31) +#define RTC_ALRM_WDSEL (1U << 30) +#define RTC_ALRM_DT(n) ((n) << 28) +#define RTC_ALRM_DU(n) ((n) << 24) +#define RTC_ALRM_MSK3 (1U << 23) +#define RTC_ALRM_HT(n) ((n) << 20) +#define RTC_ALRM_HU(n) ((n) << 16) +#define RTC_ALRM_MSK2 (1U << 15) +#define RTC_ALRM_MNT(n) ((n) << 12) +#define RTC_ALRM_MNU(n) ((n) << 8) +#define RTC_ALRM_MSK1 (1U << 7) +#define RTC_ALRM_ST(n) ((n) << 4) +#define RTC_ALRM_SU(n) ((n) << 0) +/** @} */ + +/* Requires services from the EXTI driver.*/ +#if !defined(STM32_EXTI_REQUIRED) +#define STM32_EXTI_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief RTC PRES register initialization. + * @note The default is calculated for a 32768Hz clock. + */ +#if !defined(STM32_RTC_PRESA_VALUE) || defined(__DOXYGEN__) +#define STM32_RTC_PRESA_VALUE 32 +#endif + +/** + * @brief RTC PRESS divider initialization. + * @note The default is calculated for a 32768Hz clock. + */ +#if !defined(STM32_RTC_PRESS_VALUE) || defined(__DOXYGEN__) +#define STM32_RTC_PRESS_VALUE 1024 +#endif + +/** + * @brief RTC CR register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + */ +#if !defined(STM32_RTC_CR_INIT) || defined(__DOXYGEN__) +#define STM32_RTC_CR_INIT 0 +#endif + +/** + * @brief RTC TAMPCR register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + * @note On some devices this values goes in the similar TAFCR register. + */ +#if !defined(STM32_RTC_TAMPCR_INIT) || defined(__DOXYGEN__) +#define STM32_RTC_TAMPCR_INIT 0 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if HAL_USE_RTC && !STM32_HAS_RTC +#error "RTC not present in the selected device" +#endif + +#if defined(STM32_RTC_CK) && !defined(STM32_RTCCLK) +#define STM32_RTCCLK STM32_RTC_CK +#endif + +#if !defined(STM32_RTCCLK) +#error "RTC clock not exported by HAL layer" +#endif + +#if STM32_PCLK1 < (STM32_RTCCLK * 7) +#error "STM32_PCLK1 frequency is too low" +#endif + +/** + * @brief Initialization for the RTC_PRER register. + */ +#define STM32_RTC_PRER_BITS RTC_PRER(STM32_RTC_PRESA_VALUE, \ + STM32_RTC_PRESS_VALUE) + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of an RTC event. + */ +typedef enum { + RTC_EVENT_ALARM_A = 0, /** Alarm A. */ + RTC_EVENT_ALARM_B = 1, /** Alarm B. */ + RTC_EVENT_TS = 2, /** Time stamp. */ + RTC_EVENT_TS_OVF = 3, /** Time stamp overflow. */ + RTC_EVENT_TAMP1 = 4, /** Tamper 1. */ + RTC_EVENT_TAMP2 = 5, /** Tamper 2- */ + RTC_EVENT_TAMP3 = 6, /** Tamper 3. */ + RTC_EVENT_WAKEUP = 7 /** Wakeup. */ + } rtcevent_t; + +/** + * @brief Type of a generic RTC callback. + */ +typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event); + +/** + * @brief Type of a structure representing an RTC alarm time stamp. + */ +typedef struct hal_rtc_alarm { + /** + * @brief Type of an alarm as encoded in RTC ALRMxR registers. + */ + uint32_t alrmr; +} RTCAlarm; + +#if STM32_RTC_HAS_PERIODIC_WAKEUPS +/** + * @brief Type of a wakeup as encoded in RTC WUTR register. + */ +typedef struct hal_rtc_wakeup { + /** + * @brief Wakeup as encoded in RTC WUTR register. + * @note ((WUTR == 0) || (WUCKSEL == 3)) are a forbidden combination. + * @note Bits 16..18 are copied in the CR bits 0..2 (WUCKSEL). + */ + uint32_t wutr; +} RTCWakeup; +#endif + +/** + * @brief Implementation-specific @p RTCDriver fields. + */ +#define rtc_lld_driver_fields \ + /* Pointer to the RTC registers block.*/ \ + RTC_TypeDef *rtc; \ + /* Callback pointer.*/ \ + rtccb_t callback + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void rtc_lld_init(void); + void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec); + void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec); +#if RTC_SUPPORTS_CALLBACKS == TRUE + void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback); +#endif +#if RTC_ALARMS > 0 + void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec); + void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec); +#endif +#if STM32_RTC_HAS_PERIODIC_WAKEUPS + void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec); + void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec); +#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */ +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_RTC */ + +#endif /* HAL_RTC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/driver.mk new file mode 100644 index 0000000..be3a5ad --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c new file mode 100644 index 0000000..6f776f3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c @@ -0,0 +1,717 @@ +/* + ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file RTCv3/hal_rtc_lld.c + * @brief STM32 RTC low level driver. + * + * @addtogroup RTC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define RTC_TR_PM_OFFSET RTC_TR_PM_Pos +#define RTC_TR_HT_OFFSET RTC_TR_HT_Pos +#define RTC_TR_HU_OFFSET RTC_TR_HU_Pos +#define RTC_TR_MNT_OFFSET RTC_TR_MNT_Pos +#define RTC_TR_MNU_OFFSET RTC_TR_MNU_Pos +#define RTC_TR_ST_OFFSET RTC_TR_ST_Pos +#define RTC_TR_SU_OFFSET RTC_TR_SU_Pos + +#define RTC_DR_YT_OFFSET RTC_DR_YT_Pos +#define RTC_DR_YU_OFFSET RTC_DR_YU_Pos +#define RTC_DR_WDU_OFFSET RTC_DR_WDU_Pos +#define RTC_DR_MT_OFFSET RTC_DR_MT_Pos +#define RTC_DR_MU_OFFSET RTC_DR_MU_Pos +#define RTC_DR_DT_OFFSET RTC_DR_DT_Pos +#define RTC_DR_DU_OFFSET RTC_DR_DU_Pos + +#define RTC_CR_BKP_OFFSET RTC_CR_BKP_Pos + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief RTC driver identifier. + */ +RTCDriver RTCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Beginning of configuration procedure. + * + * @notapi + */ +static void rtc_enter_init(void) { + + RTCD1.rtc->ICSR |= RTC_ICSR_INIT; + while ((RTCD1.rtc->ICSR & RTC_ICSR_INITF) == 0) + ; +} + +/** + * @brief Finalizing of configuration procedure. + * + * @notapi + */ +static inline void rtc_exit_init(void) { + + RTCD1.rtc->ICSR &= ~RTC_ICSR_INIT; +} + +/** + * @brief Converts time from TR register encoding to timespec. + * + * @param[in] tr TR register value + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +static void rtc_decode_time(uint32_t tr, RTCDateTime *timespec) { + uint32_t n; + + n = ((tr >> RTC_TR_HT_OFFSET) & 3) * 36000000; + n += ((tr >> RTC_TR_HU_OFFSET) & 15) * 3600000; + n += ((tr >> RTC_TR_MNT_OFFSET) & 7) * 600000; + n += ((tr >> RTC_TR_MNU_OFFSET) & 15) * 60000; + n += ((tr >> RTC_TR_ST_OFFSET) & 7) * 10000; + n += ((tr >> RTC_TR_SU_OFFSET) & 15) * 1000; + timespec->millisecond = n; +} + +/** + * @brief Converts date from DR register encoding to timespec. + * + * @param[in] dr DR register value + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +static void rtc_decode_date(uint32_t dr, RTCDateTime *timespec) { + + timespec->year = (((dr >> RTC_DR_YT_OFFSET) & 15) * 10) + + ((dr >> RTC_DR_YU_OFFSET) & 15); + timespec->month = (((dr >> RTC_TR_MNT_OFFSET) & 1) * 10) + + ((dr >> RTC_TR_MNU_OFFSET) & 15); + timespec->day = (((dr >> RTC_DR_DT_OFFSET) & 3) * 10) + + ((dr >> RTC_DR_DU_OFFSET) & 15); + timespec->dayofweek = ((dr >> RTC_DR_WDU_OFFSET) & 7) + 1; +} + +/** + * @brief Converts time from timespec to TR register encoding. + * + * @param[in] timespec pointer to a @p RTCDateTime structure + * @return the TR register encoding. + * + * @notapi + */ +static uint32_t rtc_encode_time(const RTCDateTime *timespec) { + uint32_t n, tr = 0; + + /* Subseconds cannot be set.*/ + n = timespec->millisecond / 1000; + + /* Seconds conversion.*/ + tr = tr | ((n % 10) << RTC_TR_SU_OFFSET); + n /= 10; + tr = tr | ((n % 6) << RTC_TR_ST_OFFSET); + n /= 6; + + /* Minutes conversion.*/ + tr = tr | ((n % 10) << RTC_TR_MNU_OFFSET); + n /= 10; + tr = tr | ((n % 6) << RTC_TR_MNT_OFFSET); + n /= 6; + + /* Hours conversion.*/ + tr = tr | ((n % 10) << RTC_TR_HU_OFFSET); + n /= 10; + tr = tr | (n << RTC_TR_HT_OFFSET); + + return tr; +} + +/** + * @brief Converts a date from timespec to DR register encoding. + * + * @param[in] timespec pointer to a @p RTCDateTime structure + * @return the DR register encoding. + * + * @notapi + */ +static uint32_t rtc_encode_date(const RTCDateTime *timespec) { + uint32_t n, dr = 0; + + /* Year conversion. Note, only years last two digits are considered.*/ + n = timespec->year; + dr = dr | ((n % 10) << RTC_DR_YU_OFFSET); + n /= 10; + dr = dr | ((n % 10) << RTC_DR_YT_OFFSET); + + /* Months conversion.*/ + n = timespec->month; + dr = dr | ((n % 10) << RTC_DR_MU_OFFSET); + n /= 10; + dr = dr | ((n % 10) << RTC_DR_MT_OFFSET); + + /* Days conversion.*/ + n = timespec->day; + dr = dr | ((n % 10) << RTC_DR_DU_OFFSET); + n /= 10; + dr = dr | ((n % 10) << RTC_DR_DT_OFFSET); + + /* Days of week conversion.*/ + dr = dr | ((timespec->dayofweek) << RTC_DR_WDU_OFFSET); + + return dr; +} + +#if RTC_HAS_STORAGE == TRUE +static size_t _getsize(void *instance) { + + (void)instance; + + return (size_t)STM32_RTC_STORAGE_SIZE; +} + +static ps_error_t _read(void *instance, ps_offset_t offset, + size_t n, uint8_t *rp) { + volatile uint32_t *bkpr = &((RTCDriver *)instance)->tamp->BKP0R; + unsigned i; + + chDbgCheck((instance != NULL) && (rp != NULL)); + chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE)); + chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) && + (offset + n <= STM32_RTC_STORAGE_SIZE)); + + for (i = 0; i < (unsigned)n; i++) { + unsigned index = ((unsigned)offset + i) / sizeof (uint32_t); + unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t); + *rp++ = (uint8_t)(bkpr[index] >> (shift * 8U)); + } + + return PS_NO_ERROR; +} + +static ps_error_t _write(void *instance, ps_offset_t offset, + size_t n, const uint8_t *wp) { + volatile uint32_t *bkpr = &((RTCDriver *)instance)->tamp->BKP0R; + unsigned i; + + chDbgCheck((instance != NULL) && (wp != NULL)); + chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE)); + chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) && + (offset + n <= STM32_RTC_STORAGE_SIZE)); + + for (i = 0; i < (unsigned)n; i++) { + unsigned index = ((unsigned)offset + i) / sizeof (uint32_t); + unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t); + uint32_t regval = bkpr[index]; + regval &= ~(0xFFU << (shift * 8U)); + regval |= (uint32_t)*wp++ << (shift * 8U); + bkpr[index] = regval; + } + + return PS_NO_ERROR; +} + +/** + * @brief VMT for the RTC storage file interface. + */ +struct RTCDriverVMT _rtc_lld_vmt = { + (size_t)0, + _getsize, _read, _write +}; +#endif /* RTC_HAS_STORAGE == TRUE */ + +/** + * @brief RTC ISR service routine. + * + */ +static void rtc_lld_serve_interrupt(void) { + + uint32_t isr; + + /* Get and clear the RTC interrupts. */ + isr = RTCD1.rtc->MISR; + RTCD1.rtc->SCR = isr; + + /* Clear EXTI events. */ + STM32_RTC_CLEAR_ALL_EXTI(); + + /* Process call backs if enabled. */ + if (RTCD1.callback != NULL) { + +#if defined(RTC_MISR_WUTMF) + if ((isr & RTC_MISR_WUTMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_WAKEUP); + } +#endif + +#if defined(RTC_MISR_ALRAMF) + if ((isr & RTC_MISR_ALRAMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_A); + } +#endif +#if defined(RTC_MISR_ALRBMF) + if ((isr & RTC_MISR_ALRBMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_B); + } +#endif +#if defined(RTC_MISR_ITSMF) + if ((isr & RTC_MISR_ITSMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TS); + } +#endif +#if defined(RTC_MISR_TSOVMF) + if ((isr & RTC_MISR_TSOVMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TS_OVF); + } +#endif + + /* Get and clear the TAMP interrupts. */ + isr = RTCD1.tamp->MISR; + RTCD1.tamp->SCR = isr; +#if defined(TAMP_MISR_TAMP1MF) + if ((isr & TAMP_MISR_TAMP1MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1); + } +#endif +#if defined(TAMP_MISR_TAMP2MF) + if ((isr & TAMP_MISR_TAMP2MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2); + } +#endif +#if defined(TAMP_MISR_ITAMP3MF) + if ((isr & TAMP_MISR_ITAMP3MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP3); + } +#endif +#if defined(TAMP_MISR_ITAMP4MF) + if ((isr & TAMP_MISR_ITAMP4MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP4); + } +#endif +#if defined(TAMP_MISR_ITAMP5MF) + if ((isr & TAMP_MISR_ITAMP5MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP5); + } +#endif +#if defined(TAMP_MISR_ITAMP6MF) + if ((isr & TAMP_MISR_ITAMP6MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP6); + } +#endif + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_RTC_COMMON_HANDLER) +#if !defined(STM32_RTC_SUPPRESS_COMMON_ISR) +/** + * @brief RTC common interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC_COMMON_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + rtc_lld_serve_interrupt(); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_RTC_SUPPRESS_COMMON_ISR) */ + +#elif defined(STM32_RTC_TAMP_STAMP_HANDLER) && \ + defined(STM32_RTC_WKUP_HANDLER) && \ + defined(STM32_RTC_ALARM_HANDLER) +/** + * @brief RTC TAMP/STAMP interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC_TAMP_STAMP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + rtc_lld_serve_interrupt(); + + OSAL_IRQ_EPILOGUE(); +} +/** + * @brief RTC wakeup interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC_WKUP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + rtc_lld_serve_interrupt(); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief RTC alarm interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC_ALARM_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + rtc_lld_serve_interrupt(); + + OSAL_IRQ_EPILOGUE(); +} + +#else +#error "missing required RTC handler definitions in registry" +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Enable access to registers. + * + * @notapi + */ +void rtc_lld_init(void) { + + /* RTC object initialization.*/ + rtcObjectInit(&RTCD1); + + /* RTC pointer initialization.*/ + RTCD1.rtc = RTC; + + /* Disable write protection. */ + RTCD1.rtc->WPR = 0xCA; + RTCD1.rtc->WPR = 0x53; + + /* If calendar has not been initialized yet then proceed with the + initial setup.*/ + if (!(RTCD1.rtc->ICSR & RTC_ICSR_INITS)) { + + rtc_enter_init(); + + RTCD1.rtc->CR |= (STM32_RTC_CR_INIT & STM32_RTC_CR_MASK); + /* Setting PRER has to be done as two writes. Write Sync part first + then Sync + Async. */ + RTCD1.rtc->PRER = STM32_RTC_PRER_BITS & 0x7FFF; + RTCD1.rtc->PRER = STM32_RTC_PRER_BITS; + + rtc_exit_init(); + } + else { + RTCD1.rtc->ICSR &= ~RTC_ICSR_RSF; + } + + /* TAMP pointer initialization. */ + RTCD1.tamp = TAMP; + + /* Initialise TAMP registers. */ + RTCD1.tamp->CR1 |= (STM32_TAMP_CR1_INIT & STM32_TAMP_CR1_MASK); + RTCD1.tamp->CR2 |= (STM32_TAMP_CR2_INIT & STM32_TAMP_CR2_MASK); + RTCD1.tamp->FLTCR |= (STM32_TAMP_FLTCR_INIT & STM32_TAMP_FLTCR_MASK); + RTCD1.tamp->IER |= (STM32_TAMP_IER_INIT & STM32_TAMP_IER_MASK); + + /* Callback initially disabled.*/ + RTCD1.callback = NULL; + + /* Enabling RTC-related EXTI lines.*/ + STM32_RTC_ENABLE_ALL_EXTI(); + + /* IRQ vectors permanently assigned to this driver.*/ + STM32_RTC_IRQ_ENABLE(); +} + +/** + * @brief Set current time. + * @note Fractional part will be silently ignored. There is no possibility + * to set it on STM32 platform. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec) { + uint32_t dr, tr; + syssts_t sts; + + tr = rtc_encode_time(timespec); + dr = rtc_encode_date(timespec); + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + /* Writing the registers.*/ + rtc_enter_init(); + rtcp->rtc->TR = tr; + rtcp->rtc->DR = dr; + rtcp->rtc->CR = (rtcp->rtc->CR & ~(1U << RTC_CR_BKP_OFFSET)) | + (timespec->dstflag << RTC_CR_BKP_OFFSET); + rtc_exit_init(); + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Get current time. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec) { + uint32_t dr, tr, cr; + uint32_t subs; +#if STM32_RTC_HAS_SUBSECONDS + uint32_t ssr; +#endif /* STM32_RTC_HAS_SUBSECONDS */ + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + /* Synchronization with the RTC and reading the registers, note + DR must be read last.*/ + while ((rtcp->rtc->ICSR & RTC_ICSR_RSF) == 0) + ; +#if STM32_RTC_HAS_SUBSECONDS + ssr = rtcp->rtc->SSR; +#endif /* STM32_RTC_HAS_SUBSECONDS */ + tr = rtcp->rtc->TR; + dr = rtcp->rtc->DR; + cr = rtcp->rtc->CR; + rtcp->rtc->ICSR &= ~RTC_ICSR_RSF; + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); + + /* Decoding day time, this starts the atomic read sequence, see "Reading + the calendar" in the RTC documentation.*/ + rtc_decode_time(tr, timespec); + + /* If the RTC is capable of sub-second counting then the value is + normalized in milliseconds and added to the time.*/ +#if STM32_RTC_HAS_SUBSECONDS + subs = (((STM32_RTC_PRESS_VALUE - 1U) - ssr) * 1000U) / STM32_RTC_PRESS_VALUE; +#else + subs = 0; +#endif /* STM32_RTC_HAS_SUBSECONDS */ + timespec->millisecond += subs; + + /* Decoding date, this concludes the atomic read sequence.*/ + rtc_decode_date(dr, timespec); + + /* Retrieving the DST bit.*/ + timespec->dstflag = (cr >> RTC_CR_BKP_OFFSET) & 1; +} + +#if (RTC_ALARMS > 0) || defined(__DOXYGEN__) +/** + * @brief Set alarm time. + * @note Default value after BKP domain reset for both comparators is 0. + * @note Function does not performs any checks of alarm time validity. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure. + * @param[in] alarm alarm identifier. Can be 0 or 1. + * @param[in] alarmspec pointer to a @p RTCAlarm structure. + * + * @notapi + */ +void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + if (alarm == 0) { + if (alarmspec != NULL) { + rtcp->rtc->CR &= ~RTC_CR_ALRAE; + while (!(rtcp->rtc->ICSR & RTC_ICSR_ALRAWF)) + ; + rtcp->rtc->ALRMAR = alarmspec->alrmr; + rtcp->rtc->CR |= RTC_CR_ALRAE; + rtcp->rtc->CR |= RTC_CR_ALRAIE; + } + else { + rtcp->rtc->CR &= ~RTC_CR_ALRAIE; + rtcp->rtc->CR &= ~RTC_CR_ALRAE; + } + } +#if RTC_ALARMS > 1 + else { + if (alarmspec != NULL) { + rtcp->rtc->CR &= ~RTC_CR_ALRBE; + while (!(rtcp->rtc->ICSR & RTC_ICSR_ALRBWF)) + ; + rtcp->rtc->ALRMBR = alarmspec->alrmr; + rtcp->rtc->CR |= RTC_CR_ALRBE; + rtcp->rtc->CR |= RTC_CR_ALRBIE; + } + else { + rtcp->rtc->CR &= ~RTC_CR_ALRBIE; + rtcp->rtc->CR &= ~RTC_CR_ALRBE; + } + } +#endif /* RTC_ALARMS > 1 */ + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Get alarm time. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] alarm alarm identifier. Can be 0 or 1. + * @param[out] alarmspec pointer to a @p RTCAlarm structure + * + * @notapi + */ +void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec) { + + if (alarm == 0) + alarmspec->alrmr = rtcp->rtc->ALRMAR; +#if RTC_ALARMS > 1 + else + alarmspec->alrmr = rtcp->rtc->ALRMBR; +#endif /* RTC_ALARMS > 1 */ +} +#endif /* RTC_ALARMS > 0 */ + +/** + * @brief Enables or disables RTC callbacks. + * @details This function enables or disables callbacks, use a @p NULL pointer + * in order to disable a callback. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] callback callback function pointer or @p NULL + * + * @notapi + */ +void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) { + + rtcp->callback = callback; +} + +#if STM32_RTC_HAS_PERIODIC_WAKEUPS || defined(__DOXYGEN__) +/** + * @brief Sets time of periodic wakeup. + * @note Default value after BKP domain reset is 0x0000FFFF + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] wakeupspec pointer to a @p RTCWakeup structure + * + * @api + */ +void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + if (wakeupspec != NULL) { + osalDbgCheck(wakeupspec->wutr != 0x30000); + + rtcp->rtc->CR &= ~RTC_CR_WUTE; + rtcp->rtc->CR &= ~RTC_CR_WUTIE; + while (!(rtcp->rtc->ICSR & RTC_ICSR_WUTWF)) + ; + rtcp->rtc->WUTR = wakeupspec->wutr & 0xFFFF; + rtcp->rtc->CR &= ~RTC_CR_WUCKSEL; + rtcp->rtc->CR |= (wakeupspec->wutr >> 16) & RTC_CR_WUCKSEL; + rtcp->rtc->CR |= RTC_CR_WUTIE; + rtcp->rtc->CR |= RTC_CR_WUTE; + } + else { + rtcp->rtc->CR &= ~RTC_CR_WUTE; + rtcp->rtc->CR &= ~RTC_CR_WUTIE; + } + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Gets time of periodic wakeup. + * @note Default value after BKP domain reset is 0x0000FFFF + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] wakeupspec pointer to a @p RTCWakeup structure + * + * @api + */ +void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + wakeupspec->wutr = 0; + wakeupspec->wutr |= rtcp->rtc->WUTR; + wakeupspec->wutr |= (((uint32_t)rtcp->rtc->CR) & 0x7) << 16; + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} +#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */ + +#endif /* HAL_USE_RTC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h new file mode 100644 index 0000000..4097a62 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h @@ -0,0 +1,289 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file RTCv3/hal_rtc_lld.h + * @brief STM32 RTC low level driver header. + * + * @addtogroup RTC + * @{ + */ + +#ifndef HAL_RTC_LLD_H +#define HAL_RTC_LLD_H + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Implementation capabilities + */ +/** + * @brief Callback support int the driver. + */ +#define RTC_SUPPORTS_CALLBACKS TRUE + +/** + * @brief Number of alarms available. + */ +#define RTC_ALARMS STM32_RTC_NUM_ALARMS + +/** + * @brief Presence of a local persistent storage. + */ +#define RTC_HAS_STORAGE (STM32_RTC_STORAGE_SIZE > 0) +/** @} */ + +/** + * @brief RTC PRER register initializer. + */ +#define RTC_PRER(a, s) ((((a) - 1) << 16) | ((s) - 1)) + +/** + * @name Alarm helper macros + * @{ + */ +#define RTC_ALRM_MSK4 (1U << 31) +#define RTC_ALRM_WDSEL (1U << 30) +#define RTC_ALRM_DT(n) ((n) << 28) +#define RTC_ALRM_DU(n) ((n) << 24) +#define RTC_ALRM_MSK3 (1U << 23) +#define RTC_ALRM_HT(n) ((n) << 20) +#define RTC_ALRM_HU(n) ((n) << 16) +#define RTC_ALRM_MSK2 (1U << 15) +#define RTC_ALRM_MNT(n) ((n) << 12) +#define RTC_ALRM_MNU(n) ((n) << 8) +#define RTC_ALRM_MSK1 (1U << 7) +#define RTC_ALRM_ST(n) ((n) << 4) +#define RTC_ALRM_SU(n) ((n) << 0) +/** @} */ + +/* Requires services from the EXTI driver.*/ +#if !defined(STM32_EXTI_REQUIRED) +#define STM32_EXTI_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief RTC PRESA register initialization. + * @note The default is calculated for a 32768Hz clock. + */ +#if !defined(STM32_RTC_PRESA_VALUE) || defined(__DOXYGEN__) +#define STM32_RTC_PRESA_VALUE 32 +#endif + +/** + * @brief RTC PRESS divider initialization. + * @note The default is calculated for a 32768Hz clock. + */ +#if !defined(STM32_RTC_PRESS_VALUE) || defined(__DOXYGEN__) +#define STM32_RTC_PRESS_VALUE 1024 +#endif + +/** + * @brief RTC CR register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + */ +#if !defined(STM32_RTC_CR_INIT) || defined(__DOXYGEN__) +#define STM32_RTC_CR_INIT 0 +#endif + +/** + * @brief TAMP register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + * @note On some devices this values goes in the similar TAFCR register. + */ +#if !defined(STM32_TAMP_CR1_INIT) || defined(__DOXYGEN__) +#define STM32_TAMP_CR1_INIT 0 +#endif + +/** + * @brief TAMP register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + * @note On some devices this values goes in the similar TAFCR register. + */ +#if !defined(STM32_TAMP_CR2_INIT) || defined(__DOXYGEN__) +#define STM32_TAMP_CR2_INIT 0 +#endif + +/** + * @brief TAMP register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + * @note On some devices this values goes in the similar TAFCR register. + */ +#if !defined(STM32_TAMP_FLTCR_INIT) || defined(__DOXYGEN__) +#define STM32_TAMP_FLTCR_INIT 0 +#endif + +/** + * @brief TAMP register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + * @note On some devices this values goes in the similar TAFCR register. + */ +#if !defined(STM32_TAMP_IER_INIT) || defined(__DOXYGEN__) +#define STM32_TAMP_IER_INIT 0 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if HAL_USE_RTC && !STM32_HAS_RTC +#error "RTC not present in the selected device" +#endif + +#if defined(STM32_RTC_CK) && !defined(STM32_RTCCLK) +#define STM32_RTCCLK STM32_RTC_CK +#endif + +#if !defined(STM32_RTCCLK) +#error "RTC clock not exported by HAL layer" +#endif + +#if STM32_RTCCLK == 0 +#error "RTC has no clock source selected" +#endif + +#if STM32_PCLK1 < (STM32_RTCCLK * 7) +#error "STM32_PCLK1 frequency is too low for RTC" +#endif + +/** + * @brief Initialization for the RTC_PRER register. + */ +#define STM32_RTC_PRER_BITS RTC_PRER(STM32_RTC_PRESA_VALUE, \ + STM32_RTC_PRESS_VALUE) + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of an RTC event. + */ +typedef enum { + RTC_EVENT_ALARM_A = 0, /** Alarm A. */ + RTC_EVENT_ALARM_B = 1, /** Alarm B. */ + RTC_EVENT_TS = 2, /** Time stamp. */ + RTC_EVENT_TS_OVF = 3, /** Time stamp overflow. */ + RTC_EVENT_TAMP1 = 4, /** Tamper 1. */ + RTC_EVENT_TAMP2 = 5, /** Tamper 2- */ + RTC_EVENT_TAMP3 = 6, /** Tamper 3. */ + RTC_EVENT_TAMP4 = 7, /** Tamper 4. */ + RTC_EVENT_TAMP5 = 8, /** Tamper 5. */ + RTC_EVENT_TAMP6 = 9, /** Tamper 6. */ + RTC_EVENT_WAKEUP = 10, /** Wakeup. */ + } rtcevent_t; + +/** + * @brief Type of a generic RTC callback. + */ +typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event); + +/** + * @brief Type of a structure representing an RTC alarm time stamp. + */ +typedef struct hal_rtc_alarm { + /** + * @brief Type of an alarm as encoded in RTC ALRMxR registers. + */ + uint32_t alrmr; +} RTCAlarm; + +#if STM32_RTC_HAS_PERIODIC_WAKEUPS +/** + * @brief Type of a wakeup as encoded in RTC WUTR register. + */ +typedef struct hal_rtc_wakeup { + /** + * @brief Wakeup as encoded in RTC WUTR register. + * @note ((WUTR == 0) || (WUCKSEL == 3)) are a forbidden combination. + * @note Bits 16..18 are copied in the CR bits 0..2 (WUCKSEL). + */ + uint32_t wutr; +} RTCWakeup; +#endif + +/** + * @brief Implementation-specific @p RTCDriver fields. + */ +#define rtc_lld_driver_fields \ + /* Pointer to the RTC registers block.*/ \ + RTC_TypeDef *rtc; \ + /* RTC event callback pointer.*/ \ + rtccb_t callback; \ + /* Pointer to TAMPER registers block. */ \ + TAMP_TypeDef *tamp + + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void rtc_lld_init(void); + void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec); + void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec); +#if RTC_SUPPORTS_CALLBACKS == TRUE + void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback); +#endif +#if RTC_ALARMS > 0 + void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec); + void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec); +#endif +#if STM32_RTC_HAS_PERIODIC_WAKEUPS + void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec); + void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec); +#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */ +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_RTC */ + +#endif /* HAL_RTC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/driver.mk new file mode 100644 index 0000000..a1ce6d4 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c new file mode 100644 index 0000000..37d4989 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c @@ -0,0 +1,876 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SDIOv1/hal_sdc_lld.c + * @brief STM32 SDC subsystem low level driver source. + * + * @addtogroup SDC + * @{ + */ + +#include + +#include "hal.h" + +#if HAL_USE_SDC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SDC_SDIO_DMA_STREAM, \ + STM32_SDC_SDIO_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief SDCD1 driver identifier.*/ +SDCDriver SDCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +#if STM32_SDC_SDIO_UNALIGNED_SUPPORT +/** + * @brief Buffer for temporary storage during unaligned transfers. + */ +static union { + uint32_t alignment; + uint8_t buf[MMCSD_BLOCK_SIZE]; +} u; +#endif /* STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + +/** + * @brief SDIO default configuration. + */ +static const SDCConfig sdc_default_cfg = { + SDC_MODE_4BIT +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Prepares to handle read transaction. + * @details Designed for read special registers from card. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] buf pointer to the read buffer + * @param[in] bytes number of bytes to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp, + uint8_t *buf, uint32_t bytes) { + osalDbgCheck(bytes < 0x1000000); + + sdcp->sdio->DTIMER = STM32_SDC_READ_TIMEOUT; + + /* Checks for errors and waits for the card to be ready for reading.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Prepares the DMA channel for writing.*/ + dmaStreamSetMemory0(sdcp->dma, buf); + dmaStreamSetTransactionSize(sdcp->dma, bytes / sizeof (uint32_t)); + dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); + dmaStreamEnable(sdcp->dma); + + /* Setting up data transfer.*/ + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | + SDIO_MASK_DTIMEOUTIE | + SDIO_MASK_STBITERRIE | + SDIO_MASK_RXOVERRIE | + SDIO_MASK_DATAENDIE; + sdcp->sdio->DLEN = bytes; + + /* Transaction starts just after DTEN bit setting.*/ + sdcp->sdio->DCTRL = SDIO_DCTRL_DTDIR | + SDIO_DCTRL_DTMODE | /* Multibyte data transfer.*/ + SDIO_DCTRL_DMAEN | + SDIO_DCTRL_DTEN; + + return HAL_SUCCESS; +} + +/** + * @brief Prepares card to handle read transaction. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[in] n number of blocks to read + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk, + uint32_t n, uint32_t *resp) { + + /* Driver handles data in 512 bytes blocks (just like HC cards). But if we + have not HC card than we must convert address from blocks to bytes.*/ + if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) + startblk *= MMCSD_BLOCK_SIZE; + + if (n > 1) { + /* Send read multiple blocks command to card.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + else { + /* Send read single block command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_SINGLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Prepares card to handle write transaction. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[in] n number of blocks to write + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk, + uint32_t n, uint32_t *resp) { + + /* Driver handles data in 512 bytes blocks (just like HC cards). But if we + have not HC card than we must convert address from blocks to bytes.*/ + if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) + startblk *= MMCSD_BLOCK_SIZE; + + if (n > 1) { + /* Write multiple blocks command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + else { + /* Write single block command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Wait end of data transaction and performs finalizations. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] n number of blocks in transaction + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + */ +static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n, + uint32_t *resp) { + + /* Note the mask is checked before going to sleep because the interrupt + may have occurred before reaching the critical zone.*/ + osalSysLock(); + if (sdcp->sdio->MASK != 0) + osalThreadSuspendS(&sdcp->thread); + if ((sdcp->sdio->STA & SDIO_STA_DATAEND) == 0) { + osalSysUnlock(); + return HAL_FAILED; + } + +#if (defined(STM32F4XX) || defined(STM32F2XX)) + /* Wait until DMA channel enabled to be sure that all data transferred.*/ + while (sdcp->dma->stream->CR & STM32_DMA_CR_EN) + ; + + /* DMA event flags must be manually cleared.*/ + dmaStreamClearInterrupt(sdcp->dma); + + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->DCTRL = 0; + osalSysUnlock(); +#else + /* Waits for transfer completion at DMA level, then the stream is + disabled and cleared.*/ + dmaWaitCompletion(sdcp->dma); + + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->DCTRL = 0; + osalSysUnlock(); +#endif + + /* Finalize transaction.*/ + if (n > 1) + return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); + + return HAL_SUCCESS; +} + +/** + * @brief Gets SDC errors. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] sta value of the STA register + * + * @notapi + */ +static void sdc_lld_collect_errors(SDCDriver *sdcp, uint32_t sta) { + uint32_t errors = SDC_NO_ERROR; + + if (sta & SDIO_STA_CCRCFAIL) + errors |= SDC_CMD_CRC_ERROR; + if (sta & SDIO_STA_DCRCFAIL) + errors |= SDC_DATA_CRC_ERROR; + if (sta & SDIO_STA_CTIMEOUT) + errors |= SDC_COMMAND_TIMEOUT; + if (sta & SDIO_STA_DTIMEOUT) + errors |= SDC_DATA_TIMEOUT; + if (sta & SDIO_STA_TXUNDERR) + errors |= SDC_TX_UNDERRUN; + if (sta & SDIO_STA_RXOVERR) + errors |= SDC_RX_OVERRUN; + if (sta & SDIO_STA_STBITERR) + errors |= SDC_STARTBIT_ERROR; + + sdcp->errors |= errors; +} + +/** + * @brief Performs clean transaction stopping in case of errors. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] n number of blocks in transaction + * @param[in] resp pointer to the response buffer + * + * @notapi + */ +static void sdc_lld_error_cleanup(SDCDriver *sdcp, + uint32_t n, + uint32_t *resp) { + uint32_t sta = sdcp->sdio->STA; + + dmaStreamClearInterrupt(sdcp->dma); + dmaStreamDisable(sdcp->dma); + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->MASK = 0; + sdcp->sdio->DCTRL = 0; + sdc_lld_collect_errors(sdcp, sta); + if (n > 1) + sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if !defined(STM32_SDIO_HANDLER) +#error "STM32_SDIO_HANDLER not defined" +#endif +/** + * @brief SDIO IRQ handler. + * @details It just wakes transaction thread. All error handling performs in + * that thread. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SDIO_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + osalSysLockFromISR(); + + /* Disables the source but the status flags are not reset because the + read/write functions needs to check them.*/ + SDIO->MASK = 0; + + osalThreadResumeI(&SDCD1.thread, MSG_OK); + + osalSysUnlockFromISR(); + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SDC driver initialization. + * + * @notapi + */ +void sdc_lld_init(void) { + + sdcObjectInit(&SDCD1); + SDCD1.thread = NULL; + SDCD1.dma = NULL; + SDCD1.sdio = SDIO; + nvicEnableVector(STM32_SDIO_NUMBER, STM32_SDC_SDIO_IRQ_PRIORITY); +} + +/** + * @brief Configures and activates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_start(SDCDriver *sdcp) { + + /* Checking configuration, using a default if NULL has been passed.*/ + if (sdcp->config == NULL) { + sdcp->config = &sdc_default_cfg; + } + + sdcp->dmamode = STM32_DMA_CR_CHSEL(DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SDC_SDIO_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_WORD | + STM32_DMA_CR_MSIZE_WORD | + STM32_DMA_CR_MINC; + +#if (defined(STM32F4XX) || defined(STM32F2XX)) + sdcp->dmamode |= STM32_DMA_CR_PFCTRL | + STM32_DMA_CR_PBURST_INCR4 | + STM32_DMA_CR_MBURST_INCR4; +#endif + + if (sdcp->state == BLK_STOP) { + sdcp->dma = dmaStreamAllocI(STM32_SDC_SDIO_DMA_STREAM, + STM32_SDC_SDIO_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(sdcp->dma != NULL, "unable to allocate stream"); + + dmaStreamSetPeripheral(sdcp->dma, &sdcp->sdio->FIFO); +#if (defined(STM32F4XX) || defined(STM32F2XX)) + dmaStreamSetFIFO(sdcp->dma, STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_FULL); +#endif + rccEnableSDIO(true); + } + + /* Configuration, card clock is initially stopped.*/ + sdcp->sdio->POWER = 0; + sdcp->sdio->CLKCR = 0; + sdcp->sdio->DCTRL = 0; + sdcp->sdio->DTIMER = 0; +} + +/** + * @brief Deactivates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_stop(SDCDriver *sdcp) { + + if (sdcp->state != BLK_STOP) { + + /* SDIO deactivation.*/ + sdcp->sdio->POWER = 0; + sdcp->sdio->CLKCR = 0; + sdcp->sdio->DCTRL = 0; + sdcp->sdio->DTIMER = 0; + + /* DMA stream released.*/ + dmaStreamFreeI(sdcp->dma); + sdcp->dma = NULL; + + /* Clock deactivation.*/ + rccDisableSDIO(); + } +} + +/** + * @brief Starts the SDIO clock and sets it to init mode (400kHz or less). + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_start_clk(SDCDriver *sdcp) { + + /* Initial clock setting: 400kHz, 1bit mode.*/ + sdcp->sdio->CLKCR = STM32_SDIO_DIV_LS; + sdcp->sdio->POWER |= SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1; + sdcp->sdio->CLKCR |= SDIO_CLKCR_CLKEN; + + /* Clock activation delay.*/ + osalThreadSleep(OSAL_MS2I(STM32_SDC_CLOCK_ACTIVATION_DELAY)); +} + +/** + * @brief Sets the SDIO clock to data mode (25MHz or less). + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] clk the clock mode + * + * @notapi + */ +void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) { + +#if STM32_SDC_SDIO_50MHZ + if (SDC_CLK_50MHz == clk) { + sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS + | SDIO_CLKCR_BYPASS; + } + else + sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS; +#else + (void)clk; + + sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS; +#endif +} + +/** + * @brief Stops the SDIO clock. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_stop_clk(SDCDriver *sdcp) { + + sdcp->sdio->CLKCR = 0; + sdcp->sdio->POWER = 0; +} + +/** + * @brief Switches the bus to 4 bits mode. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] mode bus mode + * + * @notapi + */ +void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) { + uint32_t clk = sdcp->sdio->CLKCR & ~SDIO_CLKCR_WIDBUS; + + switch (mode) { + case SDC_MODE_1BIT: + sdcp->sdio->CLKCR = clk; + break; + case SDC_MODE_4BIT: + sdcp->sdio->CLKCR = clk | SDIO_CLKCR_WIDBUS_0; + break; + case SDC_MODE_8BIT: + sdcp->sdio->CLKCR = clk | SDIO_CLKCR_WIDBUS_1; + break; + } +} + +/** + * @brief Sends an SDIO command with no response expected. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * + * @notapi + */ +void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) { + + sdcp->sdio->ARG = arg; + sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_CPSMEN; + while ((sdcp->sdio->STA & SDIO_STA_CMDSENT) == 0) + ; + sdcp->sdio->ICR = SDIO_ICR_CMDSENTC; +} + +/** + * @brief Sends an SDIO command with a short response expected. + * @note The CRC is not verified. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (one word) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + sdcp->sdio->ARG = arg; + sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN; + while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL)) == 0) + ; + sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL); + if ((sta & (SDIO_STA_CTIMEOUT)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + *resp = sdcp->sdio->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Sends an SDIO command with a short response expected and CRC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (one word) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + sdcp->sdio->ARG = arg; + sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN; + while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL)) == 0) + ; + sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL); + if ((sta & (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + *resp = sdcp->sdio->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Sends an SDIO command with a long response expected and CRC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (four words) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + (void)sdcp; + + sdcp->sdio->ARG = arg; + sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_WAITRESP_1 | + SDIO_CMD_CPSMEN; + while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL)) == 0) + ; + sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL); + if ((sta & (STM32_SDIO_STA_ERROR_MASK)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + /* Save bytes in reverse order because MSB in response comes first.*/ + *resp++ = sdcp->sdio->RESP4; + *resp++ = sdcp->sdio->RESP3; + *resp++ = sdcp->sdio->RESP2; + *resp = sdcp->sdio->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Reads special registers using data bus. + * @details Needs only during card detection procedure. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] buf pointer to the read buffer + * @param[in] bytes number of bytes to read + * @param[in] cmd card command + * @param[in] arg argument for command + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, + uint8_t cmd, uint32_t arg) { + uint32_t resp[1]; + + if (sdc_lld_prepare_read_bytes(sdcp, buf, bytes)) + goto error; + + if (sdc_lld_send_cmd_short_crc(sdcp, cmd, arg, resp) + || MMCSD_R1_ERROR(resp[0])) + goto error; + + if (sdc_lld_wait_transaction_end(sdcp, 1, resp)) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, 1, resp); + return HAL_FAILED; +} + +/** + * @brief Reads one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[out] buf pointer to the read buffer + * @param[in] blocks number of blocks to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks) { + uint32_t resp[1]; + + osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); + + sdcp->sdio->DTIMER = STM32_SDC_READ_TIMEOUT; + + /* Checks for errors and waits for the card to be ready for reading.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Prepares the DMA channel for writing.*/ + dmaStreamSetMemory0(sdcp->dma, buf); + dmaStreamSetTransactionSize(sdcp->dma, + (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); + dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); + dmaStreamEnable(sdcp->dma); + + /* Setting up data transfer.*/ + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | + SDIO_MASK_DTIMEOUTIE | + SDIO_MASK_STBITERRIE | + SDIO_MASK_RXOVERRIE | + SDIO_MASK_DATAENDIE; + sdcp->sdio->DLEN = blocks * MMCSD_BLOCK_SIZE; + + /* Transaction starts just after DTEN bit setting.*/ + sdcp->sdio->DCTRL = SDIO_DCTRL_DTDIR | + SDIO_DCTRL_DBLOCKSIZE_3 | + SDIO_DCTRL_DBLOCKSIZE_0 | + SDIO_DCTRL_DMAEN | + SDIO_DCTRL_DTEN; + + if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == true) + goto error; + + if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, blocks, resp); + return HAL_FAILED; +} + +/** + * @brief Writes one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to write + * @param[out] buf pointer to the write buffer + * @param[in] n number of blocks to write + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks) { + uint32_t resp[1]; + + osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); + + sdcp->sdio->DTIMER = STM32_SDC_WRITE_TIMEOUT; + + /* Checks for errors and waits for the card to be ready for writing.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Prepares the DMA channel for writing.*/ + dmaStreamSetMemory0(sdcp->dma, buf); + dmaStreamSetTransactionSize(sdcp->dma, + (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); + dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_M2P); + dmaStreamEnable(sdcp->dma); + + /* Setting up data transfer.*/ + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | + SDIO_MASK_DTIMEOUTIE | + SDIO_MASK_STBITERRIE | + SDIO_MASK_TXUNDERRIE | + SDIO_MASK_DATAENDIE; + sdcp->sdio->DLEN = blocks * MMCSD_BLOCK_SIZE; + + /* Talk to card what we want from it.*/ + if (sdc_lld_prepare_write(sdcp, startblk, blocks, resp) == true) + goto error; + + /* Transaction starts just after DTEN bit setting.*/ + sdcp->sdio->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | + SDIO_DCTRL_DBLOCKSIZE_0 | + SDIO_DCTRL_DMAEN | + SDIO_DCTRL_DTEN; + + if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, blocks, resp); + return HAL_FAILED; +} + +/** + * @brief Reads one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[out] buf pointer to the read buffer + * @param[in] blocks number of blocks to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks) { + +#if STM32_SDC_SDIO_UNALIGNED_SUPPORT + if (((unsigned)buf & 3) != 0) { + uint32_t i; + for (i = 0; i < blocks; i++) { + if (sdc_lld_read_aligned(sdcp, startblk, u.buf, 1)) + return HAL_FAILED; + memcpy(buf, u.buf, MMCSD_BLOCK_SIZE); + buf += MMCSD_BLOCK_SIZE; + startblk++; + } + return HAL_SUCCESS; + } +#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer"); +#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + return sdc_lld_read_aligned(sdcp, startblk, buf, blocks); +} + +/** + * @brief Writes one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to write + * @param[out] buf pointer to the write buffer + * @param[in] blocks number of blocks to write + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks) { + +#if STM32_SDC_SDIO_UNALIGNED_SUPPORT + if (((unsigned)buf & 3) != 0) { + uint32_t i; + for (i = 0; i < blocks; i++) { + memcpy(u.buf, buf, MMCSD_BLOCK_SIZE); + buf += MMCSD_BLOCK_SIZE; + if (sdc_lld_write_aligned(sdcp, startblk, u.buf, 1)) + return HAL_FAILED; + startblk++; + } + return HAL_SUCCESS; + } +#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer"); +#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + return sdc_lld_write_aligned(sdcp, startblk, buf, blocks); +} + +/** + * @brief Waits for card idle condition. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool sdc_lld_sync(SDCDriver *sdcp) { + + /* CHTODO: Implement.*/ + (void)sdcp; + return HAL_SUCCESS; +} + +#endif /* HAL_USE_SDC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.h new file mode 100644 index 0000000..4f0a430 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.h @@ -0,0 +1,353 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SDIOv1/hal_sdc_lld.h + * @brief STM32 SDC subsystem low level driver header. + * + * @addtogroup SDC + * @{ + */ + +#ifndef HAL_SDC_LLD_H +#define HAL_SDC_LLD_H + +#if HAL_USE_SDC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* + * The following definitions are missing from some implementations, fixing + * as zeroed masks. + */ +#if !defined(SDIO_STA_STBITERR) +#define SDIO_STA_STBITERR 0 +#endif + +#if !defined(SDIO_ICR_STBITERRC) +#define SDIO_ICR_STBITERRC 0 +#endif + +#if !defined(SDIO_ICR_CEATAENDC) +#define SDIO_ICR_CEATAENDC 0 +#endif + +#if !defined(SDIO_MASK_STBITERRIE) +#define SDIO_MASK_STBITERRIE 0 +#endif + +/** + * @brief Value to clear all interrupts flag at once. + */ +#define STM32_SDIO_ICR_ALL_FLAGS (SDIO_ICR_CCRCFAILC | SDIO_ICR_DCRCFAILC | \ + SDIO_ICR_CTIMEOUTC | SDIO_ICR_DTIMEOUTC | \ + SDIO_ICR_TXUNDERRC | SDIO_ICR_RXOVERRC | \ + SDIO_ICR_CMDRENDC | SDIO_ICR_CMDSENTC | \ + SDIO_ICR_DATAENDC | SDIO_ICR_STBITERRC | \ + SDIO_ICR_DBCKENDC | SDIO_ICR_SDIOITC | \ + SDIO_ICR_CEATAENDC) + +/** + * @brief Mask of error flags in STA register. + */ +#define STM32_SDIO_STA_ERROR_MASK (SDIO_STA_CCRCFAIL | SDIO_STA_DCRCFAIL | \ + SDIO_STA_CTIMEOUT | SDIO_STA_DTIMEOUT | \ + SDIO_STA_TXUNDERR | SDIO_STA_RXOVERR) + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SDIO DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_SDC_SDIO_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SDC_SDIO_DMA_PRIORITY 3 +#endif + +/** + * @brief SDIO interrupt priority level setting. + */ +#if !defined(STM32_SDC_SDIO_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SDC_SDIO_IRQ_PRIORITY 9 +#endif + +/** + * @brief Enable clock bypass. + * @note Allow clock speed up to 50 Mhz. + */ +#if !defined(STM32_SDC_SDIO_50MHZ) || defined(__DOXYGEN__) +#define STM32_SDC_SDIO_50MHZ FALSE +#endif + +/** + * @brief Write timeout in milliseconds. + */ +#if !defined(STM32_SDC_WRITE_TIMEOUT_MS) || defined(__DOXYGEN__) +#define STM32_SDC_WRITE_TIMEOUT_MS 1000 +#endif + +/** + * @brief Read timeout in milliseconds. + */ +#if !defined(STM32_SDC_READ_TIMEOUT_MS) || defined(__DOXYGEN__) +#define STM32_SDC_READ_TIMEOUT_MS 1000 +#endif + +/** + * @brief Card clock activation delay in milliseconds. + */ +#if !defined(STM32_SDC_CLOCK_ACTIVATION_DELAY) || defined(__DOXYGEN__) +#define STM32_SDC_CLOCK_ACTIVATION_DELAY 10 +#endif + +/** + * @brief Support for unaligned transfers. + * @note Unaligned transfers are much slower. + */ +#if !defined(STM32_SDC_SDIO_UNALIGNED_SUPPORT) || defined(__DOXYGEN__) +#define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !STM32_HAS_SDIO +#error "SDIO not present in the selected device" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SDC_SDIO_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SDIO" +#endif + +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_SDC_SDIO_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SDIO" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if !defined(STM32_SDC_SDIO_DMA_STREAM) +#error "SDIO DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if !STM32_DMA_IS_VALID_ID(STM32_SDC_SDIO_DMA_STREAM, STM32_SDC_SDIO_DMA_MSK) +#error "invalid DMA stream associated to SDIO" +#endif +#endif /* STM32_ADVANCED_DMA */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/* + * SDIO clock divider. + */ +#if (defined(STM32F4XX) || defined(STM32F2XX)) +#define STM32_SDIO_DIV_HS 0 +#define STM32_SDIO_DIV_LS 120 + +#elif STM32_HCLK > 48000000 +#define STM32_SDIO_DIV_HS 1 +#define STM32_SDIO_DIV_LS 178 +#else + +#define STM32_SDIO_DIV_HS 0 +#define STM32_SDIO_DIV_LS 118 +#endif + +/** + * @brief SDIO data timeouts in SDIO clock cycles. + */ +#if (defined(STM32F4XX) || defined(STM32F2XX)) +#if !STM32_CLOCK48_REQUIRED +#error "SDIO requires STM32_CLOCK48_REQUIRED to be enabled" +#endif + +#if STM32_PLL48CLK != 48000000 +#error "invalid STM32_PLL48CLK clock value" +#endif + +#define STM32_SDC_WRITE_TIMEOUT \ + (((STM32_PLL48CLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ + STM32_SDC_WRITE_TIMEOUT_MS) +#define STM32_SDC_READ_TIMEOUT \ + (((STM32_PLL48CLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ + STM32_SDC_READ_TIMEOUT_MS) + +#else /* !(defined(STM32F4XX) || defined(STM32F2XX)) */ + +#define STM32_SDC_WRITE_TIMEOUT \ + (((STM32_HCLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ + STM32_SDC_WRITE_TIMEOUT_MS) +#define STM32_SDC_READ_TIMEOUT \ + (((STM32_HCLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ + STM32_SDC_READ_TIMEOUT_MS) + +#endif /* !(defined(STM32F4XX) || defined(STM32F2XX)) */ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of card flags. + */ +typedef uint32_t sdcmode_t; + +/** + * @brief SDC Driver condition flags type. + */ +typedef uint32_t sdcflags_t; + +/** + * @brief Type of a structure representing an SDC driver. + */ +typedef struct SDCDriver SDCDriver; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Bus width. + */ + sdcbusmode_t bus_width; + /* End of the mandatory fields.*/ +} SDCConfig; + +/** + * @brief @p SDCDriver specific methods. + */ +#define _sdc_driver_methods \ + _mmcsd_block_device_methods + +/** + * @extends MMCSDBlockDeviceVMT + * + * @brief @p SDCDriver virtual methods table. + */ +struct SDCDriverVMT { + _sdc_driver_methods +}; + +/** + * @brief Structure representing an SDC driver. + */ +struct SDCDriver { + /** + * @brief Virtual Methods Table. + */ + const struct SDCDriverVMT *vmt; + _mmcsd_block_device_data + /** + * @brief Current configuration data. + */ + const SDCConfig *config; + /** + * @brief Various flags regarding the mounted card. + */ + sdcmode_t cardmode; + /** + * @brief Errors flags. + */ + sdcflags_t errors; + /** + * @brief Card RCA. + */ + uint32_t rca; + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion IRQ. + */ + thread_reference_t thread; + /** + * @brief DMA mode bit mask. + */ + uint32_t dmamode; + /** + * @brief Transmit DMA channel. + */ + const stm32_dma_stream_t *dma; + /** + * @brief Pointer to the SDIO registers block. + * @note Needed for debugging aid. + */ + SDIO_TypeDef *sdio; + /** + * @brief Buffer for internal operations. + */ + uint8_t buf[MMCSD_BLOCK_SIZE]; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern SDCDriver SDCD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sdc_lld_init(void); + void sdc_lld_start(SDCDriver *sdcp); + void sdc_lld_stop(SDCDriver *sdcp); + void sdc_lld_start_clk(SDCDriver *sdcp); + void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk); + void sdc_lld_stop_clk(SDCDriver *sdcp); + void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode); + void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg); + bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, + uint8_t cmd, uint32_t argument); + bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks); + bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks); + bool sdc_lld_sync(SDCDriver *sdcp); + bool sdc_lld_is_card_inserted(SDCDriver *sdcp); + bool sdc_lld_is_write_protected(SDCDriver *sdcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SDC */ + +#endif /* HAL_SDC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/driver.mk new file mode 100644 index 0000000..7edbc24 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c new file mode 100644 index 0000000..1544981 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c @@ -0,0 +1,981 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SDMMCv1/hal_sdc_lld.c + * @brief STM32 SDC subsystem low level driver source. + * + * @addtogroup SDC + * @{ + */ + +#include + +#include "hal.h" + +#if HAL_USE_SDC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define SDMMC_ICR_ALL_FLAGS \ + (SDMMC_ICR_CCRCFAILC | SDMMC_ICR_DCRCFAILC | \ + SDMMC_ICR_CTIMEOUTC | SDMMC_ICR_DTIMEOUTC | \ + SDMMC_ICR_TXUNDERRC | SDMMC_ICR_RXOVERRC | \ + SDMMC_ICR_CMDRENDC | SDMMC_ICR_CMDSENTC | \ + SDMMC_ICR_DATAENDC | SDMMC_ICR_DBCKENDC | \ + SDMMC_ICR_SDIOITC) + +#define SDMMC_STA_ERROR_MASK \ + (SDMMC_STA_CCRCFAIL | SDMMC_STA_DCRCFAIL | \ + SDMMC_STA_CTIMEOUT | SDMMC_STA_DTIMEOUT | \ + SDMMC_STA_TXUNDERR | SDMMC_STA_RXOVERR) + +#define SDMMC_CLKDIV_HS (2 - 2) +#define SDMMC_CLKDIV_LS (120 - 2) + +#define SDMMC1_WRITE_TIMEOUT \ + (((STM32_SDMMC1CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \ + STM32_SDC_SDMMC_WRITE_TIMEOUT) +#define SDMMC1_READ_TIMEOUT \ + (((STM32_SDMMC1CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \ + STM32_SDC_SDMMC_READ_TIMEOUT) + +#define SDMMC2_WRITE_TIMEOUT \ + (((STM32_SDMMC2CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \ + STM32_SDC_SDMMC_WRITE_TIMEOUT) +#define SDMMC2_READ_TIMEOUT \ + (((STM32_SDMMC2CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \ + STM32_SDC_SDMMC_READ_TIMEOUT) + +#define SDMMC1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SDC_SDMMC1_DMA_STREAM, \ + STM32_SDC_SDMMC1_DMA_CHN) + +#define SDMMC2_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SDC_SDMMC2_DMA_STREAM, \ + STM32_SDC_SDMMC2_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief SDCD1 driver identifier.*/ +#if STM32_SDC_USE_SDMMC1 || defined(__DOXYGEN__) +SDCDriver SDCD1; +#endif + +/** @brief SDCD2 driver identifier.*/ +#if STM32_SDC_USE_SDMMC2 || defined(__DOXYGEN__) +SDCDriver SDCD2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief SDIO default configuration. + */ +static const SDCConfig sdc_default_cfg = { + SDC_MODE_4BIT +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Prepares to handle read transaction. + * @details Designed for read special registers from card. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] buf pointer to the read buffer + * @param[in] bytes number of bytes to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp, + uint8_t *buf, uint32_t bytes) { + osalDbgCheck(bytes < 0x1000000); + + sdcp->sdmmc->DTIMER = sdcp->rtmo; + + /* Checks for errors and waits for the card to be ready for reading.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Prepares the DMA channel for writing.*/ + dmaStreamSetMemory0(sdcp->dma, buf); + dmaStreamSetTransactionSize(sdcp->dma, bytes / sizeof (uint32_t)); + dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); + dmaStreamEnable(sdcp->dma); + + /* Setting up data transfer.*/ + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE | + SDMMC_MASK_DTIMEOUTIE | + SDMMC_MASK_RXOVERRIE | + SDMMC_MASK_DATAENDIE; + sdcp->sdmmc->DLEN = bytes; + + /* Transaction starts just after DTEN bit setting.*/ + sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DTDIR | + SDMMC_DCTRL_DTMODE | /* Multibyte data transfer.*/ + SDMMC_DCTRL_DMAEN | + SDMMC_DCTRL_DTEN; + + return HAL_SUCCESS; +} + +/** + * @brief Prepares card to handle read transaction. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[in] n number of blocks to read + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk, + uint32_t n, uint32_t *resp) { + + /* Driver handles data in 512 bytes blocks (just like HC cards). But if we + have not HC card than we must convert address from blocks to bytes.*/ + if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) + startblk *= MMCSD_BLOCK_SIZE; + + if (n > 1) { + /* Send read multiple blocks command to card.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + else { + /* Send read single block command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_SINGLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Prepares card to handle write transaction. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[in] n number of blocks to write + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk, + uint32_t n, uint32_t *resp) { + + /* Driver handles data in 512 bytes blocks (just like HC cards). But if we + have not HC card than we must convert address from blocks to bytes.*/ + if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) + startblk *= MMCSD_BLOCK_SIZE; + + if (n > 1) { + /* Write multiple blocks command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + else { + /* Write single block command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Wait end of data transaction and performs finalizations. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] n number of blocks in transaction + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + */ +static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n, + uint32_t *resp) { + + /* Note the mask is checked before going to sleep because the interrupt + may have occurred before reaching the critical zone.*/ + osalSysLock(); + if (sdcp->sdmmc->MASK != 0) + osalThreadSuspendS(&sdcp->thread); + if ((sdcp->sdmmc->STA & SDMMC_STA_DATAEND) == 0) { + osalSysUnlock(); + return HAL_FAILED; + } + + /* Waits for transfer completion at DMA level, then the stream is + disabled and cleared.*/ + dmaWaitCompletion(sdcp->dma); + + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + sdcp->sdmmc->DCTRL = 0; + osalSysUnlock(); + + /* Finalize transaction.*/ + if (n > 1) + return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); + + return HAL_SUCCESS; +} + +/** + * @brief Gets SDC errors. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] sta value of the STA register + * + * @notapi + */ +static void sdc_lld_collect_errors(SDCDriver *sdcp, uint32_t sta) { + uint32_t errors = SDC_NO_ERROR; + + if (sta & SDMMC_STA_CCRCFAIL) + errors |= SDC_CMD_CRC_ERROR; + if (sta & SDMMC_STA_DCRCFAIL) + errors |= SDC_DATA_CRC_ERROR; + if (sta & SDMMC_STA_CTIMEOUT) + errors |= SDC_COMMAND_TIMEOUT; + if (sta & SDMMC_STA_DTIMEOUT) + errors |= SDC_DATA_TIMEOUT; + if (sta & SDMMC_STA_TXUNDERR) + errors |= SDC_TX_UNDERRUN; + if (sta & SDMMC_STA_RXOVERR) + errors |= SDC_RX_OVERRUN; +/* if (sta & SDMMC_STA_STBITERR) + errors |= SDC_STARTBIT_ERROR;*/ + + sdcp->errors |= errors; +} + +/** + * @brief Performs clean transaction stopping in case of errors. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] n number of blocks in transaction + * @param[in] resp pointer to the response buffer + * + * @notapi + */ +static void sdc_lld_error_cleanup(SDCDriver *sdcp, + uint32_t n, + uint32_t *resp) { + uint32_t sta = sdcp->sdmmc->STA; + + dmaStreamDisable(sdcp->dma); + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + sdcp->sdmmc->MASK = 0; + sdcp->sdmmc->DCTRL = 0; + sdc_lld_collect_errors(sdcp, sta); + + if (n > 1) + sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief SDMMC1 IRQ handler. + * @details It just wakes transaction thread, errors handling is performed in + * there. + * + * @isr + */ +#if STM32_SDC_USE_SDMMC1 || defined(__DOXYGEN__) +OSAL_IRQ_HANDLER(STM32_SDMMC1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + osalSysLockFromISR(); + + /* Disables the source but the status flags are not reset because the + read/write functions needs to check them.*/ + SDMMC1->MASK = 0; + + osalThreadResumeI(&SDCD1.thread, MSG_OK); + + osalSysUnlockFromISR(); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/** + * @brief SDMMC2 IRQ handler. + * @details It just wakes transaction thread, errors handling is performed in + * there. + * + * @isr + */ +#if STM32_SDC_USE_SDMMC2 || defined(__DOXYGEN__) +OSAL_IRQ_HANDLER(STM32_SDMMC2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + osalSysLockFromISR(); + + /* Disables the source but the status flags are not reset because the + read/write functions needs to check them.*/ + SDMMC2->MASK = 0; + + osalThreadResumeI(&SDCD2.thread, MSG_OK); + + osalSysUnlockFromISR(); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SDC driver initialization. + * + * @notapi + */ +void sdc_lld_init(void) { + +#if STM32_SDC_USE_SDMMC1 + sdcObjectInit(&SDCD1); + SDCD1.thread = NULL; + SDCD1.rtmo = SDMMC1_READ_TIMEOUT; + SDCD1.wtmo = SDMMC1_WRITE_TIMEOUT; + SDCD1.dma = NULL; + SDCD1.sdmmc = SDMMC1; + nvicEnableVector(STM32_SDMMC1_NUMBER, STM32_SDC_SDMMC1_IRQ_PRIORITY); +#endif + +#if STM32_SDC_USE_SDMMC2 + sdcObjectInit(&SDCD2); + SDCD2.thread = NULL; + SDCD2.rtmo = SDMMC2_READ_TIMEOUT; + SDCD2.wtmo = SDMMC2_WRITE_TIMEOUT; + SDCD2.dma = NULL; + SDCD2.sdmmc = SDMMC2; + nvicEnableVector(STM32_SDMMC2_NUMBER, STM32_SDC_SDMMC2_IRQ_PRIORITY); +#endif +} + +/** + * @brief Configures and activates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_start(SDCDriver *sdcp) { + + /* Checking configuration, using a default if NULL has been passed.*/ + if (sdcp->config == NULL) { + sdcp->config = &sdc_default_cfg; + } + + sdcp->dmamode = STM32_DMA_CR_PSIZE_WORD | + STM32_DMA_CR_MSIZE_WORD | + STM32_DMA_CR_MINC; + +#if STM32_DMA_ADVANCED + sdcp->dmamode |= STM32_DMA_CR_PFCTRL | + STM32_DMA_CR_PBURST_INCR4 | + STM32_DMA_CR_MBURST_INCR4; +#endif + + /* If in stopped state then clocks are enabled and DMA initialized.*/ + if (sdcp->state == BLK_STOP) { +#if STM32_SDC_USE_SDMMC1 + if (&SDCD1 == sdcp) { + sdcp->dma = dmaStreamAllocI(STM32_SDC_SDMMC1_DMA_STREAM, + STM32_SDC_SDMMC1_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(sdcp->dma != NULL, "unable to allocate stream"); + + sdcp->dmamode |= STM32_DMA_CR_CHSEL(SDMMC1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SDC_SDMMC1_DMA_PRIORITY); + dmaStreamSetPeripheral(sdcp->dma, &sdcp->sdmmc->FIFO); +#if STM32_DMA_ADVANCED + dmaStreamSetFIFO(sdcp->dma, STM32_DMA_FCR_DMDIS | + STM32_DMA_FCR_FTH_FULL); +#endif + rccEnableSDMMC1(true); + } +#endif /* STM32_SDC_USE_SDMMC1 */ + +#if STM32_SDC_USE_SDMMC2 + if (&SDCD2 == sdcp) { + sdcp->dma = dmaStreamAllocI(STM32_SDC_SDMMC2_DMA_STREAM, + STM32_SDC_SDMMC2_IRQ_PRIORITY, + NULL, + NULL); + osalDbgAssert(sdcp->dma != NULL, "unable to allocate stream"); + + sdcp->dmamode |= STM32_DMA_CR_CHSEL(SDMMC2_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SDC_SDMMC2_DMA_PRIORITY); + dmaStreamSetPeripheral(sdcp->dma, &sdcp->sdmmc->FIFO); +#if STM32_DMA_ADVANCED + dmaStreamSetFIFO(sdcp->dma, STM32_DMA_FCR_DMDIS | + STM32_DMA_FCR_FTH_FULL); +#endif + rccEnableSDMMC2(true); + } +#endif /* STM32_SDC_USE_SDMMC2 */ + } + + /* Configuration, card clock is initially stopped.*/ + sdcp->sdmmc->POWER = 0; + sdcp->sdmmc->CLKCR = 0; + sdcp->sdmmc->DCTRL = 0; + sdcp->sdmmc->DTIMER = 0; +} + +/** + * @brief Deactivates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_stop(SDCDriver *sdcp) { + + if (sdcp->state != BLK_STOP) { + + /* SDIO deactivation.*/ + sdcp->sdmmc->POWER = 0; + sdcp->sdmmc->CLKCR = 0; + sdcp->sdmmc->DCTRL = 0; + sdcp->sdmmc->DTIMER = 0; + + /* DMA stream released.*/ + dmaStreamFreeI(sdcp->dma); + sdcp->dma = NULL; + + /* Clock deactivation.*/ +#if STM32_SDC_USE_SDMMC1 + if (&SDCD1 == sdcp) { + rccDisableSDMMC1(); + } +#endif + +#if STM32_SDC_USE_SDMMC2 + if (&SDCD2 == sdcp) { + rccDisableSDMMC2(); + } +#endif + } +} + +/** + * @brief Starts the SDIO clock and sets it to init mode (400kHz or less). + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_start_clk(SDCDriver *sdcp) { + + /* Initial clock setting: 400kHz, 1bit mode.*/ + sdcp->sdmmc->CLKCR = SDMMC_CLKDIV_LS; + sdcp->sdmmc->POWER |= SDMMC_POWER_PWRCTRL_0 | SDMMC_POWER_PWRCTRL_1; + sdcp->sdmmc->CLKCR |= SDMMC_CLKCR_CLKEN; + + /* Clock activation delay.*/ + osalThreadSleep(OSAL_MS2I(STM32_SDC_SDMMC_CLOCK_DELAY)); +} + +/** + * @brief Sets the SDIO clock to data mode (25/50 MHz or less). + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] clk the clock mode + * + * @notapi + */ +void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) { + +#if STM32_SDC_SDMMC_50MHZ + if (SDC_CLK_50MHz == clk) { + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | +#if STM32_SDC_SDMMC_PWRSAV + SDMMC_CLKDIV_HS | SDMMC_CLKCR_BYPASS | + SDMMC_CLKCR_PWRSAV; +#else + SDMMC_CLKDIV_HS | SDMMC_CLKCR_BYPASS; +#endif + } + else { +#if STM32_SDC_SDMMC_PWRSAV + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS | + SDMMC_CLKCR_PWRSAV; +#else + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS; +#endif + } +#else + (void)clk; + +#if STM32_SDC_SDMMC_PWRSAV + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS | + SDMMC_CLKCR_PWRSAV; +#else + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS; +#endif +#endif +} + +/** + * @brief Stops the SDIO clock. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_stop_clk(SDCDriver *sdcp) { + + sdcp->sdmmc->CLKCR = 0; + sdcp->sdmmc->POWER = 0; +} + +/** + * @brief Switches the bus to 1, 4 or 8 bits mode. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] mode bus mode + * + * @notapi + */ +void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) { + uint32_t clk = sdcp->sdmmc->CLKCR & ~SDMMC_CLKCR_WIDBUS; + + switch (mode) { + case SDC_MODE_1BIT: + sdcp->sdmmc->CLKCR = clk; + break; + case SDC_MODE_4BIT: + sdcp->sdmmc->CLKCR = clk | SDMMC_CLKCR_WIDBUS_0; + break; + case SDC_MODE_8BIT: + sdcp->sdmmc->CLKCR = clk | SDMMC_CLKCR_WIDBUS_1; + break; + } +} + +/** + * @brief Sends an SDIO command with no response expected. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * + * @notapi + */ +void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) { + + sdcp->sdmmc->ARG = arg; + sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_CPSMEN; + while ((sdcp->sdmmc->STA & SDMMC_STA_CMDSENT) == 0) + ; + sdcp->sdmmc->ICR = SDMMC_ICR_CMDSENTC; +} + +/** + * @brief Sends an SDIO command with a short response expected. + * @note The CRC is not verified. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (one word) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + sdcp->sdmmc->ARG = arg; + sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN; + while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL)) == 0) + ; + sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL); + if ((sta & (SDMMC_STA_CTIMEOUT)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + *resp = sdcp->sdmmc->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Sends an SDIO command with a short response expected and CRC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (one word) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + sdcp->sdmmc->ARG = arg; + sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN; + while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL)) == 0) + ; + sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | SDMMC_STA_CCRCFAIL); + if ((sta & (SDMMC_STA_CTIMEOUT | SDMMC_STA_CCRCFAIL)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + *resp = sdcp->sdmmc->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Sends an SDIO command with a long response expected and CRC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (four words) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + (void)sdcp; + + sdcp->sdmmc->ARG = arg; + sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_WAITRESP_1 | + SDMMC_CMD_CPSMEN; + while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL)) == 0) + ; + sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL); + if ((sta & (SDMMC_STA_ERROR_MASK)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + /* Save bytes in reverse order because MSB in response comes first.*/ + *resp++ = sdcp->sdmmc->RESP4; + *resp++ = sdcp->sdmmc->RESP3; + *resp++ = sdcp->sdmmc->RESP2; + *resp = sdcp->sdmmc->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Reads special registers using data bus. + * @details Needs only during card detection procedure. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] buf pointer to the read buffer + * @param[in] bytes number of bytes to read + * @param[in] cmd card command + * @param[in] arg argument for command + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, + uint8_t cmd, uint32_t arg) { + uint32_t resp[1]; + + if (sdc_lld_prepare_read_bytes(sdcp, buf, bytes)) + goto error; + + if (sdc_lld_send_cmd_short_crc(sdcp, cmd, arg, resp) + || MMCSD_R1_ERROR(resp[0])) + goto error; + + if (sdc_lld_wait_transaction_end(sdcp, 1, resp)) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, 1, resp); + return HAL_FAILED; +} + +/** + * @brief Reads one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[out] buf pointer to the read buffer + * @param[in] blocks number of blocks to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks) { + uint32_t resp[1]; + + osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); + + sdcp->sdmmc->DTIMER = sdcp->rtmo; + + /* Checks for errors and waits for the card to be ready for reading.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Prepares the DMA channel for writing.*/ + dmaStreamSetMemory0(sdcp->dma, buf); + dmaStreamSetTransactionSize(sdcp->dma, + (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); + dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); + dmaStreamEnable(sdcp->dma); + + /* Setting up data transfer.*/ + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE | + SDMMC_MASK_DTIMEOUTIE | + SDMMC_MASK_RXOVERRIE | + SDMMC_MASK_DATAENDIE; + sdcp->sdmmc->DLEN = blocks * MMCSD_BLOCK_SIZE; + + /* Transaction starts just after DTEN bit setting.*/ + sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DTDIR | + SDMMC_DCTRL_DBLOCKSIZE_3 | + SDMMC_DCTRL_DBLOCKSIZE_0 | + SDMMC_DCTRL_DMAEN | + SDMMC_DCTRL_DTEN; + + if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == true) + goto error; + + if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, blocks, resp); + return HAL_FAILED; +} + +/** + * @brief Writes one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to write + * @param[out] buf pointer to the write buffer + * @param[in] n number of blocks to write + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks) { + uint32_t resp[1]; + + osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); + + sdcp->sdmmc->DTIMER = sdcp->wtmo; + + /* Checks for errors and waits for the card to be ready for writing.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Prepares the DMA channel for writing.*/ + dmaStreamSetMemory0(sdcp->dma, buf); + dmaStreamSetTransactionSize(sdcp->dma, + (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); + dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_M2P); + dmaStreamEnable(sdcp->dma); + + /* Setting up data transfer.*/ + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE | + SDMMC_MASK_DTIMEOUTIE | + SDMMC_MASK_TXUNDERRIE | + SDMMC_MASK_DATAENDIE; + sdcp->sdmmc->DLEN = blocks * MMCSD_BLOCK_SIZE; + + /* Talk to card what we want from it.*/ + if (sdc_lld_prepare_write(sdcp, startblk, blocks, resp) == true) + goto error; + + /* Transaction starts just after DTEN bit setting.*/ + sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DBLOCKSIZE_3 | + SDMMC_DCTRL_DBLOCKSIZE_0 | + SDMMC_DCTRL_DMAEN | + SDMMC_DCTRL_DTEN; + + if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, blocks, resp); + return HAL_FAILED; +} + +/** + * @brief Reads one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[out] buf pointer to the read buffer + * @param[in] blocks number of blocks to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks) { + +#if STM32_SDC_SDMMC_UNALIGNED_SUPPORT + if (((unsigned)buf & 3) != 0) { + uint32_t i; + for (i = 0; i < blocks; i++) { + if (sdc_lld_read_aligned(sdcp, startblk, sdcp->buf, 1)) + return HAL_FAILED; + memcpy(buf, sdcp->buf, MMCSD_BLOCK_SIZE); + buf += MMCSD_BLOCK_SIZE; + startblk++; + } + return HAL_SUCCESS; + } +#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer"); +#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + return sdc_lld_read_aligned(sdcp, startblk, buf, blocks); +} + +/** + * @brief Writes one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to write + * @param[out] buf pointer to the write buffer + * @param[in] blocks number of blocks to write + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks) { + +#if STM32_SDC_SDMMC_UNALIGNED_SUPPORT + if (((unsigned)buf & 3) != 0) { + uint32_t i; + for (i = 0; i < blocks; i++) { + memcpy(sdcp->buf, buf, MMCSD_BLOCK_SIZE); + buf += MMCSD_BLOCK_SIZE; + if (sdc_lld_write_aligned(sdcp, startblk, sdcp->buf, 1)) + return HAL_FAILED; + startblk++; + } + return HAL_SUCCESS; + } +#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer"); +#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + return sdc_lld_write_aligned(sdcp, startblk, buf, blocks); +} + +/** + * @brief Waits for card idle condition. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool sdc_lld_sync(SDCDriver *sdcp) { + + /* CHTODO: Implement.*/ + (void)sdcp; + return HAL_SUCCESS; +} + +#endif /* HAL_USE_SDC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.h new file mode 100644 index 0000000..b9ad69c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.h @@ -0,0 +1,400 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SDMMCv1/hal_sdc_lld.h + * @brief STM32 SDC subsystem low level driver header. + * + * @addtogroup SDC + * @{ + */ + +#ifndef HAL_SDC_LLD_H +#define HAL_SDC_LLD_H + +#if HAL_USE_SDC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SDMMC1 driver enable switch. + * @details If set to @p TRUE the support for SDMMC1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SDC_USE_SDMMC1) || defined(__DOXYGEN__) +#define STM32_SDC_USE_SDMMC1 FALSE +#endif + +/** + * @brief SDMMC2 driver enable switch. + * @details If set to @p TRUE the support for SDMMC2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SDC_USE_SDMMC2) || defined(__DOXYGEN__) +#define STM32_SDC_USE_SDMMC2 FALSE +#endif + +/** + * @brief Support for unaligned transfers. + * @note Unaligned transfers are much slower. + */ +#if !defined(STM32_SDC_SDMMC_UNALIGNED_SUPPORT) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_UNALIGNED_SUPPORT TRUE +#endif + +/** + * @brief Enable clock bypass. + * @note Allow clock speed up to 50 Mhz. + */ +#if !defined(STM32_SDC_SDMMC_50MHZ) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_50MHZ FALSE +#endif + +/** + * @brief Write timeout in milliseconds. + */ +#if !defined(STM32_SDC_SDMMC_WRITE_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000 +#endif + +/** + * @brief Read timeout in milliseconds. + */ +#if !defined(STM32_SDC_SDMMC_READ_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_READ_TIMEOUT 1000 +#endif + +/** + * @brief Card clock activation delay in milliseconds. + */ +#if !defined(STM32_SDC_SDMMC_CLOCK_DELAY) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_CLOCK_DELAY 10 +#endif + +/** + * @brief Card clock power saving enable. + */ +#if !defined(STM32_SDC_SDMMC_PWRSAV) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_PWRSAV TRUE +#endif + +/** + * @brief SDMMC1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_SDC_SDMMC1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC1_DMA_PRIORITY 3 +#endif + +/** + * @brief SDMMC2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_SDC_SDMMC2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC2_DMA_PRIORITY 3 +#endif + +/** + * @brief SDMMC1 interrupt priority level setting. + */ +#if !defined(STM32_SDC_SDMMC1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC1_IRQ_PRIORITY 9 +#endif + +/** + * @brief SDMMC2 interrupt priority level setting. + */ +#if !defined(STM32_SDC_SDMMC2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC2_IRQ_PRIORITY 9 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks.*/ +#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDMMC1_HANDLER)) || \ + (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDMMC2_HANDLER)) +#error "STM32_SDMMCx_HANDLER not defined in registry" +#endif + +#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDMMC1_NUMBER)) || \ + (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDMMC2_NUMBER)) +#error "STM32_SDMMCx_NUMBER not defined in registry" +#endif + +#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDC_SDMMC1_DMA_MSK)) || \ + (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDC_SDMMC2_DMA_MSK)) +#error "STM32_SDC_SDMMCx_DMA_MSK not defined in registry" +#endif + +#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDC_SDMMC1_DMA_CHN)) || \ + (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDC_SDMMC2_DMA_CHN)) +#error "STM32_SDC_SDMMCx_DMA_CHN not defined in registry" +#endif + +/* Units checks.*/ +#if STM32_SDC_USE_SDMMC1 && !STM32_HAS_SDMMC1 +#error "SDMMC1 not present in the selected device" +#endif + +#if STM32_SDC_USE_SDMMC2 && !STM32_HAS_SDMMC2 +#error "SDMMC2 not present in the selected device" +#endif + +#if !STM32_SDC_USE_SDMMC1 && !STM32_SDC_USE_SDMMC2 +#error "SDC driver activated but no SDMMC peripheral assigned" +#endif + +/* Clock related tests.*/ +#if STM32_HAS_SDMMC1 && !defined(STM32_SDMMC1CLK) +#error "STM32_SDMMC1CLK not defined" +#endif + +/* Clock related tests.*/ +#if STM32_HAS_SDMMC2 && !defined(STM32_SDMMC2CLK) +#error "STM32_SDMMC2CLK not defined" +#endif + +#if !defined(STM32_HCLK) +#error "STM32_HCLK not defined" +#endif + +#if STM32_HAS_SDMMC1 && (STM32_SDMMC1CLK * 10 > STM32_HCLK * 7) +#error "STM32_SDMMC1CLK must not exceed STM32_HCLK * 0.7" +#endif + +#if STM32_HAS_SDMMC2 && (STM32_SDMMC2CLK * 10 > STM32_HCLK * 7) +#error "STM32_SDMMC2CLK must not exceed STM32_HCLK * 0.7" +#endif + +#if STM32_HAS_SDMMC1 && (STM32_SDMMC1CLK > 48000000) +#error "STM32_SDMMC1CLK must not exceed 48MHz" +#endif + +#if STM32_HAS_SDMMC2 && (STM32_SDMMC2CLK > 48000000) +#error "STM32_SDMMC2CLK must not exceed 48MHz" +#endif + +#if defined(STM32_SDC_SDMMC_50MHZ) && STM32_SDC_SDMMC_50MHZ && !defined(STM32F7XX) +#error "50 Mhz clock only works for STM32F7XX" +#endif + +/* SDMMC IRQ priority tests.*/ +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SDC_SDMMC1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SDMMC1" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SDC_SDMMC2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SDMMC2" +#endif + +/* DMA priority tests.*/ +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_SDC_SDMMC1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SDMMC1" +#endif + +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_SDC_SDMMC2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SDMMC2" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_SDC_USE_SDMMC1 && !defined(STM32_SDC_SDMMC1_DMA_STREAM) +#error "SDMMC1 DMA streams not defined" +#endif + +#if STM32_SDC_USE_SDMMC2 && !defined(STM32_SDC_SDMMC2_DMA_STREAM) +#error "SDMMC2 DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_SDC_USE_SDMMC1 && \ + !STM32_DMA_IS_VALID_ID(STM32_SDC_SDMMC1_DMA_STREAM, STM32_SDC_SDMMC1_DMA_MSK) +#error "invalid DMA stream associated to SDMMC1" +#endif + +#if STM32_SDC_USE_SDMMC2 && \ + !STM32_DMA_IS_VALID_ID(STM32_SDC_SDMMC2_DMA_STREAM, STM32_SDC_SDMMC2_DMA_MSK) +#error "invalid DMA stream associated to SDMMC2" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of card flags. + */ +typedef uint32_t sdcmode_t; + +/** + * @brief SDC Driver condition flags type. + */ +typedef uint32_t sdcflags_t; + +/** + * @brief Type of a structure representing an SDC driver. + */ +typedef struct SDCDriver SDCDriver; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Bus width. + */ + sdcbusmode_t bus_width; + /* End of the mandatory fields.*/ +} SDCConfig; + +/** + * @brief @p SDCDriver specific methods. + */ +#define _sdc_driver_methods \ + _mmcsd_block_device_methods + +/** + * @extends MMCSDBlockDeviceVMT + * + * @brief @p SDCDriver virtual methods table. + */ +struct SDCDriverVMT { + _sdc_driver_methods +}; + +/** + * @brief Structure representing an SDC driver. + */ +struct SDCDriver { + /** + * @brief Virtual Methods Table. + */ + const struct SDCDriverVMT *vmt; + _mmcsd_block_device_data + /** + * @brief Current configuration data. + */ + const SDCConfig *config; + /** + * @brief Various flags regarding the mounted card. + */ + sdcmode_t cardmode; + /** + * @brief Errors flags. + */ + sdcflags_t errors; + /** + * @brief Card RCA. + */ + uint32_t rca; + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion IRQ. + */ + thread_reference_t thread; + /** + * @brief DTIMER register value for read operations. + */ + uint32_t rtmo; + /** + * @brief DTIMER register value for write operations. + */ + uint32_t wtmo; + /** + * @brief DMA mode bit mask. + */ + uint32_t dmamode; + /** + * @brief Transmit DMA channel. + */ + const stm32_dma_stream_t *dma; + /** + * @brief Pointer to the SDMMC registers block. + * @note Needed for debugging aid. + */ + SDMMC_TypeDef *sdmmc; + /** + * @brief Buffer for internal operations. + */ + uint8_t buf[MMCSD_BLOCK_SIZE]; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_SDC_USE_SDMMC1 && !defined(__DOXYGEN__) +extern SDCDriver SDCD1; +#endif + +#if STM32_SDC_USE_SDMMC2 && !defined(__DOXYGEN__) +extern SDCDriver SDCD2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sdc_lld_init(void); + void sdc_lld_start(SDCDriver *sdcp); + void sdc_lld_stop(SDCDriver *sdcp); + void sdc_lld_start_clk(SDCDriver *sdcp); + void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk); + void sdc_lld_stop_clk(SDCDriver *sdcp); + void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode); + void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg); + bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, + uint8_t cmd, uint32_t argument); + bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks); + bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks); + bool sdc_lld_sync(SDCDriver *sdcp); + bool sdc_lld_is_card_inserted(SDCDriver *sdcp); + bool sdc_lld_is_write_protected(SDCDriver *sdcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SDC */ + +#endif /* HAL_SDC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk new file mode 100644 index 0000000..cf8b9d2 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv2 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c new file mode 100644 index 0000000..9740df2 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c @@ -0,0 +1,865 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SDMMCv2/hal_sdc_lld.c + * @brief STM32 SDC subsystem low level driver source. + * + * @addtogroup SDC + * @{ + */ + +#include + +#include "hal.h" + +#if HAL_USE_SDC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define SDMMC_ICR_ALL_FLAGS 0xFFFFFFFFU + +#define SDMMC_STA_ERROR_MASK \ + (SDMMC_STA_CCRCFAIL | SDMMC_STA_DCRCFAIL | \ + SDMMC_STA_CTIMEOUT | SDMMC_STA_DTIMEOUT | \ + SDMMC_STA_TXUNDERR | SDMMC_STA_RXOVERR) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief SDCD1 driver identifier.*/ +#if STM32_SDC_USE_SDMMC1 || defined(__DOXYGEN__) +SDCDriver SDCD1; +#endif + +/** @brief SDCD2 driver identifier.*/ +#if STM32_SDC_USE_SDMMC2 || defined(__DOXYGEN__) +SDCDriver SDCD2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief SDIO default configuration. + */ +static const SDCConfig sdc_default_cfg = { + SDC_MODE_4BIT +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Calculates a clock divider for the specified frequency. + * @note The divider is calculated to not exceed the required frequency + * in case of non-integer division. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] f required frequency + */ +static uint32_t sdc_lld_clkdiv(SDCDriver *sdcp, uint32_t f) { + + if (f >= sdcp->clkfreq) { + return 0; + } + + return (sdcp->clkfreq + (f * 2) - 1) / (f * 2); +} + +/** + * @brief Prepares to handle read transaction. + * @details Designed for read special registers from card. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] buf pointer to the read buffer + * @param[in] bytes number of bytes to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp, + uint8_t *buf, uint32_t bytes) { + osalDbgCheck(bytes < 0x1000000); + + sdcp->sdmmc->DTIMER = STM32_SDC_SDMMC_READ_TIMEOUT; + + /* Checks for errors and waits for the card to be ready for reading.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Setting up data transfer.*/ + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE | + SDMMC_MASK_DTIMEOUTIE | + SDMMC_MASK_RXOVERRIE | + SDMMC_MASK_DATAENDIE; + sdcp->sdmmc->DLEN = bytes; + + /* Transfer modes.*/ + sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DTDIR | + SDMMC_DCTRL_DTMODE_0; /* Multibyte data transfer.*/ + + /* Prepares IDMA.*/ + sdcp->sdmmc->IDMABASE0 = (uint32_t)buf; + sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN; + + return HAL_SUCCESS; +} + +/** + * @brief Prepares card to handle read transaction. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[in] n number of blocks to read + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk, + uint32_t n, uint32_t *resp) { + + /* Driver handles data in 512 bytes blocks (just like HC cards). But if we + have not HC card than we must convert address from blocks to bytes.*/ + if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) + startblk *= MMCSD_BLOCK_SIZE; + + if (n > 1) { + /* Send read multiple blocks command to card.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_READ_MULTIPLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + else { + /* Send read single block command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_READ_SINGLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Prepares card to handle write transaction. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[in] n number of blocks to write + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk, + uint32_t n, uint32_t *resp) { + + /* Driver handles data in 512 bytes blocks (just like HC cards). But if we + have not HC card than we must convert address from blocks to bytes.*/ + if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) + startblk *= MMCSD_BLOCK_SIZE; + + if (n > 1) { + /* Write multiple blocks command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_WRITE_MULTIPLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + else { + /* Write single block command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_WRITE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Wait end of data transaction and performs finalizations. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] n number of blocks in transaction + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + */ +static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n, + uint32_t *resp) { + + /* Note the mask is checked before going to sleep because the interrupt + may have occurred before reaching the critical zone.*/ + osalSysLock(); + if (sdcp->sdmmc->MASK != 0) + osalThreadSuspendS(&sdcp->thread); + + /* Stopping operations.*/ + sdcp->sdmmc->IDMACTRL = 0; + sdcp->sdmmc->MASK = 0; + sdcp->sdmmc->DCTRL = 0; + + if ((sdcp->sdmmc->STA & SDMMC_STA_DATAEND) == 0) { + osalSysUnlock(); + return HAL_FAILED; + } + + /* Clearing status.*/ + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + osalSysUnlock(); + + /* Finalize transaction.*/ + if (n > 1) + return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); + + return HAL_SUCCESS; +} + +/** + * @brief Gets SDC errors. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] sta value of the STA register + * + * @notapi + */ +static void sdc_lld_collect_errors(SDCDriver *sdcp, uint32_t sta) { + uint32_t errors = SDC_NO_ERROR; + + if (sta & SDMMC_STA_CCRCFAIL) + errors |= SDC_CMD_CRC_ERROR; + if (sta & SDMMC_STA_DCRCFAIL) + errors |= SDC_DATA_CRC_ERROR; + if (sta & SDMMC_STA_CTIMEOUT) + errors |= SDC_COMMAND_TIMEOUT; + if (sta & SDMMC_STA_DTIMEOUT) + errors |= SDC_DATA_TIMEOUT; + if (sta & SDMMC_STA_TXUNDERR) + errors |= SDC_TX_UNDERRUN; + if (sta & SDMMC_STA_RXOVERR) + errors |= SDC_RX_OVERRUN; +/* if (sta & SDMMC_STA_STBITERR) + errors |= SDC_STARTBIT_ERROR;*/ + + sdcp->errors |= errors; +} + +/** + * @brief Performs clean transaction stopping in case of errors. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] n number of blocks in transaction + * @param[in] resp pointer to the response buffer + * + * @notapi + */ +static void sdc_lld_error_cleanup(SDCDriver *sdcp, + uint32_t n, + uint32_t *resp) { + uint32_t sta = sdcp->sdmmc->STA; + + /* Clearing status.*/ + sta = sdcp->sdmmc->STA; + sdcp->sdmmc->ICR = sta; + sdc_lld_collect_errors(sdcp, sta); + + if (n > 1) + sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SDC driver initialization. + * + * @notapi + */ +void sdc_lld_init(void) { + +#if STM32_SDC_USE_SDMMC1 + sdcObjectInit(&SDCD1); + SDCD1.thread = NULL; + SDCD1.sdmmc = SDMMC1; + SDCD1.clkfreq = STM32_SDMMC1CLK; +#endif + +#if STM32_SDC_USE_SDMMC2 + sdcObjectInit(&SDCD2); + SDCD2.thread = NULL; + SDCD2.sdmmc = SDMMC2; + SDCD2.clkfreq = STM32_SDMMC2CLK; +#endif +} + +/** + * @brief Configures and activates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_start(SDCDriver *sdcp) { + + /* Checking configuration, using a default if NULL has been passed.*/ + if (sdcp->config == NULL) { + sdcp->config = &sdc_default_cfg; + } + + /* If in stopped state then clocks are enabled and DMA initialized.*/ + if (sdcp->state == BLK_STOP) { +#if STM32_SDC_USE_SDMMC1 + if (&SDCD1 == sdcp) { + rccEnableSDMMC1(true); + } +#endif /* STM32_SDC_USE_SDMMC1 */ + +#if STM32_SDC_USE_SDMMC2 + if (&SDCD2 == sdcp) { + rccEnableSDMMC2(true); + } +#endif /* STM32_SDC_USE_SDMMC2 */ + } + + /* Configuration, card clock is initially stopped.*/ + sdcp->sdmmc->IDMACTRL = 0; + sdcp->sdmmc->DCTRL = 0; + sdcp->sdmmc->POWER = 0; + sdcp->sdmmc->CLKCR = 0; + sdcp->sdmmc->DTIMER = 0; + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; +} + +/** + * @brief Deactivates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_stop(SDCDriver *sdcp) { + + if (sdcp->state != BLK_STOP) { + + /* SDIO deactivation.*/ + sdcp->sdmmc->IDMACTRL = 0; + sdcp->sdmmc->DCTRL = 0; + sdcp->sdmmc->POWER = 0; + sdcp->sdmmc->CLKCR = 0; + sdcp->sdmmc->DTIMER = 0; + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + + /* Clock deactivation.*/ +#if STM32_SDC_USE_SDMMC1 + if (&SDCD1 == sdcp) { + rccDisableSDMMC1(); + } +#endif + +#if STM32_SDC_USE_SDMMC2 + if (&SDCD2 == sdcp) { + rccDisableSDMMC2(); + } +#endif + } +} + +/** + * @brief Starts the SDIO clock and sets it to init mode (400kHz or less). + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_start_clk(SDCDriver *sdcp) { + + /* Initial clock setting: 400kHz, 1bit mode.*/ + sdcp->sdmmc->CLKCR = sdc_lld_clkdiv(sdcp, 4000000); + sdcp->sdmmc->POWER |= SDMMC_POWER_PWRCTRL_0 | SDMMC_POWER_PWRCTRL_1; +/* TODO sdcp->sdmmc->CLKCR |= SDMMC_CLKCR_CLKEN;*/ + + /* Clock activation delay.*/ + osalThreadSleep(OSAL_MS2I(STM32_SDC_SDMMC_CLOCK_DELAY)); +} + +/** + * @brief Sets the SDIO clock to data mode (25/50 MHz or less). + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] clk the clock mode + * + * @notapi + */ +void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) { + + if (SDC_CLK_50MHz == clk) { + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | +#if STM32_SDC_SDMMC_PWRSAV + sdc_lld_clkdiv(sdcp, 50000000) | SDMMC_CLKCR_PWRSAV; +#else + sdc_lld_clkdiv(sdcp, 50000000); +#endif + } + else { +#if STM32_SDC_SDMMC_PWRSAV + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | + sdc_lld_clkdiv(sdcp, 25000000) | SDMMC_CLKCR_PWRSAV; +#else + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | + sdc_lld_clkdiv(sdcp, 25000000); +#endif + } +} + +/** + * @brief Stops the SDIO clock. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_stop_clk(SDCDriver *sdcp) { + + sdcp->sdmmc->CLKCR = 0; + sdcp->sdmmc->POWER = 0; +} + +/** + * @brief Switches the bus to 1, 4 or 8 bits mode. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] mode bus mode + * + * @notapi + */ +void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) { + uint32_t clk = sdcp->sdmmc->CLKCR & ~SDMMC_CLKCR_WIDBUS; + + switch (mode) { + case SDC_MODE_1BIT: + sdcp->sdmmc->CLKCR = clk; + break; + case SDC_MODE_4BIT: + sdcp->sdmmc->CLKCR = clk | SDMMC_CLKCR_WIDBUS_0; + break; + case SDC_MODE_8BIT: + sdcp->sdmmc->CLKCR = clk | SDMMC_CLKCR_WIDBUS_1; + break; + } +} + +/** + * @brief Sends an SDIO command with no response expected. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * + * @notapi + */ +void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) { + + sdcp->sdmmc->ARG = arg; + sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_CPSMEN; + while ((sdcp->sdmmc->STA & SDMMC_STA_CMDSENT) == 0) + ; + sdcp->sdmmc->ICR = SDMMC_ICR_CMDSENTC; +} + +/** + * @brief Sends an SDIO command with a short response expected. + * @note The CRC is not verified. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (one word) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + sdcp->sdmmc->ARG = arg; + sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN; + while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL)) == 0) + ; + sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL); + if ((sta & (SDMMC_STA_CTIMEOUT)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + *resp = sdcp->sdmmc->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Sends an SDIO command with a short response expected and CRC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (one word) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + sdcp->sdmmc->ARG = arg; + sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN; + while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL)) == 0) + ; + sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL); + if ((sta & (SDMMC_STA_CTIMEOUT | SDMMC_STA_CCRCFAIL)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + *resp = sdcp->sdmmc->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Sends an SDIO command with a long response expected and CRC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (four words) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + (void)sdcp; + + sdcp->sdmmc->ARG = arg; + sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_WAITRESP_1 | + SDMMC_CMD_CPSMEN; + while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL)) == 0) + ; + sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | + SDMMC_STA_CCRCFAIL); + if ((sta & (SDMMC_STA_ERROR_MASK)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + /* Save bytes in reverse order because MSB in response comes first.*/ + *resp++ = sdcp->sdmmc->RESP4; + *resp++ = sdcp->sdmmc->RESP3; + *resp++ = sdcp->sdmmc->RESP2; + *resp = sdcp->sdmmc->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Reads special registers using data bus. + * @details Needs only during card detection procedure. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] buf pointer to the read buffer + * @param[in] bytes number of bytes to read + * @param[in] cmd card command + * @param[in] arg argument for command + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, + uint8_t cmd, uint32_t arg) { + uint32_t resp[1]; + + if (sdc_lld_prepare_read_bytes(sdcp, buf, bytes)) + goto error; + + if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | cmd, arg, resp) || + MMCSD_R1_ERROR(resp[0])) + goto error; + + if (sdc_lld_wait_transaction_end(sdcp, 1, resp)) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, 1, resp); + return HAL_FAILED; +} + +/** + * @brief Reads one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[out] buf pointer to the read buffer + * @param[in] blocks number of blocks to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks) { + uint32_t resp[1]; + + osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); + + sdcp->sdmmc->DTIMER = STM32_SDC_SDMMC_READ_TIMEOUT; + + /* Checks for errors and waits for the card to be ready for reading.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Setting up data transfer.*/ + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE | + SDMMC_MASK_DTIMEOUTIE | + SDMMC_MASK_RXOVERRIE | + SDMMC_MASK_DATAENDIE; + sdcp->sdmmc->DLEN = blocks * MMCSD_BLOCK_SIZE; + + /* Transfer modes.*/ + sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DTDIR | + SDMMC_DCTRL_DBLOCKSIZE_3 | + SDMMC_DCTRL_DBLOCKSIZE_0; + + /* Prepares IDMA.*/ + sdcp->sdmmc->IDMABASE0 = (uint32_t)buf; + sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN; + + if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == true) + goto error; + + if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, blocks, resp); + return HAL_FAILED; +} + +/** + * @brief Writes one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to write + * @param[out] buf pointer to the write buffer + * @param[in] n number of blocks to write + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks) { + uint32_t resp[1]; + + osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); + + sdcp->sdmmc->DTIMER = STM32_SDC_SDMMC_WRITE_TIMEOUT; + + /* Checks for errors and waits for the card to be ready for writing.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Setting up data transfer.*/ + sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; + sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE | + SDMMC_MASK_DTIMEOUTIE | + SDMMC_MASK_TXUNDERRIE | + SDMMC_MASK_DATAENDIE; + sdcp->sdmmc->DLEN = blocks * MMCSD_BLOCK_SIZE; + + /* Transfer modes.*/ + sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DBLOCKSIZE_3 | + SDMMC_DCTRL_DBLOCKSIZE_0; + + /* Prepares IDMA.*/ + sdcp->sdmmc->IDMABASE0 = (uint32_t)buf; + sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN; + + if (sdc_lld_prepare_write(sdcp, startblk, blocks, resp) == true) + goto error; + + if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, blocks, resp); + return HAL_FAILED; +} + +/** + * @brief Reads one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[out] buf pointer to the read buffer + * @param[in] blocks number of blocks to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks) { + +#if STM32_SDC_SDMMC_UNALIGNED_SUPPORT + if (((unsigned)buf & 3) != 0) { + uint32_t i; + for (i = 0; i < blocks; i++) { + if (sdc_lld_read_aligned(sdcp, startblk, sdcp->buf, 1)) + return HAL_FAILED; + memcpy(buf, sdcp->buf, MMCSD_BLOCK_SIZE); + buf += MMCSD_BLOCK_SIZE; + startblk++; + } + return HAL_SUCCESS; + } +#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer"); +#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + return sdc_lld_read_aligned(sdcp, startblk, buf, blocks); +} + +/** + * @brief Writes one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to write + * @param[out] buf pointer to the write buffer + * @param[in] blocks number of blocks to write + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks) { + +#if STM32_SDC_SDMMC_UNALIGNED_SUPPORT + if (((unsigned)buf & 3) != 0) { + uint32_t i; + for (i = 0; i < blocks; i++) { + memcpy(sdcp->buf, buf, MMCSD_BLOCK_SIZE); + buf += MMCSD_BLOCK_SIZE; + if (sdc_lld_write_aligned(sdcp, startblk, sdcp->buf, 1)) + return HAL_FAILED; + startblk++; + } + return HAL_SUCCESS; + } +#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer"); +#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + return sdc_lld_write_aligned(sdcp, startblk, buf, blocks); +} + +/** + * @brief Waits for card idle condition. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool sdc_lld_sync(SDCDriver *sdcp) { + + /* CHTODO: Implement.*/ + (void)sdcp; + return HAL_SUCCESS; +} + +/** + * @brief Shared service routine. + * + * @param[in] sdcp pointer to the @p SDCDriver object + */ +void sdc_lld_serve_interrupt(SDCDriver *sdcp) { + + /* Disables the source but the status flags are not reset because the + read/write functions needs to check them.*/ + sdcp->sdmmc->MASK = 0; + + osalSysLockFromISR(); + osalThreadResumeI(&sdcp->thread, MSG_OK); + osalSysUnlockFromISR(); +} + +#endif /* HAL_USE_SDC */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h new file mode 100644 index 0000000..334bf7a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h @@ -0,0 +1,301 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SDMMCv2/hal_sdc_lld.h + * @brief STM32 SDC subsystem low level driver header. + * + * @addtogroup SDC + * @{ + */ + +#ifndef HAL_SDC_LLD_H +#define HAL_SDC_LLD_H + +#if HAL_USE_SDC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SDMMC1 driver enable switch. + * @details If set to @p TRUE the support for SDMMC1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SDC_USE_SDMMC1) || defined(__DOXYGEN__) +#define STM32_SDC_USE_SDMMC1 FALSE +#endif + +/** + * @brief SDMMC2 driver enable switch. + * @details If set to @p TRUE the support for SDMMC2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SDC_USE_SDMMC2) || defined(__DOXYGEN__) +#define STM32_SDC_USE_SDMMC2 FALSE +#endif + +/** + * @brief Support for unaligned transfers. + * @note Unaligned transfers are much slower. + */ +#if !defined(STM32_SDC_SDMMC_UNALIGNED_SUPPORT) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_UNALIGNED_SUPPORT TRUE +#endif + +/** + * @brief Write timeout in card clock cycles. + */ +#if !defined(STM32_SDC_SDMMC_WRITE_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000000 +#endif + +/** + * @brief Read timeout in card clock cycles. + */ +#if !defined(STM32_SDC_SDMMC_READ_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_READ_TIMEOUT 1000000 +#endif + +/** + * @brief Card clock activation delay in milliseconds. + */ +#if !defined(STM32_SDC_SDMMC_CLOCK_DELAY) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_CLOCK_DELAY 10 +#endif + +/** + * @brief Card clock power saving enable. + */ +#if !defined(STM32_SDC_SDMMC_PWRSAV) || defined(__DOXYGEN__) +#define STM32_SDC_SDMMC_PWRSAV TRUE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks.*/ +#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDMMC1_HANDLER)) || \ + (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDMMC2_HANDLER)) +#error "STM32_SDMMCx_HANDLER not defined in registry" +#endif + +#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDMMC1_NUMBER)) || \ + (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDMMC2_NUMBER)) +#error "STM32_SDMMCx_NUMBER not defined in registry" +#endif + +/* Units checks.*/ +#if STM32_SDC_USE_SDMMC1 && !STM32_HAS_SDMMC1 +#error "SDMMC1 not present in the selected device" +#endif + +#if STM32_SDC_USE_SDMMC2 && !STM32_HAS_SDMMC2 +#error "SDMMC2 not present in the selected device" +#endif + +#if !STM32_SDC_USE_SDMMC1 && !STM32_SDC_USE_SDMMC2 +#error "SDC driver activated but no SDMMC peripheral assigned" +#endif + +/* Clock related tests.*/ +#if STM32_HAS_SDMMC1 && !defined(STM32_SDMMC1CLK) +#error "STM32_SDMMC1CLK not defined" +#endif + +/* Clock related tests.*/ +#if STM32_HAS_SDMMC2 && !defined(STM32_SDMMC2CLK) +#error "STM32_SDMMC2CLK not defined" +#endif + +#if !defined(STM32_HCLK) +#error "STM32_HCLK not defined" +#endif + +#if STM32_HAS_SDMMC1 && (STM32_SDMMC1CLK * 10 > STM32_HCLK * 7) +#error "STM32_SDMMC1CLK must not exceed STM32_HCLK * 0.7" +#endif + +#if STM32_HAS_SDMMC2 && (STM32_SDMMC2CLK * 10 > STM32_HCLK * 7) +#error "STM32_SDMMC2CLK must not exceed STM32_HCLK * 0.7" +#endif + +#if !defined(STM32_SDMMC_MAXCLK) +#define STM32_SDMMC_MAXCLK 50000000 +#endif + +#if STM32_HAS_SDMMC1 && (STM32_SDMMC1CLK > STM32_SDMMC_MAXCLK) +#error "STM32_SDMMC1CLK must not exceed STM32_SDMMC_MAXCLK" +#endif + +#if STM32_HAS_SDMMC2 && (STM32_SDMMC2CLK > STM32_SDMMC_MAXCLK) +#error "STM32_SDMMC2CLK must not exceed STM32_SDMMC_MAXCLK" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of card flags. + */ +typedef uint32_t sdcmode_t; + +/** + * @brief SDC Driver condition flags type. + */ +typedef uint32_t sdcflags_t; + +/** + * @brief Type of a structure representing an SDC driver. + */ +typedef struct SDCDriver SDCDriver; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Bus width. + */ + sdcbusmode_t bus_width; + /* End of the mandatory fields.*/ +} SDCConfig; + +/** + * @brief @p SDCDriver specific methods. + */ +#define _sdc_driver_methods \ + _mmcsd_block_device_methods + +/** + * @extends MMCSDBlockDeviceVMT + * + * @brief @p SDCDriver virtual methods table. + */ +struct SDCDriverVMT { + _sdc_driver_methods +}; + +/** + * @brief Structure representing an SDC driver. + */ +struct SDCDriver { + /** + * @brief Virtual Methods Table. + */ + const struct SDCDriverVMT *vmt; + _mmcsd_block_device_data + /** + * @brief Current configuration data. + */ + const SDCConfig *config; + /** + * @brief Various flags regarding the mounted card. + */ + sdcmode_t cardmode; + /** + * @brief Errors flags. + */ + sdcflags_t errors; + /** + * @brief Card RCA. + */ + uint32_t rca; + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion IRQ. + */ + thread_reference_t thread; + /** + * @brief Pointer to the SDMMC registers block. + * @note Needed for debugging aid. + */ + SDMMC_TypeDef *sdmmc; + /** + * @brief Input clock frequency. + */ + uint32_t clkfreq; + /** + * @brief Buffer for internal operations. + */ + uint8_t buf[MMCSD_BLOCK_SIZE]; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_SDC_USE_SDMMC1 && !defined(__DOXYGEN__) +extern SDCDriver SDCD1; +#endif + +#if STM32_SDC_USE_SDMMC2 && !defined(__DOXYGEN__) +extern SDCDriver SDCD2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sdc_lld_init(void); + void sdc_lld_start(SDCDriver *sdcp); + void sdc_lld_stop(SDCDriver *sdcp); + void sdc_lld_start_clk(SDCDriver *sdcp); + void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk); + void sdc_lld_stop_clk(SDCDriver *sdcp); + void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode); + void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg); + bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, + uint8_t cmd, uint32_t argument); + bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks); + bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks); + bool sdc_lld_sync(SDCDriver *sdcp); + bool sdc_lld_is_card_inserted(SDCDriver *sdcp); + bool sdc_lld_is_write_protected(SDCDriver *sdcp); + void sdc_lld_serve_interrupt(SDCDriver *sdcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SDC */ + +#endif /* HAL_SDC_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc1.inc new file mode 100644 index 0000000..ae7b38e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc1.inc @@ -0,0 +1,110 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SDMMCv2/stm32_sdmmc1.inc + * @brief Shared SDMMC1 handler. + * + * @addtogroup STM32_SDMMC1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_SDMMC1) +#error "STM32_HAS_SDMMC1 not defined in registry" +#endif + +#if STM32_HAS_SDMMC1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_SDMMC1_PRIORITY) +#error "STM32_IRQ_SDMMC1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_SDMMC1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_SDMMC1_PRIORITY" +#endif + +#endif /* STM32_HAS_SDMMC1 */ + +/* Other checks.*/ +#if (HAL_USE_SDC && STM32_SDC_USE_SDMMC1) +#define STM32_SDMMC1_IS_USED TRUE +#else +#define STM32_SDMMC1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void sdmmc1_irq_init(void) { +#if STM32_SDMMC1_IS_USED + nvicEnableVector(STM32_SDMMC1_NUMBER, STM32_IRQ_SDMMC1_PRIORITY); +#endif +} + +static inline void sdmmc1_irq_deinit(void) { +#if STM32_SDMMC1_IS_USED + nvicDisableVector(STM32_SDMMC1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_SDMMC1_IS_USED|| defined(__DOXYGEN__) +/** + * @brief SDMMC1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SDMMC1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SDC +#if STM32_SDC_USE_SDMMC1 + sdc_lld_serve_interrupt(&SDCD1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc2.inc new file mode 100644 index 0000000..75c614c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc2.inc @@ -0,0 +1,110 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SDMMCv2/stm32_sdmmc2.inc + * @brief Shared SDMMC2 handler. + * + * @addtogroup STM32_SDMMC2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_SDMMC2) +#error "STM32_HAS_SDMMC2 not defined in registry" +#endif + +#if STM32_HAS_SDMMC2 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_SDMMC2_PRIORITY) +#error "STM32_IRQ_SDMMC2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_SDMMC2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_SDMMC2_PRIORITY" +#endif + +#endif /* STM32_HAS_SDMMC2 */ + +/* Other checks.*/ +#if (HAL_USE_SDC && STM32_SDC_USE_SDMMC2) +#define STM32_SDMMC2_IS_USED TRUE +#else +#define STM32_SDMMC2_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void sdmmc2_irq_init(void) { +#if STM32_SDMMC2_IS_USED + nvicEnableVector(STM32_SDMMC2_NUMBER, STM32_IRQ_SDMMC2_PRIORITY); +#endif +} + +static inline void sdmmc2_irq_deinit(void) { +#if STM32_SDMMC2_IS_USED + nvicDisableVector(STM32_SDMMC2_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_SDMMC2_IS_USED|| defined(__DOXYGEN__) +/** + * @brief SDMMC2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SDMMC2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SDC +#if STM32_SDC_USE_SDMMC2 + sdc_lld_serve_interrupt(&SDCD2); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/driver.mk new file mode 100644 index 0000000..1af9692 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/driver.mk @@ -0,0 +1,13 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_I2S TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c +endif +ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c new file mode 100644 index 0000000..235d2b8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c @@ -0,0 +1,584 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv1/hal_i2s_lld.c + * @brief STM32 I2S subsystem low level driver source. + * + * @addtogroup I2S + * @{ + */ + +#include "hal.h" + +#if HAL_USE_I2S || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define I2S1_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI1_RX_DMA_STREAM, \ + STM32_SPI1_RX_DMA_CHN) + +#define I2S1_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI1_TX_DMA_STREAM, \ + STM32_SPI1_TX_DMA_CHN) + +#define I2S2_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI2_RX_DMA_STREAM, \ + STM32_SPI2_RX_DMA_CHN) + +#define I2S2_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI2_TX_DMA_STREAM, \ + STM32_SPI2_TX_DMA_CHN) + +#define I2S3_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI3_RX_DMA_STREAM, \ + STM32_SPI3_RX_DMA_CHN) + +#define I2S3_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI3_TX_DMA_STREAM, \ + STM32_SPI3_TX_DMA_CHN) + +/* + * Static I2S settings for I2S1. + */ +#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) +#define STM32_I2S1_CFGR_CFG 0 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) +#define STM32_I2S1_CFGR_CFG SPI_I2SCFGR_I2SCFG_0 +#endif +#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) */ +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) +#define STM32_I2S1_CFGR_CFG SPI_I2SCFGR_I2SCFG_1 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) +#define STM32_I2S1_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \ + SPI_I2SCFGR_I2SCFG_0) +#endif +#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) */ + +/* + * Static I2S settings for I2S2. + */ +#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) +#define STM32_I2S2_CFGR_CFG 0 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) +#define STM32_I2S2_CFGR_CFG SPI_I2SCFGR_I2SCFG_0 +#endif +#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) */ +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) +#define STM32_I2S2_CFGR_CFG SPI_I2SCFGR_I2SCFG_1 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) +#define STM32_I2S2_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \ + SPI_I2SCFGR_I2SCFG_0) +#endif +#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) */ + +/* + * Static I2S settings for I2S3. + */ +#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) +#define STM32_I2S3_CFGR_CFG 0 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) +#define STM32_I2S3_CFGR_CFG SPI_I2SCFGR_I2SCFG_0 +#endif +#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) */ +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) +#define STM32_I2S3_CFGR_CFG SPI_I2SCFGR_I2SCFG_1 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) +#define STM32_I2S3_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \ + SPI_I2SCFGR_I2SCFG_0) +#endif +#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief I2S1 driver identifier.*/ +#if STM32_I2S_USE_SPI1 || defined(__DOXYGEN__) +I2SDriver I2SD1; +#endif + +/** @brief I2S2 driver identifier.*/ +#if STM32_I2S_USE_SPI2 || defined(__DOXYGEN__) +I2SDriver I2SD2; +#endif + +/** @brief I2S3 driver identifier.*/ +#if STM32_I2S_USE_SPI3 || defined(__DOXYGEN__) +I2SDriver I2SD3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) || \ + STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) || \ + STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__) +/** + * @brief Shared end-of-rx service routine. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void i2s_lld_serve_rx_interrupt(I2SDriver *i2sp, uint32_t flags) { + + (void)i2sp; + + /* DMA errors handling.*/ +#if defined(STM32_I2S_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_I2S_DMA_ERROR_HOOK(i2sp); + } +#endif + + /* Callbacks handling, note it is portable code defined in the high + level driver.*/ + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _i2s_isr_full_code(i2sp); + } + else if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _i2s_isr_half_code(i2sp); + } +} +#endif + +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) || \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) || \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__) +/** + * @brief Shared end-of-tx service routine. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void i2s_lld_serve_tx_interrupt(I2SDriver *i2sp, uint32_t flags) { + + (void)i2sp; + + /* DMA errors handling.*/ +#if defined(STM32_I2S_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_I2S_DMA_ERROR_HOOK(i2sp); + } +#endif + + /* Callbacks handling, note it is portable code defined in the high + level driver.*/ + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _i2s_isr_full_code(i2sp); + } + else if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _i2s_isr_half_code(i2sp); + } +} +#endif + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2S driver initialization. + * + * @notapi + */ +void i2s_lld_init(void) { + +#if STM32_I2S_USE_SPI1 + i2sObjectInit(&I2SD1); + I2SD1.spi = SPI1; + I2SD1.cfg = STM32_I2S1_CFGR_CFG; + I2SD1.dmarx = NULL; + I2SD1.dmatx = NULL; +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) + I2SD1.rxdmamode = STM32_DMA_CR_CHSEL(I2S1_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD1.rxdmamode = 0; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) + I2SD1.txdmamode = STM32_DMA_CR_CHSEL(I2S1_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD1.txdmamode = 0; +#endif +#endif + +#if STM32_I2S_USE_SPI2 + i2sObjectInit(&I2SD2); + I2SD2.spi = SPI2; + I2SD2.cfg = STM32_I2S2_CFGR_CFG; + I2SD2.dmarx = NULL; + I2SD2.dmatx = NULL; +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) + I2SD2.rxdmamode = STM32_DMA_CR_CHSEL(I2S2_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD2.rxdmamode = 0; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) + I2SD2.txdmamode = STM32_DMA_CR_CHSEL(I2S2_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD2.txdmamode = 0; +#endif +#endif + +#if STM32_I2S_USE_SPI3 + i2sObjectInit(&I2SD3); + I2SD3.spi = SPI3; + I2SD3.cfg = STM32_I2S3_CFGR_CFG; + I2SD3.dmarx = NULL; + I2SD3.dmatx = NULL; +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) + I2SD3.rxdmamode = STM32_DMA_CR_CHSEL(I2S3_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD3.rxdmamode = 0; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) + I2SD3.txdmamode = STM32_DMA_CR_CHSEL(I2S3_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD3.txdmamode = 0; +#endif +#endif +} + +/** + * @brief Configures and activates the I2S peripheral. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @notapi + */ +void i2s_lld_start(I2SDriver *i2sp) { + + /* If in stopped state then enables the SPI and DMA clocks.*/ + if (i2sp->state == I2S_STOP) { + +#if STM32_I2S_USE_SPI1 + if (&I2SD1 == i2sp) { + + /* Enabling I2S unit clock.*/ + rccEnableSPI1(true); + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) + i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI1_RX_DMA_STREAM, + STM32_I2S_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_RXDMAEN; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) + i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI1_TX_DMA_STREAM, + STM32_I2S_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_TXDMAEN; +#endif + } +#endif + +#if STM32_I2S_USE_SPI2 + if (&I2SD2 == i2sp) { + + /* Enabling I2S unit clock.*/ + rccEnableSPI2(true); + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) + i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI2_RX_DMA_STREAM, + STM32_I2S_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_RXDMAEN; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) + i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI2_TX_DMA_STREAM, + STM32_I2S_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_TXDMAEN; +#endif + } +#endif + +#if STM32_I2S_USE_SPI3 + if (&I2SD3 == i2sp) { + + /* Enabling I2S unit clock.*/ + rccEnableSPI3(true); + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) + i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI3_RX_DMA_STREAM, + STM32_I2S_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_RXDMAEN; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) + i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI3_TX_DMA_STREAM, + STM32_I2S_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_TXDMAEN; +#endif + } +#endif + } + + /* I2S (re)configuration.*/ + i2sp->spi->I2SPR = i2sp->config->i2spr; + i2sp->spi->I2SCFGR = i2sp->config->i2scfgr | i2sp->cfg | SPI_I2SCFGR_I2SMOD; +} + +/** + * @brief Deactivates the I2S peripheral. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @notapi + */ +void i2s_lld_stop(I2SDriver *i2sp) { + + /* If in ready state then disables the SPI clock.*/ + if (i2sp->state == I2S_READY) { + + /* SPI disable.*/ + i2sp->spi->CR2 = 0; + if (NULL != i2sp->dmarx) { + dmaStreamFreeI(i2sp->dmarx); + i2sp->dmarx = NULL; + } + if (NULL != i2sp->dmatx) { + dmaStreamFreeI(i2sp->dmatx); + i2sp->dmatx = NULL; + } + +#if STM32_I2S_USE_SPI1 + if (&I2SD1 == i2sp) + rccDisableSPI1(); +#endif + +#if STM32_I2S_USE_SPI2 + if (&I2SD2 == i2sp) + rccDisableSPI2(); +#endif + +#if STM32_I2S_USE_SPI3 + if (&I2SD3 == i2sp) + rccDisableSPI3(); +#endif + } +} + +/** + * @brief Starts a I2S data exchange. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @notapi + */ +void i2s_lld_start_exchange(I2SDriver *i2sp) { + size_t size = i2sp->config->size; + + /* In 32 bit modes the DMA has to perform double operations because fetches + are always performed using 16 bit accesses. + DATLEN CHLEN SIZE + 00 (16) 0 (16) 16 + 00 (16) 1 (32) 16 + 01 (24) X 32 + 10 (32) X 32 + 11 (NA) X NA + */ + if ((i2sp->config->i2scfgr & SPI_I2SCFGR_DATLEN) != 0) + size *= 2; + + /* RX DMA setup.*/ + if (NULL != i2sp->dmarx) { + dmaStreamSetMode(i2sp->dmarx, i2sp->rxdmamode); + dmaStreamSetPeripheral(i2sp->dmarx, &i2sp->spi->DR); + dmaStreamSetMemory0(i2sp->dmarx, i2sp->config->rx_buffer); + dmaStreamSetTransactionSize(i2sp->dmarx, size); + dmaStreamEnable(i2sp->dmarx); + } + + /* TX DMA setup.*/ + if (NULL != i2sp->dmatx) { + dmaStreamSetMode(i2sp->dmatx, i2sp->txdmamode); + dmaStreamSetPeripheral(i2sp->dmatx, &i2sp->spi->DR); + dmaStreamSetMemory0(i2sp->dmatx, i2sp->config->tx_buffer); + dmaStreamSetTransactionSize(i2sp->dmatx, size); + dmaStreamEnable(i2sp->dmatx); + } + + /* Starting transfer.*/ + i2sp->spi->I2SCFGR |= SPI_I2SCFGR_I2SE; +} + +/** + * @brief Stops the ongoing data exchange. + * @details The ongoing data exchange, if any, is stopped, if the driver + * was not active the function does nothing. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @notapi + */ +void i2s_lld_stop_exchange(I2SDriver *i2sp) { + + /* Stop TX DMA, if enabled.*/ + if (NULL != i2sp->dmatx) { + dmaStreamDisable(i2sp->dmatx); + + /* From the RM: To switch off the I2S, by clearing I2SE, it is mandatory + to wait for TXE = 1 and BSY = 0.*/ + while ((i2sp->spi->SR & (SPI_SR_TXE | SPI_SR_BSY)) != SPI_SR_TXE) + ; + + /* Stop SPI/I2S peripheral.*/ + i2sp->spi->I2SCFGR &= ~SPI_I2SCFGR_I2SE; + } + + /* Stop RX DMA, if enabled then draining the RX DR.*/ + if (NULL != i2sp->dmarx) { + dmaStreamDisable(i2sp->dmarx); + + /* Waiting for some data to be present in RX DR.*/ + while ((i2sp->spi->SR & SPI_SR_RXNE) != SPI_SR_RXNE) + ; + + /* Stop SPI/I2S peripheral.*/ + i2sp->spi->I2SCFGR &= ~SPI_I2SCFGR_I2SE; + + /* Purging data in DR.*/ + while ((i2sp->spi->SR & SPI_SR_RXNE) != 0) + (void) i2sp->spi->DR; + } +} + +#endif /* HAL_USE_I2S */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.h new file mode 100644 index 0000000..37b3f2a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.h @@ -0,0 +1,371 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv1/hal_i2s_lld.h + * @brief STM32 I2S subsystem low level driver header. + * + * @addtogroup I2S + * @{ + */ + +#ifndef HAL_I2S_LLD_H +#define HAL_I2S_LLD_H + +#if HAL_USE_I2S || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Static I2S modes + * @{ + */ +#define STM32_I2S_MODE_SLAVE 0 +#define STM32_I2S_MODE_MASTER 1 +#define STM32_I2S_MODE_RX 2 +#define STM32_I2S_MODE_TX 4 +#define STM32_I2S_MODE_RXTX (STM32_I2S_MODE_RX | \ + STM32_I2S_MODE_TX) +/** @} */ + +/** + * @name Mode checks + * @{ + */ +#define STM32_I2S_IS_MASTER(mode) ((mode) & STM32_I2S_MODE_MASTER) +#define STM32_I2S_RX_ENABLED(mode) ((mode) & STM32_I2S_MODE_RX) +#define STM32_I2S_TX_ENABLED(mode) ((mode) & STM32_I2S_MODE_TX) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief I2S1 driver enable switch. + * @details If set to @p TRUE the support for I2S1 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_I2S_USE_SPI1) || defined(__DOXYGEN__) +#define STM32_I2S_USE_SPI1 FALSE +#endif + +/** + * @brief I2S2 driver enable switch. + * @details If set to @p TRUE the support for I2S2 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_I2S_USE_SPI2) || defined(__DOXYGEN__) +#define STM32_I2S_USE_SPI2 FALSE +#endif + +/** + * @brief I2S3 driver enable switch. + * @details If set to @p TRUE the support for I2S3 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_I2S_USE_SPI3) || defined(__DOXYGEN__) +#define STM32_I2S_USE_SPI3 FALSE +#endif + +/** + * @brief I2S1 mode. + */ +#if !defined(STM32_I2S_SPI1_MODE) || defined(__DOXYGEN__) +#define STM32_I2S_SPI1_MODE (STM32_I2S_MODE_MASTER | \ + STM32_I2S_MODE_RX) +#endif + +/** + * @brief I2S2 mode. + */ +#if !defined(STM32_I2S_SPI2_MODE) || defined(__DOXYGEN__) +#define STM32_I2S_SPI2_MODE (STM32_I2S_MODE_MASTER | \ + STM32_I2S_MODE_RX) +#endif + +/** + * @brief I2S3 mode. + */ +#if !defined(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__) +#define STM32_I2S_SPI3_MODE (STM32_I2S_MODE_MASTER | \ + STM32_I2S_MODE_RX) +#endif + +/** + * @brief I2S1 interrupt priority level setting. + */ +#if !defined(STM32_I2S_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI1_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2S2 interrupt priority level setting. + */ +#if !defined(STM32_I2S_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI2_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2S3 interrupt priority level setting. + */ +#if !defined(STM32_I2S_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI3_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2S1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_I2S_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI1_DMA_PRIORITY 1 +#endif + +/** + * @brief I2S2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_I2S_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI2_DMA_PRIORITY 1 +#endif + +/** + * @brief I2S3 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_I2S_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI3_DMA_PRIORITY 1 +#endif + +/** + * @brief I2S DMA error hook. + */ +#if !defined(STM32_I2S_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_I2S_USE_SPI1 && !STM32_SPI1_SUPPORTS_I2S +#error "SPI1 does not support I2S mode" +#endif + +#if STM32_I2S_USE_SPI2 && !STM32_SPI2_SUPPORTS_I2S +#error "SPI2 does not support I2S mode" +#endif + +#if STM32_I2S_USE_SPI3 && !STM32_SPI3_SUPPORTS_I2S +#error "SPI3 does not support I2S mode" +#endif + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) && \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) +#error "I2S1 RX and TX mode not supported in this driver implementation" +#endif + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) && \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) +#error "I2S2 RX and TX mode not supported in this driver implementation" +#endif + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) && \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) +#error "I2S3 RX and TX mode not supported in this driver implementation" +#endif + +#if STM32_I2S_USE_SPI1 && !STM32_HAS_SPI1 +#error "SPI1 not present in the selected device" +#endif + +#if STM32_I2S_USE_SPI2 && !STM32_HAS_SPI2 +#error "SPI2 not present in the selected device" +#endif + +#if STM32_I2S_USE_SPI3 && !STM32_HAS_SPI3 +#error "SPI3 not present in the selected device" +#endif + +#if !STM32_I2S_USE_SPI1 && !STM32_I2S_USE_SPI2 && !STM32_I2S_USE_SPI3 +#error "I2S driver activated but no SPI peripheral assigned" +#endif + +#if STM32_I2S_USE_SPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI1" +#endif + +#if STM32_I2S_USE_SPI2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI2" +#endif + +#if STM32_I2S_USE_SPI3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI3" +#endif + +#if STM32_I2S_USE_SPI1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI1" +#endif + +#if STM32_I2S_USE_SPI2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI2" +#endif + +#if STM32_I2S_USE_SPI3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI3" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_I2S_USE_SPI1 && (!defined(STM32_I2S_SPI1_RX_DMA_STREAM) || \ + !defined(STM32_I2S_SPI1_TX_DMA_STREAM)) +#error "SPI1 DMA streams not defined" +#endif + +#if STM32_I2S_USE_SPI2 && (!defined(STM32_I2S_SPI2_RX_DMA_STREAM) || \ + !defined(STM32_I2S_SPI2_TX_DMA_STREAM)) +#error "SPI2 DMA streams not defined" +#endif + +#if STM32_I2S_USE_SPI3 && (!defined(STM32_I2S_SPI3_RX_DMA_STREAM) || \ + !defined(STM32_I2S_SPI3_TX_DMA_STREAM)) +#error "SPI3 DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_I2S_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 RX" +#endif + +#if STM32_I2S_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 TX" +#endif + +#if STM32_I2S_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 RX" +#endif + +#if STM32_I2S_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 TX" +#endif + +#if STM32_I2S_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 RX" +#endif + +#if STM32_I2S_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 TX" +#endif +#endif /* STM32_ADVANCED_DMA */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the I2S driver structure. + */ +#define i2s_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /* Calculated part of the I2SCFGR register.*/ \ + uint16_t cfg; \ + /* Receive DMA stream or @p NULL.*/ \ + const stm32_dma_stream_t *dmarx; \ + /* Transmit DMA stream or @p NULL.*/ \ + const stm32_dma_stream_t *dmatx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode + +/** + * @brief Low level fields of the I2S configuration structure. + */ +#define i2s_lld_config_fields \ + /* Configuration of the I2SCFGR register. \ + NOTE: See the STM32 reference manual, this register is used for \ + the I2S configuration, the following bits must not be \ + specified because handled directly by the driver: \ + - I2SMOD \ + - I2SE \ + - I2SCFG \ + */ \ + int16_t i2scfgr; \ + /* Configuration of the I2SPR register. \ + NOTE: See the STM32 reference manual, this register is used for \ + the I2S clock setup.*/ \ + int16_t i2spr + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_I2S_USE_SPI1 && !defined(__DOXYGEN__) +extern I2SDriver I2SD1; +#endif + +#if STM32_I2S_USE_SPI2 && !defined(__DOXYGEN__) +extern I2SDriver I2SD2; +#endif + +#if STM32_I2S_USE_SPI3 && !defined(__DOXYGEN__) +extern I2SDriver I2SD3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void i2s_lld_init(void); + void i2s_lld_start(I2SDriver *i2sp); + void i2s_lld_stop(I2SDriver *i2sp); + void i2s_lld_start_exchange(I2SDriver *i2sp); + void i2s_lld_stop_exchange(I2SDriver *i2sp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_I2S */ + +#endif /* HAL_I2S_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c new file mode 100644 index 0000000..459e6b9 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c @@ -0,0 +1,679 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv1/hal_spi_lld.c + * @brief STM32 SPI subsystem low level driver source. + * + * @addtogroup SPI + * @{ + */ + +#include "hal.h" + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define SPI1_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_RX_DMA_STREAM, \ + STM32_SPI1_RX_DMA_CHN) + +#define SPI1_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_TX_DMA_STREAM, \ + STM32_SPI1_TX_DMA_CHN) + +#define SPI2_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_RX_DMA_STREAM, \ + STM32_SPI2_RX_DMA_CHN) + +#define SPI2_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_TX_DMA_STREAM, \ + STM32_SPI2_TX_DMA_CHN) + +#define SPI3_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_RX_DMA_STREAM, \ + STM32_SPI3_RX_DMA_CHN) + +#define SPI3_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_TX_DMA_STREAM, \ + STM32_SPI3_TX_DMA_CHN) + +#define SPI4_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_RX_DMA_STREAM, \ + STM32_SPI4_RX_DMA_CHN) + +#define SPI4_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_TX_DMA_STREAM, \ + STM32_SPI4_TX_DMA_CHN) + +#define SPI5_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_RX_DMA_STREAM, \ + STM32_SPI5_RX_DMA_CHN) + +#define SPI5_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_TX_DMA_STREAM, \ + STM32_SPI5_TX_DMA_CHN) + +#define SPI6_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_RX_DMA_STREAM, \ + STM32_SPI6_RX_DMA_CHN) + +#define SPI6_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_TX_DMA_STREAM, \ + STM32_SPI6_TX_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief SPI1 driver identifier.*/ +#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__) +SPIDriver SPID1; +#endif + +/** @brief SPI2 driver identifier.*/ +#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__) +SPIDriver SPID2; +#endif + +/** @brief SPI3 driver identifier.*/ +#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__) +SPIDriver SPID3; +#endif + +/** @brief SPI4 driver identifier.*/ +#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__) +SPIDriver SPID4; +#endif + +/** @brief SPI5 driver identifier.*/ +#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__) +SPIDriver SPID5; +#endif + +/** @brief SPI6 driver identifier.*/ +#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__) +SPIDriver SPID6; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const uint16_t dummytx = 0xFFFFU; +static uint16_t dummyrx; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Shared end-of-rx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_SPI_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_SPI_DMA_ERROR_HOOK(spip); + } +#else + (void)flags; +#endif + + if (spip->config->circular) { + if ((flags & STM32_DMA_ISR_HTIF) != 0U) { + /* Half buffer interrupt.*/ + _spi_isr_half_code(spip); + } + if ((flags & STM32_DMA_ISR_TCIF) != 0U) { + /* End buffer interrupt.*/ + _spi_isr_full_code(spip); + } + } + else { + /* Stopping DMAs.*/ + dmaStreamDisable(spip->dmatx); + dmaStreamDisable(spip->dmarx); + + /* Portable SPI ISR code defined in the high level driver, note, it is + a macro.*/ + _spi_isr_code(spip); + } +} + +/** + * @brief Shared end-of-tx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_SPI_DMA_ERROR_HOOK) + (void)spip; + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_SPI_DMA_ERROR_HOOK(spip); + } +#else + (void)spip; + (void)flags; +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SPI driver initialization. + * + * @notapi + */ +void spi_lld_init(void) { + +#if STM32_SPI_USE_SPI1 + spiObjectInit(&SPID1); + SPID1.spi = SPI1; + SPID1.dmarx = NULL; + SPID1.dmatx = NULL; + SPID1.rxdmamode = STM32_DMA_CR_CHSEL(SPI1_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID1.txdmamode = STM32_DMA_CR_CHSEL(SPI1_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI2 + spiObjectInit(&SPID2); + SPID2.spi = SPI2; + SPID2.dmarx = NULL; + SPID2.dmatx = NULL; + SPID2.rxdmamode = STM32_DMA_CR_CHSEL(SPI2_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID2.txdmamode = STM32_DMA_CR_CHSEL(SPI2_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI3 + spiObjectInit(&SPID3); + SPID3.spi = SPI3; + SPID3.dmarx = NULL; + SPID3.dmatx = NULL; + SPID3.rxdmamode = STM32_DMA_CR_CHSEL(SPI3_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID3.txdmamode = STM32_DMA_CR_CHSEL(SPI3_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI4 + spiObjectInit(&SPID4); + SPID4.spi = SPI4; + SPID4.dmarx = NULL; + SPID4.dmatx = NULL; + SPID4.rxdmamode = STM32_DMA_CR_CHSEL(SPI4_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID4.txdmamode = STM32_DMA_CR_CHSEL(SPI4_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI5 + spiObjectInit(&SPID5); + SPID5.spi = SPI5; + SPID5.dmarx = NULL; + SPID5.dmatx = NULL; + SPID5.rxdmamode = STM32_DMA_CR_CHSEL(SPI5_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID5.txdmamode = STM32_DMA_CR_CHSEL(SPI5_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI6 + spiObjectInit(&SPID6); + SPID6.spi = SPI6; + SPID6.dmarx = NULL; + SPID6.dmatx = NULL; + SPID6.rxdmamode = STM32_DMA_CR_CHSEL(SPI6_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID6.txdmamode = STM32_DMA_CR_CHSEL(SPI6_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif +} + +/** + * @brief Configures and activates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_start(SPIDriver *spip) { + + /* If in stopped state then enables the SPI and DMA clocks.*/ + if (spip->state == SPI_STOP) { +#if STM32_SPI_USE_SPI1 + if (&SPID1 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI1_RX_DMA_STREAM, + STM32_SPI_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI1_TX_DMA_STREAM, + STM32_SPI_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI1(true); + } +#endif +#if STM32_SPI_USE_SPI2 + if (&SPID2 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI2_RX_DMA_STREAM, + STM32_SPI_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI2_TX_DMA_STREAM, + STM32_SPI_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI2(true); + } +#endif +#if STM32_SPI_USE_SPI3 + if (&SPID3 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI3_RX_DMA_STREAM, + STM32_SPI_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI3_TX_DMA_STREAM, + STM32_SPI_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI3(true); + } +#endif +#if STM32_SPI_USE_SPI4 + if (&SPID4 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI4_RX_DMA_STREAM, + STM32_SPI_SPI4_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI4_TX_DMA_STREAM, + STM32_SPI_SPI4_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI4(true); + } +#endif +#if STM32_SPI_USE_SPI5 + if (&SPID5 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI5_RX_DMA_STREAM, + STM32_SPI_SPI5_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI5_TX_DMA_STREAM, + STM32_SPI_SPI5_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI5(true); + } +#endif +#if STM32_SPI_USE_SPI6 + if (&SPID6 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI6_RX_DMA_STREAM, + STM32_SPI_SPI6_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI6_TX_DMA_STREAM, + STM32_SPI_SPI6_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI6(true); + } +#endif + + /* DMA setup.*/ + dmaStreamSetPeripheral(spip->dmarx, &spip->spi->DR); + dmaStreamSetPeripheral(spip->dmatx, &spip->spi->DR); + } + + /* Configuration-specific DMA setup.*/ + if ((spip->config->cr1 & SPI_CR1_DFF) == 0) { + /* Frame width is 8 bits or smaller.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + } + else { + /* Frame width is larger than 8 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + } + + if (spip->config->circular) { + spip->rxdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + spip->txdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + } + else { + spip->rxdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + spip->txdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + } + + /* SPI setup and enable.*/ + spip->spi->CR1 &= ~SPI_CR1_SPE; + spip->spi->CR1 = spip->config->cr1 | SPI_CR1_MSTR | SPI_CR1_SSM | + SPI_CR1_SSI; + spip->spi->CR2 = spip->config->cr2 | SPI_CR2_SSOE | SPI_CR2_RXDMAEN | + SPI_CR2_TXDMAEN; + spip->spi->CR1 |= SPI_CR1_SPE; +} + +/** + * @brief Deactivates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_stop(SPIDriver *spip) { + + /* If in ready state then disables the SPI clock.*/ + if (spip->state == SPI_READY) { + + /* SPI disable.*/ + spip->spi->CR1 &= ~SPI_CR1_SPE; + spip->spi->CR1 = 0; + spip->spi->CR2 = 0; + dmaStreamFreeI(spip->dmarx); + dmaStreamFreeI(spip->dmatx); + spip->dmarx = NULL; + spip->dmatx = NULL; + +#if STM32_SPI_USE_SPI1 + if (&SPID1 == spip) + rccDisableSPI1(); +#endif +#if STM32_SPI_USE_SPI2 + if (&SPID2 == spip) + rccDisableSPI2(); +#endif +#if STM32_SPI_USE_SPI3 + if (&SPID3 == spip) + rccDisableSPI3(); +#endif +#if STM32_SPI_USE_SPI4 + if (&SPID4 == spip) + rccDisableSPI4(); +#endif +#if STM32_SPI_USE_SPI5 + if (&SPID5 == spip) + rccDisableSPI5(); +#endif +#if STM32_SPI_USE_SPI6 + if (&SPID6 == spip) + rccDisableSPI6(); +#endif + } +} + +#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__) +/** + * @brief Asserts the slave select signal and prepares for transfers. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_select(SPIDriver *spip) { + + /* No implementation on STM32.*/ +} + +/** + * @brief Deasserts the slave select signal. + * @details The previously selected peripheral is unselected. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_unselect(SPIDriver *spip) { + + /* No implementation on STM32.*/ +} +#endif + +/** + * @brief Ignores data on the SPI bus. + * @details This asynchronous function starts the transmission of a series of + * idle words on the SPI bus and ignores the received data. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be ignored + * + * @notapi + */ +void spi_lld_ignore(SPIDriver *spip, size_t n) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + dmaStreamSetMemory0(spip->dmarx, &dummyrx); + dmaStreamSetTransactionSize(spip->dmarx, n); + dmaStreamSetMode(spip->dmarx, spip->rxdmamode); + + dmaStreamSetMemory0(spip->dmatx, &dummytx); + dmaStreamSetTransactionSize(spip->dmatx, n); + dmaStreamSetMode(spip->dmatx, spip->txdmamode); + + dmaStreamEnable(spip->dmarx); + dmaStreamEnable(spip->dmatx); +} + +/** + * @brief Exchanges data on the SPI bus. + * @details This asynchronous function starts a simultaneous transmit/receive + * operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * @param[in] txbuf the pointer to the transmit buffer + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + dmaStreamSetMemory0(spip->dmarx, rxbuf); + dmaStreamSetTransactionSize(spip->dmarx, n); + dmaStreamSetMode(spip->dmarx, spip->rxdmamode| STM32_DMA_CR_MINC); + + dmaStreamSetMemory0(spip->dmatx, txbuf); + dmaStreamSetTransactionSize(spip->dmatx, n); + dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC); + + dmaStreamEnable(spip->dmarx); + dmaStreamEnable(spip->dmatx); +} + +/** + * @brief Sends data over the SPI bus. + * @details This asynchronous function starts a transmit operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + dmaStreamSetMemory0(spip->dmarx, &dummyrx); + dmaStreamSetTransactionSize(spip->dmarx, n); + dmaStreamSetMode(spip->dmarx, spip->rxdmamode); + + dmaStreamSetMemory0(spip->dmatx, txbuf); + dmaStreamSetTransactionSize(spip->dmatx, n); + dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC); + + dmaStreamEnable(spip->dmarx); + dmaStreamEnable(spip->dmatx); +} + +/** + * @brief Receives data from the SPI bus. + * @details This asynchronous function starts a receive operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to receive + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + dmaStreamSetMemory0(spip->dmarx, rxbuf); + dmaStreamSetTransactionSize(spip->dmarx, n); + dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_MINC); + + dmaStreamSetMemory0(spip->dmatx, &dummytx); + dmaStreamSetTransactionSize(spip->dmatx, n); + dmaStreamSetMode(spip->dmatx, spip->txdmamode); + + dmaStreamEnable(spip->dmarx); + dmaStreamEnable(spip->dmatx); +} + +#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__) +/** + * @brief Aborts the ongoing SPI operation, if any. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_abort(SPIDriver *spip) { + + /* Stopping DMAs.*/ + dmaStreamDisable(spip->dmatx); + dmaStreamDisable(spip->dmarx); +} +#endif /* SPI_SUPPORTS_CIRCULAR == TRUE */ + +/** + * @brief Exchanges one frame using a polled wait. + * @details This synchronous function exchanges one frame using a polled + * synchronization method. This function is useful when exchanging + * small amount of data on high speed channels, usually in this + * situation is much more efficient just wait for completion using + * polling than suspending the thread waiting for an interrupt. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] frame the data frame to send over the SPI bus + * @return The received data frame from the SPI bus. + */ +uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) { + + spip->spi->DR = frame; + while ((spip->spi->SR & SPI_SR_RXNE) == 0) + ; + return spip->spi->DR; +} + +#endif /* HAL_USE_SPI */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.h new file mode 100644 index 0000000..09a6eec --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.h @@ -0,0 +1,495 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv1/hal_spi_lld.h + * @brief STM32 SPI subsystem low level driver header. + * + * @addtogroup SPI + * @{ + */ + +#ifndef HAL_SPI_LLD_H +#define HAL_SPI_LLD_H + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Circular mode support flag. + */ +#define SPI_SUPPORTS_CIRCULAR TRUE + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SPI1 driver enable switch. + * @details If set to @p TRUE the support for SPI1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI1) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI1 FALSE +#endif + +/** + * @brief SPI2 driver enable switch. + * @details If set to @p TRUE the support for SPI2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI2) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI2 FALSE +#endif + +/** + * @brief SPI3 driver enable switch. + * @details If set to @p TRUE the support for SPI3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI3) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI3 FALSE +#endif + +/** + * @brief SPI4 driver enable switch. + * @details If set to @p TRUE the support for SPI4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI4) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI4 FALSE +#endif + +/** + * @brief SPI5 driver enable switch. + * @details If set to @p TRUE the support for SPI5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI5) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI5 FALSE +#endif + +/** + * @brief SPI6 driver enable switch. + * @details If set to @p TRUE the support for SPI6 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI6) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI6 FALSE +#endif + +/** + * @brief SPI1 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI1_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI2 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI2_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI3 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI3_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI4 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI4_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI5 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI5_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI6 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI6_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI6_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI1 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI1_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI2 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI2_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI3 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI3_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI4 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI4_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI5 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI5_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI5_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI6 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI6_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI6_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI DMA error hook. + */ +#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 && !STM32_HAS_SPI1 +#error "SPI1 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI2 && !STM32_HAS_SPI2 +#error "SPI2 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI3 && !STM32_HAS_SPI3 +#error "SPI3 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI4 && !STM32_HAS_SPI4 +#error "SPI4 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI5 && !STM32_HAS_SPI5 +#error "SPI5 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI6 && !STM32_HAS_SPI6 +#error "SPI6 not present in the selected device" +#endif + +#if !STM32_SPI_USE_SPI1 && !STM32_SPI_USE_SPI2 && !STM32_SPI_USE_SPI3 && \ + !STM32_SPI_USE_SPI4 && !STM32_SPI_USE_SPI5 && !STM32_SPI_USE_SPI6 +#error "SPI driver activated but no SPI peripheral assigned" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI1" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI2" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI3" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI4" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI5" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI6_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI6" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI1" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI2" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI3" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI4" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI5_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI5" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI6_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI6" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_SPI_USE_SPI1 && (!defined(STM32_SPI_SPI1_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI1_TX_DMA_STREAM)) +#error "SPI1 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI2 && (!defined(STM32_SPI_SPI2_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI2_TX_DMA_STREAM)) +#error "SPI2 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI3 && (!defined(STM32_SPI_SPI3_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI3_TX_DMA_STREAM)) +#error "SPI3 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI4 && (!defined(STM32_SPI_SPI4_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI4_TX_DMA_STREAM)) +#error "SPI4 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI5 && (!defined(STM32_SPI_SPI5_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI5_TX_DMA_STREAM)) +#error "SPI5 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI6 && (!defined(STM32_SPI_SPI6_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI6_TX_DMA_STREAM)) +#error "SPI6 DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 RX" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 TX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 RX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 TX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 RX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 TX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_RX_DMA_STREAM, STM32_SPI4_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI4 RX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_TX_DMA_STREAM, STM32_SPI4_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI4 TX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_RX_DMA_STREAM, STM32_SPI5_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI5 RX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_TX_DMA_STREAM, STM32_SPI5_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI5 TX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_RX_DMA_STREAM, STM32_SPI6_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI6 RX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_TX_DMA_STREAM, STM32_SPI6_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI6 TX" +#endif +#endif /* STM32_ADVANCED_DMA */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +#if SPI_SELECT_MODE == SPI_SELECT_MODE_LLD +#error "SPI_SELECT_MODE_LLD not supported by this driver" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the SPI driver structure. + */ +#define spi_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /* Receive DMA stream.*/ \ + const stm32_dma_stream_t *dmarx; \ + /* Transmit DMA stream.*/ \ + const stm32_dma_stream_t *dmatx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode + +/** + * @brief Low level fields of the SPI configuration structure. + */ +#define spi_lld_config_fields \ + /* SPI CR1 register initialization data.*/ \ + uint16_t cr1; \ + /* SPI CR2 register initialization data.*/ \ + uint16_t cr2 + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 && !defined(__DOXYGEN__) +extern SPIDriver SPID1; +#endif + +#if STM32_SPI_USE_SPI2 && !defined(__DOXYGEN__) +extern SPIDriver SPID2; +#endif + +#if STM32_SPI_USE_SPI3 && !defined(__DOXYGEN__) +extern SPIDriver SPID3; +#endif + +#if STM32_SPI_USE_SPI4 && !defined(__DOXYGEN__) +extern SPIDriver SPID4; +#endif + +#if STM32_SPI_USE_SPI5 && !defined(__DOXYGEN__) +extern SPIDriver SPID5; +#endif + +#if STM32_SPI_USE_SPI6 && !defined(__DOXYGEN__) +extern SPIDriver SPID6; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void spi_lld_init(void); + void spi_lld_start(SPIDriver *spip); + void spi_lld_stop(SPIDriver *spip); +#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__) + void spi_lld_select(SPIDriver *spip); + void spi_lld_unselect(SPIDriver *spip); +#endif + void spi_lld_ignore(SPIDriver *spip, size_t n); + void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf); + void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf); + void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf); +#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__) + void spi_lld_abort(SPIDriver *spip); +#endif + uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SPI */ + +#endif /* HAL_SPI_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/driver.mk new file mode 100644 index 0000000..2e1bae4 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/driver.mk @@ -0,0 +1,13 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_I2S TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c +endif +ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c new file mode 100644 index 0000000..aa437da --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c @@ -0,0 +1,572 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv2/hal_i2s_lld.c + * @brief STM32 I2S subsystem low level driver source. + * + * @addtogroup I2S + * @{ + */ + +#include "hal.h" + +#if HAL_USE_I2S || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define I2S1_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI1_RX_DMA_STREAM, \ + STM32_SPI1_RX_DMA_CHN) + +#define I2S1_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI1_TX_DMA_STREAM, \ + STM32_SPI1_TX_DMA_CHN) + +#define I2S2_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI2_RX_DMA_STREAM, \ + STM32_SPI2_RX_DMA_CHN) + +#define I2S2_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI2_TX_DMA_STREAM, \ + STM32_SPI2_TX_DMA_CHN) + +#define I2S3_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI3_RX_DMA_STREAM, \ + STM32_SPI3_RX_DMA_CHN) + +#define I2S3_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_I2S_SPI3_TX_DMA_STREAM, \ + STM32_SPI3_TX_DMA_CHN) + +/* + * Static I2S settings for I2S1. + */ +#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) +#define STM32_I2S1_CFGR_CFG 0 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) +#define STM32_I2S1_CFGR_CFG SPI_I2SCFGR_I2SCFG_0 +#endif +#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) */ +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) +#define STM32_I2S1_CFGR_CFG SPI_I2SCFGR_I2SCFG_1 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) +#define STM32_I2S1_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \ + SPI_I2SCFGR_I2SCFG_0) +#endif +#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) */ + +/* + * Static I2S settings for I2S2. + */ +#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) +#define STM32_I2S2_CFGR_CFG 0 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) +#define STM32_I2S2_CFGR_CFG SPI_I2SCFGR_I2SCFG_0 +#endif +#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) */ +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) +#define STM32_I2S2_CFGR_CFG SPI_I2SCFGR_I2SCFG_1 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) +#define STM32_I2S2_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \ + SPI_I2SCFGR_I2SCFG_0) +#endif +#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) */ + +/* + * Static I2S settings for I2S3. + */ +#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) +#define STM32_I2S3_CFGR_CFG 0 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) +#define STM32_I2S3_CFGR_CFG SPI_I2SCFGR_I2SCFG_0 +#endif +#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) */ +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) +#define STM32_I2S3_CFGR_CFG SPI_I2SCFGR_I2SCFG_1 +#endif +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) +#define STM32_I2S3_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \ + SPI_I2SCFGR_I2SCFG_0) +#endif +#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief I2S1 driver identifier.*/ +#if STM32_I2S_USE_SPI1 || defined(__DOXYGEN__) +I2SDriver I2SD1; +#endif + +/** @brief I2S2 driver identifier.*/ +#if STM32_I2S_USE_SPI2 || defined(__DOXYGEN__) +I2SDriver I2SD2; +#endif + +/** @brief I2S3 driver identifier.*/ +#if STM32_I2S_USE_SPI3 || defined(__DOXYGEN__) +I2SDriver I2SD3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) || \ + STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) || \ + STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__) +/** + * @brief Shared end-of-rx service routine. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void i2s_lld_serve_rx_interrupt(I2SDriver *i2sp, uint32_t flags) { + + (void)i2sp; + + /* DMA errors handling.*/ +#if defined(STM32_I2S_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_I2S_DMA_ERROR_HOOK(i2sp); + } +#endif + + /* Callbacks handling, note it is portable code defined in the high + level driver.*/ + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _i2s_isr_full_code(i2sp); + } + else if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _i2s_isr_half_code(i2sp); + } +} +#endif + +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) || \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) || \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__) +/** + * @brief Shared end-of-tx service routine. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void i2s_lld_serve_tx_interrupt(I2SDriver *i2sp, uint32_t flags) { + + (void)i2sp; + + /* DMA errors handling.*/ +#if defined(STM32_I2S_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_I2S_DMA_ERROR_HOOK(i2sp); + } +#endif + + /* Callbacks handling, note it is portable code defined in the high + level driver.*/ + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _i2s_isr_full_code(i2sp); + } + else if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _i2s_isr_half_code(i2sp); + } +} +#endif + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2S driver initialization. + * + * @notapi + */ +void i2s_lld_init(void) { + +#if STM32_I2S_USE_SPI1 + i2sObjectInit(&I2SD1); + I2SD1.spi = SPI1; + I2SD1.cfg = STM32_I2S1_CFGR_CFG; + I2SD1.dmarx = NULL; + I2SD1.dmatx = NULL; +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) + I2SD1.rxdmamode = STM32_DMA_CR_CHSEL(I2S1_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD1.rxdmamode = 0; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) + I2SD1.txdmamode = STM32_DMA_CR_CHSEL(I2S1_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD1.txdmamode = 0; +#endif +#endif + +#if STM32_I2S_USE_SPI2 + i2sObjectInit(&I2SD2); + I2SD2.spi = SPI2; + I2SD2.cfg = STM32_I2S2_CFGR_CFG; + I2SD2.dmarx = NULL; + I2SD2.dmatx = NULL; +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) + I2SD2.rxdmamode = STM32_DMA_CR_CHSEL(I2S2_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD2.rxdmamode = 0; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) + I2SD2.txdmamode = STM32_DMA_CR_CHSEL(I2S2_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD2.txdmamode = 0; +#endif +#endif + +#if STM32_I2S_USE_SPI3 + i2sObjectInit(&I2SD3); + I2SD3.spi = SPI3; + I2SD3.cfg = STM32_I2S3_CFGR_CFG; + I2SD3.dmarx = NULL; + I2SD3.dmatx = NULL; +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) + I2SD3.rxdmamode = STM32_DMA_CR_CHSEL(I2S3_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD3.rxdmamode = 0; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) + I2SD3.txdmamode = STM32_DMA_CR_CHSEL(I2S3_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_I2S_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MSIZE_HWORD | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_HTIE | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#else + I2SD3.txdmamode = 0; +#endif +#endif +} + +/** + * @brief Configures and activates the I2S peripheral. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @notapi + */ +void i2s_lld_start(I2SDriver *i2sp) { + + /* If in stopped state then enables the SPI and DMA clocks.*/ + if (i2sp->state == I2S_STOP) { + +#if STM32_I2S_USE_SPI1 + if (&I2SD1 == i2sp) { + + /* Enabling I2S unit clock.*/ + rccEnableSPI1(true); + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) + i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI1_RX_DMA_STREAM, + STM32_I2S_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_RXDMAEN; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) + i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI1_TX_DMA_STREAM, + STM32_I2S_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_TXDMAEN; +#endif + } +#endif + +#if STM32_I2S_USE_SPI2 + if (&I2SD2 == i2sp) { + + /* Enabling I2S unit clock.*/ + rccEnableSPI2(true); + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) + i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI2_RX_DMA_STREAM, + STM32_I2S_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_RXDMAEN; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) + i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI2_TX_DMA_STREAM, + STM32_I2S_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_TXDMAEN; +#endif + } +#endif + +#if STM32_I2S_USE_SPI3 + if (&I2SD3 == i2sp) { + + /* Enabling I2S unit clock.*/ + rccEnableSPI3(true); + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) + i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI3_RX_DMA_STREAM, + STM32_I2S_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_RXDMAEN; +#endif +#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) + i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI3_TX_DMA_STREAM, + STM32_I2S_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt, + (void *)i2sp); + osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream"); + + /* CRs settings are done here because those never changes until + the driver is stopped.*/ + i2sp->spi->CR1 = 0; + i2sp->spi->CR2 = SPI_CR2_TXDMAEN; +#endif + } +#endif + } + + /* I2S (re)configuration.*/ + i2sp->spi->I2SPR = i2sp->config->i2spr; + i2sp->spi->I2SCFGR = i2sp->config->i2scfgr | i2sp->cfg | SPI_I2SCFGR_I2SMOD; +} + +/** + * @brief Deactivates the I2S peripheral. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @notapi + */ +void i2s_lld_stop(I2SDriver *i2sp) { + + /* If in ready state then disables the SPI clock.*/ + if (i2sp->state == I2S_READY) { + + /* SPI disable.*/ + i2sp->spi->CR2 = 0; + if (NULL != i2sp->dmarx) { + dmaStreamFreeI(i2sp->dmarx); + i2sp->dmarx = NULL; + } + if (NULL != i2sp->dmatx) { + dmaStreamFreeI(i2sp->dmatx); + i2sp->dmatx = NULL; + } + +#if STM32_I2S_USE_SPI1 + if (&I2SD1 == i2sp) + rccDisableSPI1(); +#endif + +#if STM32_I2S_USE_SPI2 + if (&I2SD2 == i2sp) + rccDisableSPI2(); +#endif + +#if STM32_I2S_USE_SPI3 + if (&I2SD3 == i2sp) + rccDisableSPI3(); +#endif + } +} + +/** + * @brief Starts a I2S data exchange. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @notapi + */ +void i2s_lld_start_exchange(I2SDriver *i2sp) { + size_t size = i2sp->config->size; + + /* In 32 bit modes the DMA has to perform double operations because fetches + are always performed using 16 bit accesses. + DATLEN CHLEN SIZE + 00 (16) 0 (16) 16 + 00 (16) 1 (32) 16 + 01 (24) X 32 + 10 (32) X 32 + 11 (NA) X NA + */ + if ((i2sp->config->i2scfgr & SPI_I2SCFGR_DATLEN) != 0) + size *= 2; + + /* RX DMA setup.*/ + if (NULL != i2sp->dmarx) { + dmaStreamSetMode(i2sp->dmarx, i2sp->rxdmamode); + dmaStreamSetPeripheral(i2sp->dmarx, &i2sp->spi->DR); + dmaStreamSetMemory0(i2sp->dmarx, i2sp->config->rx_buffer); + dmaStreamSetTransactionSize(i2sp->dmarx, size); + dmaStreamEnable(i2sp->dmarx); + } + + /* TX DMA setup.*/ + if (NULL != i2sp->dmatx) { + dmaStreamSetMode(i2sp->dmatx, i2sp->txdmamode); + dmaStreamSetPeripheral(i2sp->dmatx, &i2sp->spi->DR); + dmaStreamSetMemory0(i2sp->dmatx, i2sp->config->tx_buffer); + dmaStreamSetTransactionSize(i2sp->dmatx, size); + dmaStreamEnable(i2sp->dmatx); + } + + /* Starting transfer.*/ + i2sp->spi->I2SCFGR |= SPI_I2SCFGR_I2SE; +} + +/** + * @brief Stops the ongoing data exchange. + * @details The ongoing data exchange, if any, is stopped, if the driver + * was not active the function does nothing. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @notapi + */ +void i2s_lld_stop_exchange(I2SDriver *i2sp) { + + /* Stop TX DMA, if enabled.*/ + if (NULL != i2sp->dmatx) { + dmaStreamDisable(i2sp->dmatx); + + /* From the RM: To switch off the I2S, by clearing I2SE, it is mandatory + to wait for TXE = 1 and BSY = 0.*/ + while ((i2sp->spi->SR & (SPI_SR_TXE | SPI_SR_BSY)) != SPI_SR_TXE) + ; + } + + /* Stop SPI/I2S peripheral.*/ + i2sp->spi->I2SCFGR &= ~SPI_I2SCFGR_I2SE; + + /* Stop RX DMA, if enabled.*/ + if (NULL != i2sp->dmarx) + dmaStreamDisable(i2sp->dmarx); +} + +#endif /* HAL_USE_I2S */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.h new file mode 100644 index 0000000..acf92e1 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.h @@ -0,0 +1,371 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv2/hal_i2s_lld.h + * @brief STM32 I2S subsystem low level driver header. + * + * @addtogroup I2S + * @{ + */ + +#ifndef HAL_I2S_LLD_H +#define HAL_I2S_LLD_H + +#if HAL_USE_I2S || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Static I2S modes + * @{ + */ +#define STM32_I2S_MODE_SLAVE 0 +#define STM32_I2S_MODE_MASTER 1 +#define STM32_I2S_MODE_RX 2 +#define STM32_I2S_MODE_TX 4 +#define STM32_I2S_MODE_RXTX (STM32_I2S_MODE_RX | \ + STM32_I2S_MODE_TX) +/** @} */ + +/** + * @name Mode checks + * @{ + */ +#define STM32_I2S_IS_MASTER(mode) ((mode) & STM32_I2S_MODE_MASTER) +#define STM32_I2S_RX_ENABLED(mode) ((mode) & STM32_I2S_MODE_RX) +#define STM32_I2S_TX_ENABLED(mode) ((mode) & STM32_I2S_MODE_TX) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief I2S1 driver enable switch. + * @details If set to @p TRUE the support for I2S1 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_I2S_USE_SPI1) || defined(__DOXYGEN__) +#define STM32_I2S_USE_SPI1 FALSE +#endif + +/** + * @brief I2S2 driver enable switch. + * @details If set to @p TRUE the support for I2S2 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_I2S_USE_SPI2) || defined(__DOXYGEN__) +#define STM32_I2S_USE_SPI2 FALSE +#endif + +/** + * @brief I2S3 driver enable switch. + * @details If set to @p TRUE the support for I2S3 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_I2S_USE_SPI3) || defined(__DOXYGEN__) +#define STM32_I2S_USE_SPI3 FALSE +#endif + +/** + * @brief I2S1 mode. + */ +#if !defined(STM32_I2S_SPI1_MODE) || defined(__DOXYGEN__) +#define STM32_I2S_SPI1_MODE (STM32_I2S_MODE_MASTER | \ + STM32_I2S_MODE_RX) +#endif + +/** + * @brief I2S2 mode. + */ +#if !defined(STM32_I2S_SPI2_MODE) || defined(__DOXYGEN__) +#define STM32_I2S_SPI2_MODE (STM32_I2S_MODE_MASTER | \ + STM32_I2S_MODE_RX) +#endif + +/** + * @brief I2S3 mode. + */ +#if !defined(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__) +#define STM32_I2S_SPI3_MODE (STM32_I2S_MODE_MASTER | \ + STM32_I2S_MODE_RX) +#endif + +/** + * @brief I2S1 interrupt priority level setting. + */ +#if !defined(STM32_I2S_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI1_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2S2 interrupt priority level setting. + */ +#if !defined(STM32_I2S_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI2_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2S3 interrupt priority level setting. + */ +#if !defined(STM32_I2S_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI3_IRQ_PRIORITY 10 +#endif + +/** + * @brief I2S1 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_I2S_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI1_DMA_PRIORITY 1 +#endif + +/** + * @brief I2S2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_I2S_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI2_DMA_PRIORITY 1 +#endif + +/** + * @brief I2S3 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_I2S_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_I2S_SPI3_DMA_PRIORITY 1 +#endif + +/** + * @brief I2S DMA error hook. + */ +#if !defined(STM32_I2S_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_I2S_USE_SPI1 && !STM32_SPI1_SUPPORTS_I2S +#error "SPI1 does not support I2S mode" +#endif + +#if STM32_I2S_USE_SPI2 && !STM32_SPI2_SUPPORTS_I2S +#error "SPI2 does not support I2S mode" +#endif + +#if STM32_I2S_USE_SPI3 && !STM32_SPI3_SUPPORTS_I2S +#error "SPI3 does not support I2S mode" +#endif + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) && \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) +#error "I2S1 RX and TX mode not supported in this driver implementation" +#endif + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) && \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) +#error "I2S2 RX and TX mode not supported in this driver implementation" +#endif + +#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) && \ + STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) +#error "I2S3 RX and TX mode not supported in this driver implementation" +#endif + +#if STM32_I2S_USE_SPI1 && !STM32_HAS_SPI1 +#error "SPI1 not present in the selected device" +#endif + +#if STM32_I2S_USE_SPI2 && !STM32_HAS_SPI2 +#error "SPI2 not present in the selected device" +#endif + +#if STM32_I2S_USE_SPI3 && !STM32_HAS_SPI3 +#error "SPI3 not present in the selected device" +#endif + +#if !STM32_I2S_USE_SPI1 && !STM32_I2S_USE_SPI2 && !STM32_I2S_USE_SPI3 +#error "I2S driver activated but no SPI peripheral assigned" +#endif + +#if STM32_I2S_USE_SPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI1" +#endif + +#if STM32_I2S_USE_SPI2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI2" +#endif + +#if STM32_I2S_USE_SPI3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI3" +#endif + +#if STM32_I2S_USE_SPI1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI1" +#endif + +#if STM32_I2S_USE_SPI2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI2" +#endif + +#if STM32_I2S_USE_SPI3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI3" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_I2S_USE_SPI1 && (!defined(STM32_I2S_SPI1_RX_DMA_STREAM) || \ + !defined(STM32_I2S_SPI1_TX_DMA_STREAM)) +#error "SPI1 DMA streams not defined" +#endif + +#if STM32_I2S_USE_SPI2 && (!defined(STM32_I2S_SPI2_RX_DMA_STREAM) || \ + !defined(STM32_I2S_SPI2_TX_DMA_STREAM)) +#error "SPI2 DMA streams not defined" +#endif + +#if STM32_I2S_USE_SPI3 && (!defined(STM32_I2S_SPI3_RX_DMA_STREAM) || \ + !defined(STM32_I2S_SPI3_TX_DMA_STREAM)) +#error "SPI3 DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_I2S_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 RX" +#endif + +#if STM32_I2S_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 TX" +#endif + +#if STM32_I2S_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 RX" +#endif + +#if STM32_I2S_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 TX" +#endif + +#if STM32_I2S_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 RX" +#endif + +#if STM32_I2S_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 TX" +#endif +#endif /* STM32_ADVANCED_DMA */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the I2S driver structure. + */ +#define i2s_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /* Calculated part of the I2SCFGR register.*/ \ + uint16_t cfg; \ + /* Receive DMA stream or @p NULL.*/ \ + const stm32_dma_stream_t *dmarx; \ + /* Transmit DMA stream or @p NULL.*/ \ + const stm32_dma_stream_t *dmatx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode + +/** + * @brief Low level fields of the I2S configuration structure. + */ +#define i2s_lld_config_fields \ + /* Configuration of the I2SCFGR register. \ + NOTE: See the STM32 reference manual, this register is used for \ + the I2S configuration, the following bits must not be \ + specified because handled directly by the driver: \ + - I2SMOD \ + - I2SE \ + - I2SCFG \ + */ \ + int16_t i2scfgr; \ + /* Configuration of the I2SPR register. \ + NOTE: See the STM32 reference manual, this register is used for \ + the I2S clock setup.*/ \ + int16_t i2spr + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_I2S_USE_SPI1 && !defined(__DOXYGEN__) +extern I2SDriver I2SD1; +#endif + +#if STM32_I2S_USE_SPI2 && !defined(__DOXYGEN__) +extern I2SDriver I2SD2; +#endif + +#if STM32_I2S_USE_SPI3 && !defined(__DOXYGEN__) +extern I2SDriver I2SD3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void i2s_lld_init(void); + void i2s_lld_start(I2SDriver *i2sp); + void i2s_lld_stop(I2SDriver *i2sp); + void i2s_lld_start_exchange(I2SDriver *i2sp); + void i2s_lld_stop_exchange(I2SDriver *i2sp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_I2S */ + +#endif /* HAL_I2S_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c new file mode 100644 index 0000000..02bc9a0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c @@ -0,0 +1,720 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv2/hal_spi_lld.c + * @brief STM32 SPI subsystem low level driver source. + * + * @addtogroup SPI + * @{ + */ + +#include "hal.h" + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define SPI1_RX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_RX_DMA_STREAM, \ + STM32_SPI1_RX_DMA_CHN) + +#define SPI1_TX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_TX_DMA_STREAM, \ + STM32_SPI1_TX_DMA_CHN) + +#define SPI2_RX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_RX_DMA_STREAM, \ + STM32_SPI2_RX_DMA_CHN) + +#define SPI2_TX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_TX_DMA_STREAM, \ + STM32_SPI2_TX_DMA_CHN) + +#define SPI3_RX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_RX_DMA_STREAM, \ + STM32_SPI3_RX_DMA_CHN) + +#define SPI3_TX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_TX_DMA_STREAM, \ + STM32_SPI3_TX_DMA_CHN) + +#define SPI4_RX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_RX_DMA_STREAM, \ + STM32_SPI4_RX_DMA_CHN) + +#define SPI4_TX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_TX_DMA_STREAM, \ + STM32_SPI4_TX_DMA_CHN) + +#define SPI5_RX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_RX_DMA_STREAM, \ + STM32_SPI5_RX_DMA_CHN) + +#define SPI5_TX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_TX_DMA_STREAM, \ + STM32_SPI5_TX_DMA_CHN) + +#define SPI6_RX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_RX_DMA_STREAM, \ + STM32_SPI6_RX_DMA_CHN) + +#define SPI6_TX_DMA_STREAM \ + STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_TX_DMA_STREAM, \ + STM32_SPI6_TX_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief SPI1 driver identifier.*/ +#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__) +SPIDriver SPID1; +#endif + +/** @brief SPI2 driver identifier.*/ +#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__) +SPIDriver SPID2; +#endif + +/** @brief SPI3 driver identifier.*/ +#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__) +SPIDriver SPID3; +#endif + +/** @brief SPI4 driver identifier.*/ +#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__) +SPIDriver SPID4; +#endif + +/** @brief SPI5 driver identifier.*/ +#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__) +SPIDriver SPID5; +#endif + +/** @brief SPI6 driver identifier.*/ +#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__) +SPIDriver SPID6; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const uint16_t dummytx = 0xFFFFU; +static uint16_t dummyrx; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Shared end-of-rx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_SPI_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_SPI_DMA_ERROR_HOOK(spip); + } +#else + (void)flags; +#endif + + if (spip->config->circular) { + if ((flags & STM32_DMA_ISR_HTIF) != 0U) { + /* Half buffer interrupt.*/ + _spi_isr_half_code(spip); + } + if ((flags & STM32_DMA_ISR_TCIF) != 0U) { + /* End buffer interrupt.*/ + _spi_isr_full_code(spip); + } + } + else { + /* Stopping DMAs.*/ + dmaStreamDisable(spip->dmatx); + dmaStreamDisable(spip->dmarx); + + /* Portable SPI ISR code defined in the high level driver, note, it is + a macro.*/ + _spi_isr_code(spip); + } +} + +/** + * @brief Shared end-of-tx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_SPI_DMA_ERROR_HOOK) + (void)spip; + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_SPI_DMA_ERROR_HOOK(spip); + } +#else + (void)spip; + (void)flags; +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SPI driver initialization. + * + * @notapi + */ +void spi_lld_init(void) { + +#if STM32_SPI_USE_SPI1 + spiObjectInit(&SPID1); + SPID1.spi = SPI1; + SPID1.dmarx = NULL; + SPID1.dmatx = NULL; + SPID1.rxdmamode = STM32_DMA_CR_CHSEL(SPI1_RX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID1.txdmamode = STM32_DMA_CR_CHSEL(SPI1_TX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI2 + spiObjectInit(&SPID2); + SPID2.spi = SPI2; + SPID2.dmarx = NULL; + SPID2.dmatx = NULL; + SPID2.rxdmamode = STM32_DMA_CR_CHSEL(SPI2_RX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID2.txdmamode = STM32_DMA_CR_CHSEL(SPI2_TX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI3 + spiObjectInit(&SPID3); + SPID3.spi = SPI3; + SPID3.dmarx = NULL; + SPID3.dmatx = NULL; + SPID3.rxdmamode = STM32_DMA_CR_CHSEL(SPI3_RX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID3.txdmamode = STM32_DMA_CR_CHSEL(SPI3_TX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI4 + spiObjectInit(&SPID4); + SPID4.spi = SPI4; + SPID4.dmarx = NULL; + SPID4.dmatx = NULL; + SPID4.rxdmamode = STM32_DMA_CR_CHSEL(SPI4_RX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID4.txdmamode = STM32_DMA_CR_CHSEL(SPI4_TX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI5 + spiObjectInit(&SPID5); + SPID5.spi = SPI5; + SPID5.dmarx = NULL; + SPID5.dmatx = NULL; + SPID5.rxdmamode = STM32_DMA_CR_CHSEL(SPI5_RX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID5.txdmamode = STM32_DMA_CR_CHSEL(SPI5_TX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif + +#if STM32_SPI_USE_SPI6 + spiObjectInit(&SPID6); + SPID6.spi = SPI6; + SPID6.dmarx = NULL; + SPID6.dmatx = NULL; + SPID6.rxdmamode = STM32_DMA_CR_CHSEL(SPI6_RX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID6.txdmamode = STM32_DMA_CR_CHSEL(SPI6_TX_DMA_STREAM) | + STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif +} + +/** + * @brief Configures and activates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_start(SPIDriver *spip) { + uint32_t ds; + + /* If in stopped state then enables the SPI and DMA clocks.*/ + if (spip->state == SPI_STOP) { +#if STM32_SPI_USE_SPI1 + if (&SPID1 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI1_RX_DMA_STREAM, + STM32_SPI_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI1_TX_DMA_STREAM, + STM32_SPI_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI1(true); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI1_RX); + dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI1_TX); +#endif + } +#endif +#if STM32_SPI_USE_SPI2 + if (&SPID2 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI2_RX_DMA_STREAM, + STM32_SPI_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI2_TX_DMA_STREAM, + STM32_SPI_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI2(true); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI2_RX); + dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI2_TX); +#endif + } +#endif +#if STM32_SPI_USE_SPI3 + if (&SPID3 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI3_RX_DMA_STREAM, + STM32_SPI_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI3_TX_DMA_STREAM, + STM32_SPI_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI3(true); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI3_RX); + dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI3_TX); +#endif + } +#endif +#if STM32_SPI_USE_SPI4 + if (&SPID4 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI4_RX_DMA_STREAM, + STM32_SPI_SPI4_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI4_TX_DMA_STREAM, + STM32_SPI_SPI4_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI4(true); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI4_RX); + dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI4_TX); +#endif + } +#endif +#if STM32_SPI_USE_SPI5 + if (&SPID5 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI5_RX_DMA_STREAM, + STM32_SPI_SPI5_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI5_TX_DMA_STREAM, + STM32_SPI_SPI5_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI5(true); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI5_RX); + dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI5_TX); +#endif + } +#endif +#if STM32_SPI_USE_SPI6 + if (&SPID6 == spip) { + spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI6_RX_DMA_STREAM, + STM32_SPI_SPI6_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream"); + spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI6_TX_DMA_STREAM, + STM32_SPI_SPI6_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream"); + rccEnableSPI6(true); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI6_RX); + dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI6_TX); +#endif + } +#endif + + /* DMA setup.*/ + dmaStreamSetPeripheral(spip->dmarx, &spip->spi->DR); + dmaStreamSetPeripheral(spip->dmatx, &spip->spi->DR); + } + + /* Configuration-specific DMA setup.*/ + ds = spip->config->cr2 & SPI_CR2_DS; + if (!ds || (ds <= (SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0))) { + /* Frame width is 8 bits or smaller.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + } + else { + /* Frame width is larger than 8 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + } + + if (spip->config->circular) { + spip->rxdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + spip->txdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + } + else { + spip->rxdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + spip->txdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + } + + /* SPI setup and enable.*/ + spip->spi->CR1 &= ~SPI_CR1_SPE; + spip->spi->CR1 = spip->config->cr1 | SPI_CR1_MSTR; + spip->spi->CR2 = spip->config->cr2 | SPI_CR2_FRXTH | SPI_CR2_SSOE | + SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN; + spip->spi->CR1 |= SPI_CR1_SPE; +} + +/** + * @brief Deactivates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_stop(SPIDriver *spip) { + + /* If in ready state then disables the SPI clock.*/ + if (spip->state == SPI_READY) { + + /* SPI disable.*/ + spip->spi->CR1 &= ~SPI_CR1_SPE; + spip->spi->CR1 = 0; + spip->spi->CR2 = 0; + dmaStreamFreeI(spip->dmarx); + dmaStreamFreeI(spip->dmatx); + spip->dmarx = NULL; + spip->dmatx = NULL; + +#if STM32_SPI_USE_SPI1 + if (&SPID1 == spip) + rccDisableSPI1(); +#endif +#if STM32_SPI_USE_SPI2 + if (&SPID2 == spip) + rccDisableSPI2(); +#endif +#if STM32_SPI_USE_SPI3 + if (&SPID3 == spip) + rccDisableSPI3(); +#endif +#if STM32_SPI_USE_SPI4 + if (&SPID4 == spip) + rccDisableSPI4(); +#endif +#if STM32_SPI_USE_SPI5 + if (&SPID5 == spip) + rccDisableSPI5(); +#endif +#if STM32_SPI_USE_SPI6 + if (&SPID6 == spip) + rccDisableSPI6(); +#endif + } +} + +#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__) +/** + * @brief Asserts the slave select signal and prepares for transfers. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_select(SPIDriver *spip) { + + /* No implementation on STM32.*/ +} + +/** + * @brief Deasserts the slave select signal. + * @details The previously selected peripheral is unselected. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_unselect(SPIDriver *spip) { + + /* No implementation on STM32.*/ +} +#endif + +/** + * @brief Ignores data on the SPI bus. + * @details This asynchronous function starts the transmission of a series of + * idle words on the SPI bus and ignores the received data. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be ignored + * + * @notapi + */ +void spi_lld_ignore(SPIDriver *spip, size_t n) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + dmaStreamSetMemory0(spip->dmarx, &dummyrx); + dmaStreamSetTransactionSize(spip->dmarx, n); + dmaStreamSetMode(spip->dmarx, spip->rxdmamode); + + dmaStreamSetMemory0(spip->dmatx, &dummytx); + dmaStreamSetTransactionSize(spip->dmatx, n); + dmaStreamSetMode(spip->dmatx, spip->txdmamode); + + dmaStreamEnable(spip->dmarx); + dmaStreamEnable(spip->dmatx); +} + +/** + * @brief Exchanges data on the SPI bus. + * @details This asynchronous function starts a simultaneous transmit/receive + * operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * @param[in] txbuf the pointer to the transmit buffer + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + dmaStreamSetMemory0(spip->dmarx, rxbuf); + dmaStreamSetTransactionSize(spip->dmarx, n); + dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_MINC); + + dmaStreamSetMemory0(spip->dmatx, txbuf); + dmaStreamSetTransactionSize(spip->dmatx, n); + dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC); + + dmaStreamEnable(spip->dmarx); + dmaStreamEnable(spip->dmatx); +} + +/** + * @brief Sends data over the SPI bus. + * @details This asynchronous function starts a transmit operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + dmaStreamSetMemory0(spip->dmarx, &dummyrx); + dmaStreamSetTransactionSize(spip->dmarx, n); + dmaStreamSetMode(spip->dmarx, spip->rxdmamode); + + dmaStreamSetMemory0(spip->dmatx, txbuf); + dmaStreamSetTransactionSize(spip->dmatx, n); + dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC); + + dmaStreamEnable(spip->dmarx); + dmaStreamEnable(spip->dmatx); +} + +/** + * @brief Receives data from the SPI bus. + * @details This asynchronous function starts a receive operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to receive + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + dmaStreamSetMemory0(spip->dmarx, rxbuf); + dmaStreamSetTransactionSize(spip->dmarx, n); + dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_MINC); + + dmaStreamSetMemory0(spip->dmatx, &dummytx); + dmaStreamSetTransactionSize(spip->dmatx, n); + dmaStreamSetMode(spip->dmatx, spip->txdmamode); + + dmaStreamEnable(spip->dmarx); + dmaStreamEnable(spip->dmatx); +} + +#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__) +/** + * @brief Aborts the ongoing SPI operation, if any. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_abort(SPIDriver *spip) { + + /* Stopping DMAs.*/ + dmaStreamDisable(spip->dmatx); + dmaStreamDisable(spip->dmarx); +} +#endif /* SPI_SUPPORTS_CIRCULAR == TRUE */ + +/** + * @brief Exchanges one frame using a polled wait. + * @details This synchronous function exchanges one frame using a polled + * synchronization method. This function is useful when exchanging + * small amount of data on high speed channels, usually in this + * situation is much more efficient just wait for completion using + * polling than suspending the thread waiting for an interrupt. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] frame the data frame to send over the SPI bus + * @return The received data frame from the SPI bus. + */ +uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) { + + /* + * Data register must be accessed with the appropriate data size. + * Byte size access (uint8_t *) for transactions that are <= 8-bit. + * Halfword size access (uint16_t) for transactions that are <= 8-bit. + */ + if ((spip->config->cr2 & SPI_CR2_DS) <= (SPI_CR2_DS_2 | + SPI_CR2_DS_1 | + SPI_CR2_DS_0)) { + volatile uint8_t *spidr = (volatile uint8_t *)&spip->spi->DR; + *spidr = (uint8_t)frame; + while ((spip->spi->SR & SPI_SR_RXNE) == 0) + ; + return (uint16_t)*spidr; + } + else { + spip->spi->DR = frame; + while ((spip->spi->SR & SPI_SR_RXNE) == 0) + ; + return spip->spi->DR; + } +} + +#endif /* HAL_USE_SPI */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.h new file mode 100644 index 0000000..3ded6ed --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.h @@ -0,0 +1,552 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv2/hal_spi_lld.h + * @brief STM32 SPI subsystem low level driver header. + * + * @addtogroup SPI + * @{ + */ + +#ifndef HAL_SPI_LLD_H +#define HAL_SPI_LLD_H + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Circular mode support flag. + */ +#define SPI_SUPPORTS_CIRCULAR TRUE + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SPI1 driver enable switch. + * @details If set to @p TRUE the support for SPI1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI1) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI1 FALSE +#endif + +/** + * @brief SPI2 driver enable switch. + * @details If set to @p TRUE the support for SPI2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI2) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI2 FALSE +#endif + +/** + * @brief SPI3 driver enable switch. + * @details If set to @p TRUE the support for SPI3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI3) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI3 FALSE +#endif + +/** + * @brief SPI4 driver enable switch. + * @details If set to @p TRUE the support for SPI4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI4) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI4 FALSE +#endif + +/** + * @brief SPI5 driver enable switch. + * @details If set to @p TRUE the support for SPI5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI5) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI5 FALSE +#endif + +/** + * @brief SPI6 driver enable switch. + * @details If set to @p TRUE the support for SPI6 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI6) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI6 FALSE +#endif + +/** + * @brief SPI1 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI1_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI2 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI2_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI3 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI3_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI4 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI4_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI5 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI5_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI6 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI6_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI6_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI1 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI1_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI2 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI2_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI3 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI3_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI4 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI4_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI5 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI5_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI5_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI6 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI6_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI6_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI DMA error hook. + */ +#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 && !STM32_HAS_SPI1 +#error "SPI1 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI2 && !STM32_HAS_SPI2 +#error "SPI2 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI3 && !STM32_HAS_SPI3 +#error "SPI3 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI4 && !STM32_HAS_SPI4 +#error "SPI4 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI5 && !STM32_HAS_SPI5 +#error "SPI5 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI6 && !STM32_HAS_SPI6 +#error "SPI6 not present in the selected device" +#endif + +#if !STM32_SPI_USE_SPI1 && !STM32_SPI_USE_SPI2 && !STM32_SPI_USE_SPI3 && \ + !STM32_SPI_USE_SPI4 && !STM32_SPI_USE_SPI5 && !STM32_SPI_USE_SPI6 +#error "SPI driver activated but no SPI peripheral assigned" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI1" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI2" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI3" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI4" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI5" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI6_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI6" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI1" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI2" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI3" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI4" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI5_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI5" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI6_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI6" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_SPI_USE_SPI1 && (!defined(STM32_SPI_SPI1_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI1_TX_DMA_STREAM)) +#error "SPI1 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI2 && (!defined(STM32_SPI_SPI2_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI2_TX_DMA_STREAM)) +#error "SPI2 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI3 && (!defined(STM32_SPI_SPI3_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI3_TX_DMA_STREAM)) +#error "SPI3 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI4 && (!defined(STM32_SPI_SPI4_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI4_TX_DMA_STREAM)) +#error "SPI4 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI5 && (!defined(STM32_SPI_SPI5_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI5_TX_DMA_STREAM)) +#error "SPI5 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI6 && (!defined(STM32_SPI_SPI6_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI6_TX_DMA_STREAM)) +#error "SPI6 DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI1 TX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI2 RX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI2 TX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI3 RX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI3 TX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI4 RX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI4 TX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI5 RX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI5 TX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI6_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI6 RX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI6_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to SPI6 TX" +#endif + +/* Devices without DMAMUX require an additional check.*/ +#if STM32_ADVANCED_DMA && !STM32_DMA_SUPPORTS_DMAMUX + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 RX" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 TX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 RX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 TX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 RX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 TX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_RX_DMA_STREAM, STM32_SPI4_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI4 RX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_TX_DMA_STREAM, STM32_SPI4_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI4 TX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_RX_DMA_STREAM, STM32_SPI5_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI5 RX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_TX_DMA_STREAM, STM32_SPI5_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI5 TX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_RX_DMA_STREAM, STM32_SPI6_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI6 RX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_TX_DMA_STREAM, STM32_SPI6_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI6 TX" +#endif + +#endif /* STM32_ADVANCED_DMA && !STM32_DMA_SUPPORTS_DMAMUX */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +#if SPI_SELECT_MODE == SPI_SELECT_MODE_LLD +#error "SPI_SELECT_MODE_LLD not supported by this driver" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the SPI driver structure. + */ +#define spi_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /* Receive DMA stream.*/ \ + const stm32_dma_stream_t *dmarx; \ + /* Transmit DMA stream.*/ \ + const stm32_dma_stream_t *dmatx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode + +/** + * @brief Low level fields of the SPI configuration structure. + */ +#define spi_lld_config_fields \ + /* SPI CR1 register initialization data.*/ \ + uint16_t cr1; \ + /* SPI CR2 register initialization data.*/ \ + uint16_t cr2 + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 && !defined(__DOXYGEN__) +extern SPIDriver SPID1; +#endif + +#if STM32_SPI_USE_SPI2 && !defined(__DOXYGEN__) +extern SPIDriver SPID2; +#endif + +#if STM32_SPI_USE_SPI3 && !defined(__DOXYGEN__) +extern SPIDriver SPID3; +#endif + +#if STM32_SPI_USE_SPI4 && !defined(__DOXYGEN__) +extern SPIDriver SPID4; +#endif + +#if STM32_SPI_USE_SPI5 && !defined(__DOXYGEN__) +extern SPIDriver SPID5; +#endif + +#if STM32_SPI_USE_SPI6 && !defined(__DOXYGEN__) +extern SPIDriver SPID6; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void spi_lld_init(void); + void spi_lld_start(SPIDriver *spip); + void spi_lld_stop(SPIDriver *spip); +#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__) + void spi_lld_select(SPIDriver *spip); + void spi_lld_unselect(SPIDriver *spip); +#endif + void spi_lld_ignore(SPIDriver *spip, size_t n); + void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf); + void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf); + void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf); +#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__) + void spi_lld_abort(SPIDriver *spip); +#endif + uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SPI */ + +#endif /* HAL_SPI_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/driver.mk new file mode 100644 index 0000000..b29942c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c new file mode 100644 index 0000000..4a67c87 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c @@ -0,0 +1,1140 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv3/hal_spi_lld.c + * @brief STM32 SPI subsystem low level driver source. + * + * @addtogroup SPI + * @{ + */ + +#include "hal.h" + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief SPI1 driver identifier.*/ +#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__) +SPIDriver SPID1; +#endif + +/** @brief SPI2 driver identifier.*/ +#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__) +SPIDriver SPID2; +#endif + +/** @brief SPI3 driver identifier.*/ +#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__) +SPIDriver SPID3; +#endif + +/** @brief SPI4 driver identifier.*/ +#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__) +SPIDriver SPID4; +#endif + +/** @brief SPI5 driver identifier.*/ +#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__) +SPIDriver SPID5; +#endif + +/** @brief SPI6 driver identifier.*/ +#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__) +SPIDriver SPID6; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const uint32_t dummytx = STM32_SPI_FILLER_PATTERN; +static uint32_t dummyrx; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static void spi_lld_wait_complete(SPIDriver *spip) { + + while ((spip->spi->CR1 & SPI_CR1_CSTART) != 0) { + } + spip->spi->IFCR = 0xFFFFFFFF; +} + +#if defined(STM32_SPI_BDMA_REQUIRED) +/** + * @brief Shared DMA end-of-rx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_bdma_rx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_SPI_DMA_ERROR_HOOK) + if ((flags & STM32_BDMA_ISR_TEIF) != 0U) { + STM32_SPI_DMA_ERROR_HOOK(spip); + } +#else + (void)flags; +#endif + + if (spip->config->circular) { + if ((flags & STM32_BDMA_ISR_HTIF) != 0U) { + /* Half buffer interrupt.*/ + _spi_isr_half_code(spip); + } + if ((flags & STM32_BDMA_ISR_TCIF) != 0U) { + /* End buffer interrupt.*/ + _spi_isr_full_code(spip); + } + } + else { + /* Stopping SPI.*/ + spip->spi->CR1 |= SPI_CR1_CSUSP; + + /* Stopping DMAs.*/ + bdmaStreamDisable(spip->tx.bdma); + bdmaStreamDisable(spip->rx.bdma); + + /* Portable SPI ISR code defined in the high level driver, note, it is + a macro.*/ + _spi_isr_code(spip); + } +} + +/** + * @brief Shared BDMA end-of-tx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_bdma_tx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_SPI_DMA_ERROR_HOOK) + (void)spip; + if ((flags & STM32_BDMA_ISR_TEIF) != 0) { + STM32_SPI_DMA_ERROR_HOOK(spip); + } +#else + (void)spip; + (void)flags; +#endif +} +#endif /* defined(STM32_SPI_BDMA_REQUIRED) */ + +#if defined(STM32_SPI_DMA_REQUIRED) +/** + * @brief Shared DMA end-of-rx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_dma_rx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_SPI_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) { + STM32_SPI_DMA_ERROR_HOOK(spip); + } +#else + (void)flags; +#endif + + if (spip->config->circular) { + if ((flags & STM32_DMA_ISR_HTIF) != 0U) { + /* Half buffer interrupt.*/ + _spi_isr_half_code(spip); + } + if ((flags & STM32_DMA_ISR_TCIF) != 0U) { + /* End buffer interrupt.*/ + _spi_isr_full_code(spip); + } + } + else { + /* Stopping SPI.*/ + spip->spi->CR1 |= SPI_CR1_CSUSP; + + /* Stopping DMAs.*/ + dmaStreamDisable(spip->tx.dma); + dmaStreamDisable(spip->rx.dma); + + /* Portable SPI ISR code defined in the high level driver, note, it is + a macro.*/ + _spi_isr_code(spip); + } +} + +/** + * @brief Shared DMA end-of-tx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_dma_tx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_SPI_DMA_ERROR_HOOK) + (void)spip; + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_SPI_DMA_ERROR_HOOK(spip); + } +#else + (void)spip; + (void)flags; +#endif +} +#endif /* defined(STM32_SPI_DMA_REQUIRED) */ + +/** + * @brief Shared SPI service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + */ +static void spi_lld_serve_interrupt(SPIDriver *spip) { + uint32_t sr; + + sr = spip->spi->SR & spip->spi->IER; + spip->spi->IFCR = sr; + + if ((sr & SPI_SR_OVR) != 0U) { + /* CHTODO: fault notification.*/ + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__) +#if !defined(STM32_SPI1_SUPPRESS_ISR) +#if !defined(STM32_SPI1_HANDLER) +#error "STM32_SPI1_HANDLER not defined" +#endif +/** + * @brief SPI1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI1_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI1 */ + +#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__) +#if !defined(STM32_SPI2_SUPPRESS_ISR) +#if !defined(STM32_SPI2_HANDLER) +#error "STM32_SPI2_HANDLER not defined" +#endif +/** + * @brief SPI2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI2_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI2 */ + +#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__) +#if !defined(STM32_SPI3_SUPPRESS_ISR) +#if !defined(STM32_SPI3_HANDLER) +#error "STM32_SPI3_HANDLER not defined" +#endif +/** + * @brief SPI3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID3); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI3_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI3 */ + +#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__) +#if !defined(STM32_SPI4_SUPPRESS_ISR) +#if !defined(STM32_SPI4_HANDLER) +#error "STM32_SPI4_HANDLER not defined" +#endif +/** + * @brief SPI4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID4); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI4_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI4 */ + +#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__) +#if !defined(STM32_SPI5_SUPPRESS_ISR) +#if !defined(STM32_SPI5_HANDLER) +#error "STM32_SPI5_HANDLER not defined" +#endif +/** + * @brief SPI5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID5); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI5_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI5 */ + +#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__) +#if !defined(STM32_SPI6_SUPPRESS_ISR) +#if !defined(STM32_SPI6_HANDLER) +#error "STM32_SPI6_HANDLER not defined" +#endif +/** + * @brief SPI6 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID6); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI6_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI6 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SPI driver initialization. + * + * @notapi + */ +void spi_lld_init(void) { + +#if STM32_SPI_USE_SPI1 + spiObjectInit(&SPID1); + SPID1.spi = SPI1; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID1.is_bdma = false; +#endif + SPID1.rx.dma = NULL; + SPID1.tx.dma = NULL; + SPID1.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID1.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI1_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI1_NUMBER, STM32_SPI_SPI1_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI2 + spiObjectInit(&SPID2); + SPID2.spi = SPI2; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID2.is_bdma = false; +#endif + SPID2.rx.dma = NULL; + SPID2.tx.dma = NULL; + SPID2.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID2.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI2_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI2_NUMBER, STM32_SPI_SPI2_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI3 + spiObjectInit(&SPID3); + SPID3.spi = SPI3; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID3.is_bdma = false; +#endif + SPID3.rx.dma = NULL; + SPID3.tx.dma = NULL; + SPID3.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID3.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI3_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI3_NUMBER, STM32_SPI_SPI3_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI4 + spiObjectInit(&SPID4); + SPID4.spi = SPI4; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID4.is_bdma = false; +#endif + SPID4.rx.dma = NULL; + SPID4.tx.dma = NULL; + SPID4.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID4.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI4_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI4_NUMBER, STM32_SPI_SPI4_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI5 + spiObjectInit(&SPID5); + SPID5.spi = SPI5; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID5.is_bdma = false; +#endif + SPID5.rx.dma = NULL; + SPID5.tx.dma = NULL; + SPID5.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID5.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI5_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI5_NUMBER, STM32_SPI_SPI5_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI6 + spiObjectInit(&SPID6); + SPID6.spi = SPI6; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID6.is_bdma = true; +#endif + SPID6.rx.bdma = NULL; + SPID6.tx.bdma = NULL; + SPID6.rxdmamode = STM32_BDMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) | + STM32_BDMA_CR_DIR_P2M | + STM32_BDMA_CR_TCIE | + STM32_BDMA_CR_TEIE; + SPID6.txdmamode = STM32_BDMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) | + STM32_BDMA_CR_DIR_M2P | + STM32_BDMA_CR_TEIE; +#if !defined(STM32_SPI6_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI6_NUMBER, STM32_SPI_SPI6_IRQ_PRIORITY); +#endif +#endif +} + +/** + * @brief Configures and activates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_start(SPIDriver *spip) { + uint32_t dsize; + + /* If in stopped state then enables the SPI and DMA clocks.*/ + if (spip->state == SPI_STOP) { +#if STM32_SPI_USE_SPI1 + if (&SPID1 == spip) { + spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI1_RX_DMA_STREAM, + STM32_SPI_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream"); + spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI1_TX_DMA_STREAM, + STM32_SPI_SPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream"); + rccEnableSPI1(true); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI1_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI1_TX); + } +#endif +#if STM32_SPI_USE_SPI2 + if (&SPID2 == spip) { + spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI2_RX_DMA_STREAM, + STM32_SPI_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream"); + spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI2_TX_DMA_STREAM, + STM32_SPI_SPI2_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream"); + rccEnableSPI2(true); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI2_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI2_TX); + } +#endif +#if STM32_SPI_USE_SPI3 + if (&SPID3 == spip) { + spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI3_RX_DMA_STREAM, + STM32_SPI_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream"); + spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI3_TX_DMA_STREAM, + STM32_SPI_SPI3_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream"); + rccEnableSPI3(true); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI3_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI3_TX); + } +#endif +#if STM32_SPI_USE_SPI4 + if (&SPID4 == spip) { + spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI4_RX_DMA_STREAM, + STM32_SPI_SPI4_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream"); + spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI4_TX_DMA_STREAM, + STM32_SPI_SPI4_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream"); + rccEnableSPI4(true); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI4_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI4_TX); + } +#endif +#if STM32_SPI_USE_SPI5 + if (&SPID5 == spip) { + spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI5_RX_DMA_STREAM, + STM32_SPI_SPI5_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream"); + spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI5_TX_DMA_STREAM, + STM32_SPI_SPI5_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream"); + rccEnableSPI5(true); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI5_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI5_TX); + } +#endif +#if STM32_SPI_USE_SPI6 + if (&SPID6 == spip) { + spip->rx.bdma = bdmaStreamAllocI(STM32_SPI_SPI6_RX_BDMA_STREAM, + STM32_SPI_SPI6_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_bdma_rx_interrupt, + (void *)spip); + osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream"); + spip->tx.bdma = bdmaStreamAllocI(STM32_SPI_SPI6_TX_BDMA_STREAM, + STM32_SPI_SPI6_IRQ_PRIORITY, + (stm32_dmaisr_t)spi_lld_serve_bdma_tx_interrupt, + (void *)spip); + osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream"); + rccEnableSPI6(true); + bdmaSetRequestSource(spip->rx.bdma, STM32_DMAMUX2_SPI6_RX); + bdmaSetRequestSource(spip->tx.bdma, STM32_DMAMUX2_SPI6_TX); + } +#endif + + /* DMA setup.*/ +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetPeripheral(spip->rx.bdma, &spip->spi->RXDR); + bdmaStreamSetPeripheral(spip->tx.bdma, &spip->spi->TXDR); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetPeripheral(spip->rx.dma, &spip->spi->RXDR); + dmaStreamSetPeripheral(spip->tx.dma, &spip->spi->TXDR); + } +#endif + } + + /* Configuration-specific DMA setup.*/ + dsize = (spip->config->cfg1 & SPI_CFG1_DSIZE_Msk) + 1U; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + if (dsize <= 8U) { + /* Frame width is between 4 and 8 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_BYTE | STM32_BDMA_CR_MSIZE_BYTE; + spip->txdmamode = (spip->txdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_BYTE | STM32_BDMA_CR_MSIZE_BYTE; + } + else if (dsize <= 16U) { + /* Frame width is between 9 and 16 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_HWORD | STM32_BDMA_CR_MSIZE_HWORD; + spip->txdmamode = (spip->txdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_HWORD | STM32_BDMA_CR_MSIZE_HWORD; + } + else { + /* Frame width is between 16 and 32 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_WORD | STM32_BDMA_CR_MSIZE_WORD; + spip->txdmamode = (spip->txdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_WORD | STM32_BDMA_CR_MSIZE_WORD; + } + if (spip->config->circular) { + spip->rxdmamode |= (STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE); + spip->txdmamode |= (STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE); + } + else { + spip->rxdmamode &= ~(STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE); + spip->txdmamode &= ~(STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE); + } + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + if (dsize <= 8U) { + /* Frame width is between 4 and 8 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + } + else if (dsize <= 16U) { + /* Frame width is between 9 and 16 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + } + else { + /* Frame width is between 16 and 32 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD; + } + if (spip->config->circular) { + spip->rxdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + spip->txdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + } + else { + spip->rxdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + spip->txdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + } + } +#endif + + /* SPI setup and enable.*/ + spip->spi->CR1 &= ~SPI_CR1_SPE; + spip->spi->CR1 = SPI_CR1_MASRX; + spip->spi->CR2 = 0U; + spip->spi->CFG1 = (spip->config->cfg1 & ~SPI_CFG1_FTHLV_Msk) | + SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN; + spip->spi->CFG2 = (spip->config->cfg2 | SPI_CFG2_MASTER | SPI_CFG2_SSOE) & + ~SPI_CFG2_COMM_Msk; + spip->spi->IER = SPI_IER_OVRIE; + spip->spi->IFCR = 0xFFFFFFFFU; + spip->spi->CR1 |= SPI_CR1_SPE; +} + +/** + * @brief Deactivates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_stop(SPIDriver *spip) { + + /* If in ready state then disables the SPI clock.*/ + if (spip->state == SPI_READY) { + + /* SPI disable.*/ + spip->spi->CR1 &= ~SPI_CR1_SPE; + spip->spi->CR1 = 0U; + spip->spi->CR2 = 0U; + spip->spi->CFG1 = 0U; + spip->spi->CFG2 = 0U; + spip->spi->IER = 0U; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamFreeI(spip->rx.bdma); + bdmaStreamFreeI(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamFreeI(spip->rx.dma); + dmaStreamFreeI(spip->tx.dma); + } +#endif + +#if STM32_SPI_USE_SPI1 + if (&SPID1 == spip) + rccDisableSPI1(); +#endif +#if STM32_SPI_USE_SPI2 + if (&SPID2 == spip) + rccDisableSPI2(); +#endif +#if STM32_SPI_USE_SPI3 + if (&SPID3 == spip) + rccDisableSPI3(); +#endif +#if STM32_SPI_USE_SPI4 + if (&SPID4 == spip) + rccDisableSPI4(); +#endif +#if STM32_SPI_USE_SPI5 + if (&SPID5 == spip) + rccDisableSPI5(); +#endif +#if STM32_SPI_USE_SPI6 + if (&SPID6 == spip) + rccDisableSPI6(); +#endif + } +} + +#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__) +/** + * @brief Asserts the slave select signal and prepares for transfers. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_select(SPIDriver *spip) { + + /* No implementation on STM32.*/ +} + +/** + * @brief Deasserts the slave select signal. + * @details The previously selected peripheral is unselected. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_unselect(SPIDriver *spip) { + + /* No implementation on STM32.*/ +} +#endif + +/** + * @brief Ignores data on the SPI bus. + * @details This asynchronous function starts the transmission of a series of + * idle words on the SPI bus and ignores the received data. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be ignored + * + * @notapi + */ +void spi_lld_ignore(SPIDriver *spip, size_t n) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetMemory(spip->rx.bdma, &dummyrx); + bdmaStreamSetTransactionSize(spip->rx.bdma, n); + bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode); + + bdmaStreamSetMemory(spip->tx.bdma, &dummytx); + bdmaStreamSetTransactionSize(spip->tx.bdma, n); + bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode); + + bdmaStreamEnable(spip->rx.bdma); + bdmaStreamEnable(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetMemory0(spip->rx.dma, &dummyrx); + dmaStreamSetTransactionSize(spip->rx.dma, n); + dmaStreamSetMode(spip->rx.dma, spip->rxdmamode); + + dmaStreamSetMemory0(spip->tx.dma, &dummytx); + dmaStreamSetTransactionSize(spip->tx.dma, n); + dmaStreamSetMode(spip->tx.dma, spip->txdmamode); + + dmaStreamEnable(spip->rx.dma); + dmaStreamEnable(spip->tx.dma); + } +#endif + + spip->spi->CR1 |= SPI_CR1_CSTART; +} + +/** + * @brief Exchanges data on the SPI bus. + * @details This asynchronous function starts a simultaneous transmit/receive + * operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * @param[in] txbuf the pointer to the transmit buffer + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + spi_lld_wait_complete(spip); + +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetMemory(spip->rx.bdma, rxbuf); + bdmaStreamSetTransactionSize(spip->rx.bdma, n); + bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode | STM32_BDMA_CR_MINC); + + bdmaStreamSetMemory(spip->tx.bdma, txbuf); + bdmaStreamSetTransactionSize(spip->tx.bdma, n); + bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode | STM32_BDMA_CR_MINC); + + bdmaStreamEnable(spip->rx.bdma); + bdmaStreamEnable(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetMemory0(spip->rx.dma, rxbuf); + dmaStreamSetTransactionSize(spip->rx.dma, n); + dmaStreamSetMode(spip->rx.dma, spip->rxdmamode | STM32_DMA_CR_MINC); + + dmaStreamSetMemory0(spip->tx.dma, txbuf); + dmaStreamSetTransactionSize(spip->tx.dma, n); + dmaStreamSetMode(spip->tx.dma, spip->txdmamode | STM32_DMA_CR_MINC); + + dmaStreamEnable(spip->rx.dma); + dmaStreamEnable(spip->tx.dma); + } +#endif + + spip->spi->CR1 |= SPI_CR1_CSTART; +} + +/** + * @brief Sends data over the SPI bus. + * @details This asynchronous function starts a transmit operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + spi_lld_wait_complete(spip); + +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetMemory(spip->rx.bdma, &dummyrx); + bdmaStreamSetTransactionSize(spip->rx.bdma, n); + bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode); + + bdmaStreamSetMemory(spip->tx.bdma, txbuf); + bdmaStreamSetTransactionSize(spip->tx.bdma, n); + bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode | STM32_BDMA_CR_MINC); + + bdmaStreamEnable(spip->rx.bdma); + bdmaStreamEnable(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetMemory0(spip->rx.dma, &dummyrx); + dmaStreamSetTransactionSize(spip->rx.dma, n); + dmaStreamSetMode(spip->rx.dma, spip->rxdmamode); + + dmaStreamSetMemory0(spip->tx.dma, txbuf); + dmaStreamSetTransactionSize(spip->tx.dma, n); + dmaStreamSetMode(spip->tx.dma, spip->txdmamode | STM32_DMA_CR_MINC); + + dmaStreamEnable(spip->rx.dma); + dmaStreamEnable(spip->tx.dma); + } +#endif + + spip->spi->CR1 |= SPI_CR1_CSTART; +} + +/** + * @brief Receives data from the SPI bus. + * @details This asynchronous function starts a receive operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to receive + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + spi_lld_wait_complete(spip); + +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetMemory(spip->rx.bdma, rxbuf); + bdmaStreamSetTransactionSize(spip->rx.bdma, n); + bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode | STM32_BDMA_CR_MINC); + + bdmaStreamSetMemory(spip->tx.bdma, &dummytx); + bdmaStreamSetTransactionSize(spip->tx.bdma, n); + bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode); + + bdmaStreamEnable(spip->rx.bdma); + bdmaStreamEnable(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetMemory0(spip->rx.dma, rxbuf); + dmaStreamSetTransactionSize(spip->rx.dma, n); + dmaStreamSetMode(spip->rx.dma, spip->rxdmamode | STM32_DMA_CR_MINC); + + dmaStreamSetMemory0(spip->tx.dma, &dummytx); + dmaStreamSetTransactionSize(spip->tx.dma, n); + dmaStreamSetMode(spip->tx.dma, spip->txdmamode); + + dmaStreamEnable(spip->rx.dma); + dmaStreamEnable(spip->tx.dma); + } +#endif + + spip->spi->CR1 |= SPI_CR1_CSTART; +} + +#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__) +/** + * @brief Aborts the ongoing SPI operation, if any. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_abort(SPIDriver *spip) { + + /* Stopping SPI.*/ + spip->spi->CR1 |= SPI_CR1_CSUSP; + + spi_lld_wait_complete(spip); + + /* Stopping DMAs.*/ +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamDisable(spip->tx.bdma); + bdmaStreamDisable(spip->rx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamDisable(spip->tx.dma); + dmaStreamDisable(spip->rx.dma); + } +#endif +} +#endif /* SPI_SUPPORTS_CIRCULAR == TRUE */ + +/** + * @brief Exchanges one frame using a polled wait. + * @details This synchronous function exchanges one frame using a polled + * synchronization method. This function is useful when exchanging + * small amount of data on high speed channels, usually in this + * situation is much more efficient just wait for completion using + * polling than suspending the thread waiting for an interrupt. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] frame the data frame to send over the SPI bus + * @return The received data frame from the SPI bus. + * + * @notapi + */ +uint32_t spi_lld_polled_exchange(SPIDriver *spip, uint32_t frame) { + uint32_t dsize = (spip->spi->CFG1 & SPI_CFG1_DSIZE_Msk) + 1U; + uint32_t rxframe; + + spi_lld_wait_complete(spip); + + spip->spi->CR1 |= SPI_CR1_CSTART; + + /* wait for room in TX FIFO.*/ + while ((spip->spi->SR & SPI_SR_TXP) == 0U) + ; + + /* Data register must be accessed with the appropriate data size. + Byte size access (uint8_t *) for transactions that are <= 8-bit etc.*/ + if (dsize <= 8U) { + /* Frame width is between 4 and 8 bits.*/ + volatile uint8_t *txdrp8 = (volatile uint8_t *)&spip->spi->TXDR; + volatile uint8_t *rxdrp8 = (volatile uint8_t *)&spip->spi->RXDR; + *txdrp8 = (uint8_t)frame; + while ((spip->spi->SR & SPI_SR_RXP) == 0U) + ; + rxframe = (uint32_t)*rxdrp8; + } + else if (dsize <= 16U) { + /* Frame width is between 9 and 16 bits.*/ + volatile uint16_t *txdrp16 = (volatile uint16_t *)&spip->spi->TXDR; + volatile uint16_t *rxdrp16 = (volatile uint16_t *)&spip->spi->RXDR; + *txdrp16 = (uint16_t)frame; + while ((spip->spi->SR & SPI_SR_RXP) == 0U) + ; + rxframe = (uint32_t)*rxdrp16; + } + else { + /* Frame width is between 16 and 32 bits.*/ + spip->spi->TXDR = frame; + while ((spip->spi->SR & SPI_SR_RXP) == 0U) + ; + rxframe = spip->spi->RXDR; + } + + spip->spi->CR1 |= SPI_CR1_CSUSP; + + return rxframe; +} + +#endif /* HAL_USE_SPI */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.h new file mode 100644 index 0000000..c906524 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.h @@ -0,0 +1,590 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file SPIv3/hal_spi_lld.h + * @brief STM32 SPI subsystem low level driver header. + * + * @addtogroup SPI + * @{ + */ + +#ifndef HAL_SPI_LLD_H +#define HAL_SPI_LLD_H + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Circular mode support flag. + */ +#define SPI_SUPPORTS_CIRCULAR TRUE + +/** + * @name Register helpers not found in ST headers + * @{ + */ +#define SPI_CFG1_MBR_VALUE(n) ((n) << SPI_CFG1_MBR_Pos) +#define SPI_CFG1_MBR_DIV2 SPI_CFG1_MBR_VALUE(0) +#define SPI_CFG1_MBR_DIV4 SPI_CFG1_MBR_VALUE(1) +#define SPI_CFG1_MBR_DIV8 SPI_CFG1_MBR_VALUE(2) +#define SPI_CFG1_MBR_DIV16 SPI_CFG1_MBR_VALUE(3) +#define SPI_CFG1_MBR_DIV32 SPI_CFG1_MBR_VALUE(4) +#define SPI_CFG1_MBR_DIV64 SPI_CFG1_MBR_VALUE(5) +#define SPI_CFG1_MBR_DIV128 SPI_CFG1_MBR_VALUE(6) +#define SPI_CFG1_MBR_DIV256 SPI_CFG1_MBR_VALUE(7) +#define SPI_CFG1_CRCSIZE_VALUE(n) ((n) << SPI_CFG1_CRCSIZE_Pos) +#define SPI_CFG1_UDRDET_VALUE(n) ((n) << SPI_CFG1_UDRDET_Pos) +#define SPI_CFG1_UDRCFG_VALUE(n) ((n) << SPI_CFG1_UDRCFG_Pos) +#define SPI_CFG1_FTHLV_VALUE(n) ((n) << SPI_CFG1_FTHLV_Pos) +#define SPI_CFG1_DSIZE_VALUE(n) ((n) << SPI_CFG1_DSIZE_Pos) + +#define SPI_CFG2_SP_VALUE(n) ((n) << SPI_CFG2_SP_Pos) +#define SPI_CFG2_COMM_VALUE(n) ((n) << SPI_CFG2_COMM_Pos) +#define SPI_CFG2_COMM_FULL_DUPLEX SPI_CFG2_COMM_VALUE(0) +#define SPI_CFG2_COMM_TRANSMITTER SPI_CFG2_COMM_VALUE(1) +#define SPI_CFG2_COMM_RECEIVER SPI_CFG2_COMM_VALUE(2) +#define SPI_CFG2_COMM_HALF_DUPLEX SPI_CFG2_COMM_VALUE(3) +#define SPI_CFG2_MIDI_VALUE(n) ((n) << SPI_CFG2_MIDI_Pos) +#define SPI_CFG2_MSSI_VALUE(n) ((n) << SPI_CFG2_MSSI_Pos) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SPI1 driver enable switch. + * @details If set to @p TRUE the support for SPI1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI1) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI1 FALSE +#endif + +/** + * @brief SPI2 driver enable switch. + * @details If set to @p TRUE the support for SPI2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI2) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI2 FALSE +#endif + +/** + * @brief SPI3 driver enable switch. + * @details If set to @p TRUE the support for SPI3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI3) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI3 FALSE +#endif + +/** + * @brief SPI4 driver enable switch. + * @details If set to @p TRUE the support for SPI4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI4) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI4 FALSE +#endif + +/** + * @brief SPI5 driver enable switch. + * @details If set to @p TRUE the support for SPI5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI5) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI5 FALSE +#endif + +/** + * @brief SPI6 driver enable switch. + * @details If set to @p TRUE the support for SPI6 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI6) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI6 FALSE +#endif + +/** + * @brief Filler pattern used when there is nothing to transmit. + */ +#if !defined(STM32_SPI_FILLER_PATTERN) || defined(__DOXYGEN__) +#define STM32_SPI_FILLER_PATTERN 0xFFFFFFFFU +#endif + +/** + * @brief SPI1 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI1_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI2 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI2_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI3 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI3_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI4 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI4_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI5 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI5_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI6 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI6_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI6_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI1 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI1_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI2 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI2_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI3 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI3_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI4 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI4_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI5 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI5_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI5_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI6 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI6_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI6_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI DMA error hook. + */ +#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 && !STM32_HAS_SPI1 +#error "SPI1 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI2 && !STM32_HAS_SPI2 +#error "SPI2 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI3 && !STM32_HAS_SPI3 +#error "SPI3 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI4 && !STM32_HAS_SPI4 +#error "SPI4 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI5 && !STM32_HAS_SPI5 +#error "SPI5 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI6 && !STM32_HAS_SPI6 +#error "SPI6 not present in the selected device" +#endif + +#if !STM32_SPI_USE_SPI1 && !STM32_SPI_USE_SPI2 && !STM32_SPI_USE_SPI3 && \ + !STM32_SPI_USE_SPI4 && !STM32_SPI_USE_SPI5 && !STM32_SPI_USE_SPI6 +#error "SPI driver activated but no SPI peripheral assigned" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI1" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI2" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI3" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI4" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI5" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI6_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI6" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_SPI_USE_SPI1 && (!defined(STM32_SPI_SPI1_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI1_TX_DMA_STREAM)) +#error "SPI1 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI2 && (!defined(STM32_SPI_SPI2_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI2_TX_DMA_STREAM)) +#error "SPI2 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI3 && (!defined(STM32_SPI_SPI3_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI3_TX_DMA_STREAM)) +#error "SPI3 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI4 && (!defined(STM32_SPI_SPI4_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI4_TX_DMA_STREAM)) +#error "SPI4 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI5 && (!defined(STM32_SPI_SPI5_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI5_TX_DMA_STREAM)) +#error "SPI5 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI6 && (!defined(STM32_SPI_SPI6_RX_BDMA_STREAM) || \ + !defined(STM32_SPI_SPI6_TX_BDMA_STREAM)) +#error "SPI6 BDMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA streams.*/ +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI1_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI1 RX" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI1 TX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI2 RX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI2 TX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI3 RX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI3 TX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI4 RX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI4 TX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI5 RX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI5 TX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_BDMA_IS_VALID_STREAM(STM32_SPI_SPI6_RX_BDMA_STREAM) +#error "Invalid BDMA stream assigned to SPI6 RX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_BDMA_IS_VALID_STREAM(STM32_SPI_SPI6_TX_BDMA_STREAM) +#error "Invalid BDMA stream assigned to SPI6 TX" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI1" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI2" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI3" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI4" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI5_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI5" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI6_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI6" +#endif + +#if STM32_SPI_USE_SPI1 || STM32_SPI_USE_SPI2 || STM32_SPI_USE_SPI1 || \ + STM32_SPI_USE_SPI4 || STM32_SPI_USE_SPI5 +#define STM32_SPI_DMA_REQUIRED +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif +#endif + +#if STM32_SPI_USE_SPI6 +#define STM32_SPI_BDMA_REQUIRED +#if !defined(STM32_BDMA_REQUIRED) +#define STM32_BDMA_REQUIRED +#endif +#endif + +#if SPI_SELECT_MODE == SPI_SELECT_MODE_LLD +#error "SPI_SELECT_MODE_LLD not supported by this driver" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +#if (defined(STM32_SPI_DMA_REQUIRED) && \ + defined(STM32_SPI_BDMA_REQUIRED)) || defined(__DOXYGEN__) +#define spi_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /** DMA type for this instance.*/ \ + bool is_bdma; \ + /** Union of the RX DMA streams.*/ \ + union { \ + /* Receive DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + /* Receive BDMA stream.*/ \ + const stm32_bdma_stream_t *bdma; \ + } rx; \ + /* Union of the TX DMA streams.*/ \ + union { \ + /* Transmit DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + /* Transmit DMA stream.*/ \ + const stm32_bdma_stream_t *bdma; \ + } tx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode +#endif + +#if defined(STM32_SPI_DMA_REQUIRED) && !defined(STM32_SPI_BDMA_REQUIRED) +#define spi_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /** Union of the RX DMA streams.*/ \ + union { \ + /* Receive DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + } rx; \ + /* Union of the TX DMA streams.*/ \ + union { \ + /* Transmit DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + } tx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode +#endif + +#if !defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) +#define spi_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /** Union of the RX DMA streams.*/ \ + union { \ + /* Receive BDMA stream.*/ \ + const stm32_bdma_stream_t *bdma; \ + } rx; \ + /* Union of the TX DMA streams.*/ \ + union { \ + /* Transmit DMA stream.*/ \ + const stm32_bdma_stream_t *bdma; \ + } tx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode +#endif + +/** + * @brief Low level fields of the SPI configuration structure. + */ +#define spi_lld_config_fields \ + /* SPI CFG1 register initialization data.*/ \ + uint32_t cfg1; \ + /* SPI CFG2 register initialization data.*/ \ + uint32_t cfg2 + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 && !defined(__DOXYGEN__) +extern SPIDriver SPID1; +#endif + +#if STM32_SPI_USE_SPI2 && !defined(__DOXYGEN__) +extern SPIDriver SPID2; +#endif + +#if STM32_SPI_USE_SPI3 && !defined(__DOXYGEN__) +extern SPIDriver SPID3; +#endif + +#if STM32_SPI_USE_SPI4 && !defined(__DOXYGEN__) +extern SPIDriver SPID4; +#endif + +#if STM32_SPI_USE_SPI5 && !defined(__DOXYGEN__) +extern SPIDriver SPID5; +#endif + +#if STM32_SPI_USE_SPI6 && !defined(__DOXYGEN__) +extern SPIDriver SPID6; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void spi_lld_init(void); + void spi_lld_start(SPIDriver *spip); + void spi_lld_stop(SPIDriver *spip); +#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__) + void spi_lld_select(SPIDriver *spip); + void spi_lld_unselect(SPIDriver *spip); +#endif + void spi_lld_ignore(SPIDriver *spip, size_t n); + void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf); + void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf); + void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf); +#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__) + void spi_lld_abort(SPIDriver *spip); +#endif + uint32_t spi_lld_polled_exchange(SPIDriver *spip, uint32_t frame); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SPI */ + +#endif /* HAL_SPI_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/driver.mk new file mode 100644 index 0000000..032d75a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/driver.mk @@ -0,0 +1,19 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c + +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_GPT TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c +endif +ifneq ($(findstring HAL_USE_ICU TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c +endif +ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c new file mode 100644 index 0000000..f7c449e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c @@ -0,0 +1,1153 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/hal_gpt_lld.c + * @brief STM32 GPT subsystem low level driver source. + * + * @addtogroup GPT + * @{ + */ + +#include "hal.h" + +#if HAL_USE_GPT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief GPTD1 driver identifier. + * @note The driver GPTD1 allocates the complex timer TIM1 when enabled. + */ +#if STM32_GPT_USE_TIM1 || defined(__DOXYGEN__) +GPTDriver GPTD1; +#endif + +/** + * @brief GPTD2 driver identifier. + * @note The driver GPTD2 allocates the timer TIM2 when enabled. + */ +#if STM32_GPT_USE_TIM2 || defined(__DOXYGEN__) +GPTDriver GPTD2; +#endif + +/** + * @brief GPTD3 driver identifier. + * @note The driver GPTD3 allocates the timer TIM3 when enabled. + */ +#if STM32_GPT_USE_TIM3 || defined(__DOXYGEN__) +GPTDriver GPTD3; +#endif + +/** + * @brief GPTD4 driver identifier. + * @note The driver GPTD4 allocates the timer TIM4 when enabled. + */ +#if STM32_GPT_USE_TIM4 || defined(__DOXYGEN__) +GPTDriver GPTD4; +#endif + +/** + * @brief GPTD5 driver identifier. + * @note The driver GPTD5 allocates the timer TIM5 when enabled. + */ +#if STM32_GPT_USE_TIM5 || defined(__DOXYGEN__) +GPTDriver GPTD5; +#endif + +/** + * @brief GPTD6 driver identifier. + * @note The driver GPTD6 allocates the timer TIM6 when enabled. + */ +#if STM32_GPT_USE_TIM6 || defined(__DOXYGEN__) +GPTDriver GPTD6; +#endif + +/** + * @brief GPTD7 driver identifier. + * @note The driver GPTD7 allocates the timer TIM7 when enabled. + */ +#if STM32_GPT_USE_TIM7 || defined(__DOXYGEN__) +GPTDriver GPTD7; +#endif + +/** + * @brief GPTD8 driver identifier. + * @note The driver GPTD8 allocates the timer TIM8 when enabled. + */ +#if STM32_GPT_USE_TIM8 || defined(__DOXYGEN__) +GPTDriver GPTD8; +#endif + +/** + * @brief GPTD9 driver identifier. + * @note The driver GPTD9 allocates the timer TIM9 when enabled. + */ +#if STM32_GPT_USE_TIM9 || defined(__DOXYGEN__) +GPTDriver GPTD9; +#endif + +/** + * @brief GPTD10 driver identifier. + * @note The driver GPTD10 allocates the timer TIM10 when enabled. + */ +#if STM32_GPT_USE_TIM10 || defined(__DOXYGEN__) +GPTDriver GPTD10; +#endif + +/** + * @brief GPTD11 driver identifier. + * @note The driver GPTD11 allocates the timer TIM11 when enabled. + */ +#if STM32_GPT_USE_TIM11 || defined(__DOXYGEN__) +GPTDriver GPTD11; +#endif + +/** + * @brief GPTD12 driver identifier. + * @note The driver GPTD12 allocates the timer TIM12 when enabled. + */ +#if STM32_GPT_USE_TIM12 || defined(__DOXYGEN__) +GPTDriver GPTD12; +#endif + +/** + * @brief GPTD13 driver identifier. + * @note The driver GPTD13 allocates the timer TIM13 when enabled. + */ +#if STM32_GPT_USE_TIM13 || defined(__DOXYGEN__) +GPTDriver GPTD13; +#endif + +/** + * @brief GPTD14 driver identifier. + * @note The driver GPTD14 allocates the timer TIM14 when enabled. + */ +#if STM32_GPT_USE_TIM14 || defined(__DOXYGEN__) +GPTDriver GPTD14; +#endif + +/** + * @brief GPTD15 driver identifier. + * @note The driver GPTD14 allocates the timer TIM14 when enabled. + */ +#if STM32_GPT_USE_TIM15 || defined(__DOXYGEN__) +GPTDriver GPTD15; +#endif + +/** + * @brief GPTD16 driver identifier. + * @note The driver GPTD14 allocates the timer TIM14 when enabled. + */ +#if STM32_GPT_USE_TIM16 || defined(__DOXYGEN__) +GPTDriver GPTD16; +#endif + +/** + * @brief GPTD17 driver identifier. + * @note The driver GPTD14 allocates the timer TIM14 when enabled. + */ +#if STM32_GPT_USE_TIM17 || defined(__DOXYGEN__) +GPTDriver GPTD17; +#endif + +/** + * @brief GPTD21 driver identifier. + * @note The driver GPTD21 allocates the timer TIM21 when enabled. + */ +#if STM32_GPT_USE_TIM21 || defined(__DOXYGEN__) +GPTDriver GPTD21; +#endif + +/** + * @brief GPTD22 driver identifier. + * @note The driver GPTD22 allocates the timer TIM22 when enabled. + */ +#if STM32_GPT_USE_TIM22 || defined(__DOXYGEN__) +GPTDriver GPTD22; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_GPT_USE_TIM1 || defined(__DOXYGEN__) +#if !defined(STM32_TIM1_SUPPRESS_ISR) +#if !defined(STM32_TIM1_UP_HANDLER) +#error "STM32_TIM1_UP_HANDLER not defined" +#endif +/** + * @brief TIM1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM1_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM1 */ + +#if STM32_GPT_USE_TIM2 || defined(__DOXYGEN__) +#if !defined(STM32_TIM2_SUPPRESS_ISR) +#if !defined(STM32_TIM2_HANDLER) +#error "STM32_TIM2_HANDLER not defined" +#endif +/** + * @brief TIM2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM2_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM2 */ + +#if STM32_GPT_USE_TIM3 || defined(__DOXYGEN__) +#if !defined(STM32_TIM3_SUPPRESS_ISR) +#if !defined(STM32_TIM3_HANDLER) +#error "STM32_TIM3_HANDLER not defined" +#endif +/** + * @brief TIM3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD3); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM3_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM3 */ + +#if STM32_GPT_USE_TIM4 || defined(__DOXYGEN__) +#if !defined(STM32_TIM4_SUPPRESS_ISR) +#if !defined(STM32_TIM4_HANDLER) +#error "STM32_TIM4_HANDLER not defined" +#endif +/** + * @brief TIM4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD4); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM4_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM4 */ + +#if STM32_GPT_USE_TIM5 || defined(__DOXYGEN__) +#if !defined(STM32_TIM5_SUPPRESS_ISR) +#if !defined(STM32_TIM5_HANDLER) +#error "STM32_TIM5_HANDLER not defined" +#endif +/** + * @brief TIM5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD5); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM5_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM5 */ + +#if STM32_GPT_USE_TIM6 || defined(__DOXYGEN__) +#if !defined(STM32_TIM6_SUPPRESS_ISR) +#if !defined(STM32_TIM6_HANDLER) +#error "STM32_TIM6_HANDLER not defined" +#endif +/** + * @brief TIM6 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD6); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM6_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM6 */ + +#if STM32_GPT_USE_TIM7 || defined(__DOXYGEN__) +#if !defined(STM32_TIM7_SUPPRESS_ISR) +#if !defined(STM32_TIM7_HANDLER) +#error "STM32_TIM7_HANDLER not defined" +#endif +/** + * @brief TIM7 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD7); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM7_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM7 */ + +#if STM32_GPT_USE_TIM8 || defined(__DOXYGEN__) +#if !defined(STM32_TIM8_SUPPRESS_ISR) +#if !defined(STM32_TIM8_UP_HANDLER) +#error "STM32_TIM8_UP_HANDLER not defined" +#endif +/** + * @brief TIM8 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD8); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM8_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM8 */ + +#if STM32_GPT_USE_TIM9 || defined(__DOXYGEN__) +#if !defined(STM32_TIM9_SUPPRESS_ISR) +#error "TIM9 ISR not defined by platform" +#endif /* !defined(STM32_TIM9_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM9 */ + +#if STM32_GPT_USE_TIM10 || defined(__DOXYGEN__) +#if !defined(STM32_TIM10_SUPPRESS_ISR) +#error "TIM10 ISR not defined by platform" +#endif /* !defined(STM32_TIM10_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM10 */ + +#if STM32_GPT_USE_TIM11 || defined(__DOXYGEN__) +#if !defined(STM32_TIM11_SUPPRESS_ISR) +#error "TIM11 ISR not defined by platform" +#endif /* !defined(STM32_TIM11_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM11 */ + +#if STM32_GPT_USE_TIM12 || defined(__DOXYGEN__) +#if !defined(STM32_TIM12_SUPPRESS_ISR) +#error "TIM12 ISR not defined by platform" +#endif /* !defined(STM32_TIM12_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM12 */ + +#if STM32_GPT_USE_TIM13 || defined(__DOXYGEN__) +#if !defined(STM32_TIM13_SUPPRESS_ISR) +#error "TIM13 ISR not defined by platform" +#endif /* !defined(STM32_TIM13_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM13 */ + +#if STM32_GPT_USE_TIM14 || defined(__DOXYGEN__) +#if !defined(STM32_TIM14_SUPPRESS_ISR) +#error "TIM14 ISR not defined by platform" +#endif /* !defined(STM32_TIM14_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM14 */ + +#if STM32_GPT_USE_TIM15 || defined(__DOXYGEN__) +#if !defined(STM32_TIM15_SUPPRESS_ISR) +#error "TIM15 ISR not defined by platform" +#endif /* !defined(STM32_TIM15_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM15 */ + +#if STM32_GPT_USE_TIM16 || defined(__DOXYGEN__) +#if !defined(STM32_TIM16_SUPPRESS_ISR) +#error "TIM16 ISR not defined by platform" +#endif /* !defined(STM32_TIM16_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM16 */ + +#if STM32_GPT_USE_TIM17 || defined(__DOXYGEN__) +#if !defined(STM32_TIM17_SUPPRESS_ISR) +#error "TIM17 ISR not defined by platform" +#endif /* !defined(STM32_TIM17_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM17 */ + +#if STM32_GPT_USE_TIM21 || defined(__DOXYGEN__) +#if !defined(STM32_TIM21_SUPPRESS_ISR) +#if !defined(STM32_TIM21_HANDLER) +#error "STM32_TIM21_HANDLER not defined" +#endif +/** + * @brief TIM21 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM21_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD21); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM21_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM21 */ + +#if STM32_GPT_USE_TIM22 || defined(__DOXYGEN__) +#if !defined(STM32_TIM22_SUPPRESS_ISR) +#if !defined(STM32_TIM22_HANDLER) +#error "STM32_TIM22_HANDLER not defined" +#endif +/** + * @brief TIM22 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM22_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD22); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM22_SUPPRESS_ISR) */ +#endif /* STM32_GPT_USE_TIM22 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level GPT driver initialization. + * + * @notapi + */ +void gpt_lld_init(void) { + +#if STM32_GPT_USE_TIM1 + /* Driver initialization.*/ + GPTD1.tim = STM32_TIM1; + gptObjectInit(&GPTD1); +#endif + +#if STM32_GPT_USE_TIM2 + /* Driver initialization.*/ + GPTD2.tim = STM32_TIM2; + gptObjectInit(&GPTD2); +#endif + +#if STM32_GPT_USE_TIM3 + /* Driver initialization.*/ + GPTD3.tim = STM32_TIM3; + gptObjectInit(&GPTD3); +#endif + +#if STM32_GPT_USE_TIM4 + /* Driver initialization.*/ + GPTD4.tim = STM32_TIM4; + gptObjectInit(&GPTD4); +#endif + +#if STM32_GPT_USE_TIM5 + /* Driver initialization.*/ + GPTD5.tim = STM32_TIM5; + gptObjectInit(&GPTD5); +#endif + +#if STM32_GPT_USE_TIM6 + /* Driver initialization.*/ + GPTD6.tim = STM32_TIM6; + gptObjectInit(&GPTD6); +#endif + +#if STM32_GPT_USE_TIM7 + /* Driver initialization.*/ + GPTD7.tim = STM32_TIM7; + gptObjectInit(&GPTD7); +#endif + +#if STM32_GPT_USE_TIM8 + /* Driver initialization.*/ + GPTD8.tim = STM32_TIM8; + gptObjectInit(&GPTD8); +#endif + +#if STM32_GPT_USE_TIM9 + /* Driver initialization.*/ + GPTD9.tim = STM32_TIM9; + gptObjectInit(&GPTD9); +#endif + +#if STM32_GPT_USE_TIM10 + /* Driver initialization.*/ + GPTD10.tim = STM32_TIM10; + gptObjectInit(&GPTD10); +#endif + +#if STM32_GPT_USE_TIM11 + /* Driver initialization.*/ + GPTD11.tim = STM32_TIM11; + gptObjectInit(&GPTD11); +#endif + +#if STM32_GPT_USE_TIM12 + /* Driver initialization.*/ + GPTD12.tim = STM32_TIM12; + gptObjectInit(&GPTD12); +#endif + +#if STM32_GPT_USE_TIM13 + /* Driver initialization.*/ + GPTD13.tim = STM32_TIM13; + gptObjectInit(&GPTD13); +#endif + +#if STM32_GPT_USE_TIM14 + /* Driver initialization.*/ + GPTD14.tim = STM32_TIM14; + gptObjectInit(&GPTD14); +#endif + +#if STM32_GPT_USE_TIM15 + /* Driver initialization.*/ + GPTD15.tim = STM32_TIM15; + gptObjectInit(&GPTD15); +#endif + +#if STM32_GPT_USE_TIM16 + /* Driver initialization.*/ + GPTD16.tim = STM32_TIM16; + gptObjectInit(&GPTD16); +#endif + +#if STM32_GPT_USE_TIM17 + /* Driver initialization.*/ + GPTD17.tim = STM32_TIM17; + gptObjectInit(&GPTD17); +#endif + +#if STM32_GPT_USE_TIM21 + /* Driver initialization.*/ + GPTD21.tim = STM32_TIM21; + gptObjectInit(&GPTD21); +#endif + +#if STM32_GPT_USE_TIM22 + /* Driver initialization.*/ + GPTD22.tim = STM32_TIM22; + gptObjectInit(&GPTD22); +#endif +} + +/** + * @brief Configures and activates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_start(GPTDriver *gptp) { + uint16_t psc; + + if (gptp->state == GPT_STOP) { + /* Clock activation.*/ +#if STM32_GPT_USE_TIM1 + if (&GPTD1 == gptp) { + rccEnableTIM1(true); + rccResetTIM1(); +#if !defined(STM32_TIM1_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_GPT_TIM1_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM1CLK) + gptp->clock = STM32_TIM1CLK; +#else + gptp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_GPT_USE_TIM2 + if (&GPTD2 == gptp) { + rccEnableTIM2(true); + rccResetTIM2(); +#if !defined(STM32_TIM2_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM2_NUMBER, STM32_GPT_TIM2_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM2CLK) + gptp->clock = STM32_TIM2CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM3 + if (&GPTD3 == gptp) { + rccEnableTIM3(true); + rccResetTIM3(); +#if !defined(STM32_TIM3_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM3_NUMBER, STM32_GPT_TIM3_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM3CLK) + gptp->clock = STM32_TIM3CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM4 + if (&GPTD4 == gptp) { + rccEnableTIM4(true); + rccResetTIM4(); +#if !defined(STM32_TIM4_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM4_NUMBER, STM32_GPT_TIM4_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM4CLK) + gptp->clock = STM32_TIM4CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM5 + if (&GPTD5 == gptp) { + rccEnableTIM5(true); + rccResetTIM5(); +#if !defined(STM32_TIM5_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM5_NUMBER, STM32_GPT_TIM5_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM5CLK) + gptp->clock = STM32_TIM5CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM6 + if (&GPTD6 == gptp) { + rccEnableTIM6(true); + rccResetTIM6(); +#if !defined(STM32_TIM6_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM6_NUMBER, STM32_GPT_TIM6_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM6CLK) + gptp->clock = STM32_TIM6CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM7 + if (&GPTD7 == gptp) { + rccEnableTIM7(true); + rccResetTIM7(); +#if !defined(STM32_TIM7_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM7_NUMBER, STM32_GPT_TIM7_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM7CLK) + gptp->clock = STM32_TIM7CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM8 + if (&GPTD8 == gptp) { + rccEnableTIM8(true); + rccResetTIM8(); +#if !defined(STM32_TIM8_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_GPT_TIM8_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM8CLK) + gptp->clock = STM32_TIM8CLK; +#else + gptp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_GPT_USE_TIM9 + if (&GPTD9 == gptp) { + rccEnableTIM9(true); + rccResetTIM9(); +#if !defined(STM32_TIM9_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM9_NUMBER, STM32_GPT_TIM9_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM9CLK) + gptp->clock = STM32_TIM9CLK; +#else + gptp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_GPT_USE_TIM10 + if (&GPTD10 == gptp) { + rccEnableTIM10(true); + rccResetTIM10(); +#if !defined(STM32_TIM10_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM10_NUMBER, STM32_GPT_TIM10_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM10CLK) + gptp->clock = STM32_TIM10CLK; +#else + gptp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_GPT_USE_TIM11 + if (&GPTD11 == gptp) { + rccEnableTIM11(true); + rccResetTIM11(); +#if !defined(STM32_TIM11_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM11_NUMBER, STM32_GPT_TIM11_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM11CLK) + gptp->clock = STM32_TIM11CLK; +#else + gptp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_GPT_USE_TIM12 + if (&GPTD12 == gptp) { + rccEnableTIM12(true); + rccResetTIM12(); +#if !defined(STM32_TIM12_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM12_NUMBER, STM32_GPT_TIM12_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM12CLK) + gptp->clock = STM32_TIM12CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM13 + if (&GPTD13 == gptp) { + rccEnableTIM13(true); + rccResetTIM13(); +#if !defined(STM32_TIM13_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM13_NUMBER, STM32_GPT_TIM13_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM13CLK) + gptp->clock = STM32_TIM13CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM14 + if (&GPTD14 == gptp) { + rccEnableTIM14(true); + rccResetTIM14(); +#if !defined(STM32_TIM14_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM14_NUMBER, STM32_GPT_TIM14_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM14CLK) + gptp->clock = STM32_TIM14CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM15 + if (&GPTD15 == gptp) { + rccEnableTIM15(true); + rccResetTIM15(); +#if defined(STM32_TIM15CLK) + gptp->clock = STM32_TIM15CLK; +#else + gptp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_GPT_USE_TIM16 + if (&GPTD16 == gptp) { + rccEnableTIM16(true); + rccResetTIM16(); +#if defined(STM32_TIM16CLK) + gptp->clock = STM32_TIM16CLK; +#else + gptp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_GPT_USE_TIM17 + if (&GPTD17 == gptp) { + rccEnableTIM17(true); + rccResetTIM17(); +#if defined(STM32_TIM17CLK) + gptp->clock = STM32_TIM17CLK; +#else + gptp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_GPT_USE_TIM21 + if (&GPTD21 == gptp) { + rccEnableTIM21(true); + rccResetTIM21(); +#if !defined(STM32_TIM21_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM21_NUMBER, STM32_GPT_TIM21_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM21CLK) + gptp->clock = STM32_TIM21CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_GPT_USE_TIM22 + if (&GPTD22 == gptp) { + rccEnableTIM22(true); + rccResetTIM22(); +#if !defined(STM32_TIM22_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM22_NUMBER, STM32_GPT_TIM22_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM22CLK) + gptp->clock = STM32_TIM22CLK; +#else + gptp->clock = STM32_TIMCLK1; +#endif + } +#endif + } + + /* Prescaler value calculation.*/ + psc = (uint16_t)((gptp->clock / gptp->config->frequency) - 1); + osalDbgAssert(((uint32_t)(psc + 1) * gptp->config->frequency) == gptp->clock, + "invalid frequency"); + + /* Timer configuration.*/ + gptp->tim->CR1 = 0; /* Initially stopped. */ + gptp->tim->CR2 = gptp->config->cr2; + gptp->tim->PSC = psc; /* Prescaler value. */ + gptp->tim->SR = 0; /* Clear pending IRQs. */ + gptp->tim->DIER = gptp->config->dier & /* DMA-related DIER bits. */ + ~STM32_TIM_DIER_IRQ_MASK; +} + +/** + * @brief Deactivates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop(GPTDriver *gptp) { + + if (gptp->state == GPT_READY) { + gptp->tim->CR1 = 0; /* Timer disabled. */ + gptp->tim->DIER = 0; /* All IRQs disabled. */ + gptp->tim->SR = 0; /* Clear pending IRQs. */ + +#if STM32_GPT_USE_TIM1 + if (&GPTD1 == gptp) { +#if !defined(STM32_TIM1_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM1_UP_NUMBER); +#endif + rccDisableTIM1(); + } +#endif + +#if STM32_GPT_USE_TIM2 + if (&GPTD2 == gptp) { +#if !defined(STM32_TIM2_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM2_NUMBER); +#endif + rccDisableTIM2(); + } +#endif + +#if STM32_GPT_USE_TIM3 + if (&GPTD3 == gptp) { +#if !defined(STM32_TIM3_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM3_NUMBER); +#endif + rccDisableTIM3(); + } +#endif + +#if STM32_GPT_USE_TIM4 + if (&GPTD4 == gptp) { +#if !defined(STM32_TIM4_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM4_NUMBER); +#endif + rccDisableTIM4(); + } +#endif + +#if STM32_GPT_USE_TIM5 + if (&GPTD5 == gptp) { +#if !defined(STM32_TIM5_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM5_NUMBER); +#endif + rccDisableTIM5(); + } +#endif + +#if STM32_GPT_USE_TIM6 + if (&GPTD6 == gptp) { +#if !defined(STM32_TIM6_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM6_NUMBER); +#endif + rccDisableTIM6(); + } +#endif + +#if STM32_GPT_USE_TIM7 + if (&GPTD7 == gptp) { +#if !defined(STM32_TIM7_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM7_NUMBER); +#endif + rccDisableTIM7(); + } +#endif + +#if STM32_GPT_USE_TIM8 + if (&GPTD8 == gptp) { +#if !defined(STM32_TIM8_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM8_UP_NUMBER); +#endif + rccDisableTIM8(); + } +#endif + +#if STM32_GPT_USE_TIM9 + if (&GPTD9 == gptp) { +#if !defined(STM32_TIM9_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM9_NUMBER); +#endif + rccDisableTIM9(); + } +#endif + +#if STM32_GPT_USE_TIM10 + if (&GPTD10 == gptp) { +#if !defined(STM32_TIM10_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM10_NUMBER); +#endif + rccDisableTIM10(); + } +#endif + +#if STM32_GPT_USE_TIM11 + if (&GPTD11 == gptp) { +#if !defined(STM32_TIM11_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM11_NUMBER); +#endif + rccDisableTIM11(); + } +#endif + +#if STM32_GPT_USE_TIM12 + if (&GPTD12 == gptp) { +#if !defined(STM32_TIM12_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM12_NUMBER); +#endif + rccDisableTIM12(); + } +#endif + +#if STM32_GPT_USE_TIM13 + if (&GPTD13 == gptp) { +#if !defined(STM32_TIM13_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM13_NUMBER); +#endif + rccDisableTIM13(); + } +#endif + +#if STM32_GPT_USE_TIM14 + if (&GPTD14 == gptp) { +#if !defined(STM32_TIM14_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM14_NUMBER); +#endif + rccDisableTIM14(); + } +#endif + +#if STM32_GPT_USE_TIM15 + if (&GPTD15 == gptp) { + rccDisableTIM15(); + } +#endif + +#if STM32_GPT_USE_TIM16 + if (&GPTD16 == gptp) { + rccDisableTIM16(); + } +#endif + +#if STM32_GPT_USE_TIM17 + if (&GPTD17 == gptp) { + rccDisableTIM17(); + } +#endif + +#if STM32_GPT_USE_TIM21 + if (&GPTD21 == gptp) { +#if !defined(STM32_TIM21_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM21_NUMBER); +#endif + rccDisableTIM21(); + } +#endif + +#if STM32_GPT_USE_TIM22 + if (&GPTD22 == gptp) { +#if !defined(STM32_TIM22_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM22_NUMBER); +#endif + rccDisableTIM22(); + } +#endif + } +} + +/** + * @brief Starts the timer in continuous mode. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval period in ticks + * + * @notapi + */ +void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) { + + gptp->tim->ARR = (uint32_t)(interval - 1U); /* Time constant. */ + gptp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */ + gptp->tim->CNT = 0; /* Reset counter. */ + + /* NOTE: After generating the UG event it takes several clock cycles before + SR bit 0 goes to 1. This is why the clearing of CNT has been inserted + before the clearing of SR, to give it some time.*/ + gptp->tim->SR = 0; /* Clear pending IRQs. */ + if (NULL != gptp->config->callback) + gptp->tim->DIER |= STM32_TIM_DIER_UIE; /* Update Event IRQ enabled.*/ + gptp->tim->CR1 = STM32_TIM_CR1_ARPE | STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN; +} + +/** + * @brief Stops the timer. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop_timer(GPTDriver *gptp) { + + gptp->tim->CR1 = 0; /* Initially stopped. */ + gptp->tim->SR = 0; /* Clear pending IRQs. */ + + /* All interrupts disabled.*/ + gptp->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK; +} + +/** + * @brief Starts the timer in one shot mode and waits for completion. + * @details This function specifically polls the timer waiting for completion + * in order to not have extra delays caused by interrupt servicing, + * this function is only recommended for short delays. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval time interval in ticks + * + * @notapi + */ +void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) { + + gptp->tim->ARR = (uint32_t)(interval - 1U); /* Time constant. */ + gptp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */ + gptp->tim->SR = 0; /* Clear pending IRQs. */ + gptp->tim->CR1 = STM32_TIM_CR1_OPM | STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN; + while (!(gptp->tim->SR & STM32_TIM_SR_UIF)) + ; + gptp->tim->SR = 0; /* Clear pending IRQs. */ +} + +/** + * @brief Shared IRQ handler. + * + * @param[in] gptp pointer to a @p GPTDriver object + * + * @notapi + */ +void gpt_lld_serve_interrupt(GPTDriver *gptp) { + uint32_t sr; + + sr = gptp->tim->SR; + sr &= gptp->tim->DIER & STM32_TIM_DIER_IRQ_MASK; + gptp->tim->SR = ~sr; + if ((sr & STM32_TIM_SR_UIF) != 0) { + _gpt_isr_invoke_cb(gptp); + } +} + +#endif /* HAL_USE_GPT */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.h new file mode 100644 index 0000000..1fbdea3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.h @@ -0,0 +1,980 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/hal_gpt_lld.h + * @brief STM32 GPT subsystem low level driver header. + * + * @addtogroup GPT + * @{ + */ + +#ifndef HAL_GPT_LLD_H +#define HAL_GPT_LLD_H + +#include "stm32_tim.h" + +#if HAL_USE_GPT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief GPTD1 driver enable switch. + * @details If set to @p TRUE the support for GPTD1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM1) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM1 FALSE +#endif + +/** + * @brief GPTD2 driver enable switch. + * @details If set to @p TRUE the support for GPTD2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM2) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM2 FALSE +#endif + +/** + * @brief GPTD3 driver enable switch. + * @details If set to @p TRUE the support for GPTD3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM3) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM3 FALSE +#endif + +/** + * @brief GPTD4 driver enable switch. + * @details If set to @p TRUE the support for GPTD4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM4) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM4 FALSE +#endif + +/** + * @brief GPTD5 driver enable switch. + * @details If set to @p TRUE the support for GPTD5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM5) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM5 FALSE +#endif + +/** + * @brief GPTD6 driver enable switch. + * @details If set to @p TRUE the support for GPTD6 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM6) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM6 FALSE +#endif + +/** + * @brief GPTD7 driver enable switch. + * @details If set to @p TRUE the support for GPTD7 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM7) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM7 FALSE +#endif + +/** + * @brief GPTD8 driver enable switch. + * @details If set to @p TRUE the support for GPTD8 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM8) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM8 FALSE +#endif + +/** + * @brief GPTD9 driver enable switch. + * @details If set to @p TRUE the support for GPTD9 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM9) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM9 FALSE +#endif + +/** + * @brief GPTD10 driver enable switch. + * @details If set to @p TRUE the support for GPTD10 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM10) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM10 FALSE +#endif + +/** + * @brief GPTD11 driver enable switch. + * @details If set to @p TRUE the support for GPTD11 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM11) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM11 FALSE +#endif + +/** + * @brief GPTD12 driver enable switch. + * @details If set to @p TRUE the support for GPTD12 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM12) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM12 FALSE +#endif + +/** + * @brief GPTD13 driver enable switch. + * @details If set to @p TRUE the support for GPTD13 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM13) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM13 FALSE +#endif + +/** + * @brief GPTD14 driver enable switch. + * @details If set to @p TRUE the support for GPTD14 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM14) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM14 FALSE +#endif + +/** + * @brief GPTD14 driver enable switch. + * @details If set to @p TRUE the support for GPTD15 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM15) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM15 FALSE +#endif + +/** + * @brief GPTD14 driver enable switch. + * @details If set to @p TRUE the support for GPTD16 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM16) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM16 FALSE +#endif + +/** + * @brief GPTD14 driver enable switch. + * @details If set to @p TRUE the support for GPTD17 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM17) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM17 FALSE +#endif + +/** + * @brief GPTD21 driver enable switch. + * @details If set to @p TRUE the support for GPTD21 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM21) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM21 FALSE +#endif + +/** + * @brief GPTD22 driver enable switch. + * @details If set to @p TRUE the support for GPTD22 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_GPT_USE_TIM22) || defined(__DOXYGEN__) +#define STM32_GPT_USE_TIM22 FALSE +#endif + +/** + * @brief GPTD1 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM1_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD2 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM2_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD3 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM3_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD4 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM4_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD5 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM5_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD6 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM6_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM6_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD7 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM7_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM7_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD8 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM8_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD9 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM9_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD10 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM10_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM10_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD11 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM11_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM11_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD12 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM12_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM12_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD13 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM13_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM13_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD14 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM14_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM14_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD15 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM15_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM15_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD16 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM16_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM16_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD17 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM17_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM17_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD21 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM21_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM21_IRQ_PRIORITY 7 +#endif + +/** + * @brief GPTD22 interrupt priority level setting. + */ +#if !defined(STM32_GPT_TIM22_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_GPT_TIM22_IRQ_PRIORITY 7 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_TIM1) +#define STM32_HAS_TIM1 FALSE +#endif + +#if !defined(STM32_HAS_TIM2) +#define STM32_HAS_TIM2 FALSE +#endif + +#if !defined(STM32_HAS_TIM3) +#define STM32_HAS_TIM3 FALSE +#endif + +#if !defined(STM32_HAS_TIM4) +#define STM32_HAS_TIM4 FALSE +#endif + +#if !defined(STM32_HAS_TIM5) +#define STM32_HAS_TIM5 FALSE +#endif + +#if !defined(STM32_HAS_TIM6) +#define STM32_HAS_TIM6 FALSE +#endif + +#if !defined(STM32_HAS_TIM7) +#define STM32_HAS_TIM7 FALSE +#endif + +#if !defined(STM32_HAS_TIM8) +#define STM32_HAS_TIM8 FALSE +#endif + +#if !defined(STM32_HAS_TIM9) +#define STM32_HAS_TIM9 FALSE +#endif + +#if !defined(STM32_HAS_TIM10) +#define STM32_HAS_TIM10 FALSE +#endif + +#if !defined(STM32_HAS_TIM11) +#define STM32_HAS_TIM11 FALSE +#endif + +#if !defined(STM32_HAS_TIM12) +#define STM32_HAS_TIM12 FALSE +#endif + +#if !defined(STM32_HAS_TIM13) +#define STM32_HAS_TIM13 FALSE +#endif + +#if !defined(STM32_HAS_TIM14) +#define STM32_HAS_TIM14 FALSE +#endif + +#if !defined(STM32_HAS_TIM15) +#define STM32_HAS_TIM15 FALSE +#endif + +#if !defined(STM32_HAS_TIM16) +#define STM32_HAS_TIM16 FALSE +#endif + +#if !defined(STM32_HAS_TIM17) +#define STM32_HAS_TIM17 FALSE +#endif + +#if !defined(STM32_HAS_TIM21) +#define STM32_HAS_TIM21 FALSE +#endif + +#if !defined(STM32_HAS_TIM22) +#define STM32_HAS_TIM22 FALSE +#endif + +#if STM32_GPT_USE_TIM1 && !STM32_HAS_TIM1 +#error "TIM1 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM2 && !STM32_HAS_TIM2 +#error "TIM2 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM3 && !STM32_HAS_TIM3 +#error "TIM3 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM4 && !STM32_HAS_TIM4 +#error "TIM4 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM5 && !STM32_HAS_TIM5 +#error "TIM5 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM6 && !STM32_HAS_TIM6 +#error "TIM6 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM7 && !STM32_HAS_TIM7 +#error "TIM7 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM8 && !STM32_HAS_TIM8 +#error "TIM8 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM9 && !STM32_HAS_TIM9 +#error "TIM9 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM10 && !STM32_HAS_TIM10 +#error "TIM10 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM11 && !STM32_HAS_TIM11 +#error "TIM11 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM12 && !STM32_HAS_TIM12 +#error "TIM12 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM13 && !STM32_HAS_TIM13 +#error "TIM13 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM14 && !STM32_HAS_TIM14 +#error "TIM14 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM15 && !STM32_HAS_TIM15 +#error "TIM15 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM16 && !STM32_HAS_TIM16 +#error "TIM16 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM17 && !STM32_HAS_TIM17 +#error "TIM17 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM21 && !STM32_HAS_TIM21 +#error "TIM21 not present in the selected device" +#endif + +#if STM32_GPT_USE_TIM22 && !STM32_HAS_TIM22 +#error "TIM22 not present in the selected device" +#endif + +#if !STM32_GPT_USE_TIM1 && !STM32_GPT_USE_TIM2 && \ + !STM32_GPT_USE_TIM3 && !STM32_GPT_USE_TIM4 && \ + !STM32_GPT_USE_TIM5 && !STM32_GPT_USE_TIM6 && \ + !STM32_GPT_USE_TIM7 && !STM32_GPT_USE_TIM8 && \ + !STM32_GPT_USE_TIM9 && !STM32_GPT_USE_TIM10 && \ + !STM32_GPT_USE_TIM11 && !STM32_GPT_USE_TIM12 && \ + !STM32_GPT_USE_TIM13 && !STM32_GPT_USE_TIM14 && \ + !STM32_GPT_USE_TIM15 && !STM32_GPT_USE_TIM16 && \ + !STM32_GPT_USE_TIM17 && \ + !STM32_GPT_USE_TIM21 && !STM32_GPT_USE_TIM22 +#error "GPT driver activated but no TIM peripheral assigned" +#endif + +/* Checks on allocation of TIMx units.*/ +#if STM32_GPT_USE_TIM1 +#if defined(STM32_TIM1_IS_USED) +#error "GPTD1 requires TIM1 but the timer is already used" +#else +#define STM32_TIM1_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM2 +#if defined(STM32_TIM2_IS_USED) +#error "GPTD2 requires TIM2 but the timer is already used" +#else +#define STM32_TIM2_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM3 +#if defined(STM32_TIM3_IS_USED) +#error "GPTD3 requires TIM3 but the timer is already used" +#else +#define STM32_TIM3_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM4 +#if defined(STM32_TIM4_IS_USED) +#error "GPTD4 requires TIM4 but the timer is already used" +#else +#define STM32_TIM4_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM5 +#if defined(STM32_TIM5_IS_USED) +#error "GPTD5 requires TIM5 but the timer is already used" +#else +#define STM32_TIM5_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM6 +#if defined(STM32_TIM6_IS_USED) +#error "GPTD6 requires TIM6 but the timer is already used" +#else +#define STM32_TIM6_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM7 +#if defined(STM32_TIM7_IS_USED) +#error "GPTD7 requires TIM7 but the timer is already used" +#else +#define STM32_TIM7_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM8 +#if defined(STM32_TIM8_IS_USED) +#error "GPTD8 requires TIM8 but the timer is already used" +#else +#define STM32_TIM8_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM9 +#if defined(STM32_TIM9_IS_USED) +#error "GPTD9 requires TIM9 but the timer is already used" +#else +#define STM32_TIM9_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM10 +#if defined(STM32_TIM10_IS_USED) +#error "GPTD10 requires TIM10 but the timer is already used" +#else +#define STM32_TIM10_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM11 +#if defined(STM32_TIM11_IS_USED) +#error "GPTD11 requires TIM11 but the timer is already used" +#else +#define STM32_TIM11_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM12 +#if defined(STM32_TIM12_IS_USED) +#error "GPTD12 requires TIM12 but the timer is already used" +#else +#define STM32_TIM12_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM13 +#if defined(STM32_TIM13_IS_USED) +#error "GPTD13 requires TIM13 but the timer is already used" +#else +#define STM32_TIM13_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM14 +#if defined(STM32_TIM14_IS_USED) +#error "GPTD14 requires TIM14 but the timer is already used" +#else +#define STM32_TIM14_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM15 +#if defined(STM32_TIM15_IS_USED) +#error "GPTD14 requires TIM15 but the timer is already used" +#else +#define STM32_TIM15_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM16 +#if defined(STM32_TIM16_IS_USED) +#error "GPTD14 requires TIM16 but the timer is already used" +#else +#define STM32_TIM16_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM17 +#if defined(STM32_TIM17_IS_USED) +#error "GPTD14 requires TIM17 but the timer is already used" +#else +#define STM32_TIM17_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM21 +#if defined(STM32_TIM21_IS_USED) +#error "GPTD21 requires TIM21 but the timer is already used" +#else +#define STM32_TIM21_IS_USED +#endif +#endif + +#if STM32_GPT_USE_TIM22 +#if defined(STM32_TIM22_IS_USED) +#error "GPTD22 requires TIM22 but the timer is already used" +#else +#define STM32_TIM22_IS_USED +#endif +#endif + +/* IRQ priority checks.*/ +#if STM32_GPT_USE_TIM1 && !defined(STM32_TIM1_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM1" +#endif + +#if STM32_GPT_USE_TIM2 && !defined(STM32_TIM2_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM2" +#endif + +#if STM32_GPT_USE_TIM3 && !defined(STM32_TIM3_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM3" +#endif + +#if STM32_GPT_USE_TIM4 && !defined(STM32_TIM_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM4" +#endif + +#if STM32_GPT_USE_TIM5 && !defined(STM32_TIM5_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM5" +#endif + +#if STM32_GPT_USE_TIM6 && !defined(STM32_TIM6_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM6_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM6" +#endif + +#if STM32_GPT_USE_TIM7 && !defined(STM32_TIM7_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM7_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM7" +#endif + +#if STM32_GPT_USE_TIM8 && !defined(STM32_TIM8_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM8_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM8" +#endif + +#if STM32_GPT_USE_TIM9 && !defined(STM32_TIM9_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM9_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM9" +#endif + +#if STM32_GPT_USE_TIM10 && !defined(STM32_TIM10_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM10_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM10" +#endif + +#if STM32_GPT_USE_TIM11 && !defined(STM32_TIM11_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM11_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM11" +#endif + +#if STM32_GPT_USE_TIM12 && !defined(STM32_TIM12_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM12_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM12" +#endif + +#if STM32_GPT_USE_TIM13 && !defined(STM32_TIM13_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM13_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM13" +#endif + +#if STM32_GPT_USE_TIM14 && !defined(STM32_TIM14_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM14_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM14" +#endif + +#if STM32_GPT_USE_TIM15 && !defined(STM32_TIM15_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM15_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM15" +#endif + +#if STM32_GPT_USE_TIM16 && !defined(STM32_TIM16_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM16_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM16" +#endif + +#if STM32_GPT_USE_TIM17 && !defined(STM32_TIM17_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM17_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM17" +#endif + +#if STM32_GPT_USE_TIM21 && !defined(STM32_TIM21_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM21_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM21" +#endif + +#if STM32_GPT_USE_TIM22 && !defined(STM32_TIM22_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM22_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM22" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief GPT frequency type. + */ +typedef uint32_t gptfreq_t; + +/** + * @brief GPT counter type. + */ +typedef uint32_t gptcnt_t; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Timer clock in Hz. + * @note The low level can use assertions in order to catch invalid + * frequency specifications. + */ + gptfreq_t frequency; + /** + * @brief Timer callback pointer. + * @note This callback is invoked on GPT counter events. + * @note This callback can be set to @p NULL but in that case the + * one-shot mode cannot be used. + */ + gptcallback_t callback; + /* End of the mandatory fields.*/ + /** + * @brief TIM CR2 register initialization data. + * @note The value of this field should normally be equal to zero. + */ + uint32_t cr2; + /** + * @brief TIM DIER register initialization data. + * @note The value of this field should normally be equal to zero. + * @note Only the DMA-related bits can be specified in this field. + */ + uint32_t dier; +} GPTConfig; + +/** + * @brief Structure representing a GPT driver. + */ +struct GPTDriver { + /** + * @brief Driver state. + */ + gptstate_t state; + /** + * @brief Current configuration data. + */ + const GPTConfig *config; +#if defined(GPT_DRIVER_EXT_FIELDS) + GPT_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Timer base clock. + */ + uint32_t clock; + /** + * @brief Pointer to the TIMx registers block. + */ + stm32_tim_t *tim; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Changes the interval of GPT peripheral. + * @details This function changes the interval of a running GPT unit. + * @pre The GPT unit must be running in continuous mode. + * @post The GPT unit interval is changed to the new value. + * @note The function has effect at the next cycle start. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @param[in] interval new cycle time in timer ticks + * + * @notapi + */ +#define gpt_lld_change_interval(gptp, interval) \ + ((gptp)->tim->ARR = (uint32_t)((interval) - 1U)) + +/** + * @brief Returns the interval of GPT peripheral. + * @pre The GPT unit must be running in continuous mode. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @return The current interval. + * + * @notapi + */ +#define gpt_lld_get_interval(gptp) ((gptcnt_t)((gptp)->tim->ARR + 1U)) + +/** + * @brief Returns the counter value of GPT peripheral. + * @pre The GPT unit must be running in continuous mode. + * @note The nature of the counter is not defined, it may count upward + * or downward, it could be continuously running or not. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @return The current counter value. + * + * @notapi + */ +#define gpt_lld_get_counter(gptp) ((gptcnt_t)(gptp)->tim->CNT) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_GPT_USE_TIM1 && !defined(__DOXYGEN__) +extern GPTDriver GPTD1; +#endif + +#if STM32_GPT_USE_TIM2 && !defined(__DOXYGEN__) +extern GPTDriver GPTD2; +#endif + +#if STM32_GPT_USE_TIM3 && !defined(__DOXYGEN__) +extern GPTDriver GPTD3; +#endif + +#if STM32_GPT_USE_TIM4 && !defined(__DOXYGEN__) +extern GPTDriver GPTD4; +#endif + +#if STM32_GPT_USE_TIM5 && !defined(__DOXYGEN__) +extern GPTDriver GPTD5; +#endif + +#if STM32_GPT_USE_TIM6 && !defined(__DOXYGEN__) +extern GPTDriver GPTD6; +#endif + +#if STM32_GPT_USE_TIM7 && !defined(__DOXYGEN__) +extern GPTDriver GPTD7; +#endif + +#if STM32_GPT_USE_TIM8 && !defined(__DOXYGEN__) +extern GPTDriver GPTD8; +#endif + +#if STM32_GPT_USE_TIM9 && !defined(__DOXYGEN__) +extern GPTDriver GPTD9; +#endif + +#if STM32_GPT_USE_TIM10 && !defined(__DOXYGEN__) +extern GPTDriver GPTD10; +#endif + +#if STM32_GPT_USE_TIM11 && !defined(__DOXYGEN__) +extern GPTDriver GPTD11; +#endif + +#if STM32_GPT_USE_TIM12 && !defined(__DOXYGEN__) +extern GPTDriver GPTD12; +#endif + +#if STM32_GPT_USE_TIM13 && !defined(__DOXYGEN__) +extern GPTDriver GPTD13; +#endif + +#if STM32_GPT_USE_TIM14 && !defined(__DOXYGEN__) +extern GPTDriver GPTD14; +#endif + +#if STM32_GPT_USE_TIM15 && !defined(__DOXYGEN__) +extern GPTDriver GPTD15; +#endif + +#if STM32_GPT_USE_TIM16 && !defined(__DOXYGEN__) +extern GPTDriver GPTD16; +#endif + +#if STM32_GPT_USE_TIM17 && !defined(__DOXYGEN__) +extern GPTDriver GPTD17; +#endif + +#if STM32_GPT_USE_TIM21 && !defined(__DOXYGEN__) +extern GPTDriver GPTD21; +#endif + +#if STM32_GPT_USE_TIM22 && !defined(__DOXYGEN__) +extern GPTDriver GPTD22; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void gpt_lld_init(void); + void gpt_lld_start(GPTDriver *gptp); + void gpt_lld_stop(GPTDriver *gptp); + void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period); + void gpt_lld_stop_timer(GPTDriver *gptp); + void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval); + void gpt_lld_serve_interrupt(GPTDriver *gptp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_GPT */ + +#endif /* HAL_GPT_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c new file mode 100644 index 0000000..e9a669d --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c @@ -0,0 +1,1135 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ +/* + Concepts and parts of this file have been contributed by Fabio Utzig and + Xo Wang. + */ + +/** + * @file TIMv1/hal_icu_lld.c + * @brief STM32 ICU subsystem low level driver header. + * + * @addtogroup ICU + * @{ + */ + +#include "hal.h" + +#if HAL_USE_ICU || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief ICUD1 driver identifier. + * @note The driver ICUD1 allocates the complex timer TIM1 when enabled. + */ +#if STM32_ICU_USE_TIM1 || defined(__DOXYGEN__) +ICUDriver ICUD1; +#endif + +/** + * @brief ICUD2 driver identifier. + * @note The driver ICUD1 allocates the timer TIM2 when enabled. + */ +#if STM32_ICU_USE_TIM2 || defined(__DOXYGEN__) +ICUDriver ICUD2; +#endif + +/** + * @brief ICUD3 driver identifier. + * @note The driver ICUD1 allocates the timer TIM3 when enabled. + */ +#if STM32_ICU_USE_TIM3 || defined(__DOXYGEN__) +ICUDriver ICUD3; +#endif + +/** + * @brief ICUD4 driver identifier. + * @note The driver ICUD4 allocates the timer TIM4 when enabled. + */ +#if STM32_ICU_USE_TIM4 || defined(__DOXYGEN__) +ICUDriver ICUD4; +#endif + +/** + * @brief ICUD5 driver identifier. + * @note The driver ICUD5 allocates the timer TIM5 when enabled. + */ +#if STM32_ICU_USE_TIM5 || defined(__DOXYGEN__) +ICUDriver ICUD5; +#endif + +/** + * @brief ICUD8 driver identifier. + * @note The driver ICUD8 allocates the timer TIM8 when enabled. + */ +#if STM32_ICU_USE_TIM8 || defined(__DOXYGEN__) +ICUDriver ICUD8; +#endif + +/** + * @brief ICUD9 driver identifier. + * @note The driver ICUD9 allocates the timer TIM9 when enabled. + */ +#if STM32_ICU_USE_TIM9 || defined(__DOXYGEN__) +ICUDriver ICUD9; +#endif + +/** + * @brief ICUD10 driver identifier. + * @note The driver ICUD10 allocates the timer TIM10 when enabled. + */ +#if STM32_ICU_USE_TIM10 || defined(__DOXYGEN__) +ICUDriver ICUD10; +#endif + +/** + * @brief ICUD11 driver identifier. + * @note The driver ICUD11 allocates the timer TIM11 when enabled. + */ +#if STM32_ICU_USE_TIM11 || defined(__DOXYGEN__) +ICUDriver ICUD11; +#endif + +/** + * @brief ICUD12 driver identifier. + * @note The driver ICUD12 allocates the timer TIM12 when enabled. + */ +#if STM32_ICU_USE_TIM12 || defined(__DOXYGEN__) +ICUDriver ICUD12; +#endif + +/** + * @brief ICUD13 driver identifier. + * @note The driver ICUD13 allocates the timer TIM13 when enabled. + */ +#if STM32_ICU_USE_TIM13 || defined(__DOXYGEN__) +ICUDriver ICUD13; +#endif + +/** + * @brief ICUD14 driver identifier. + * @note The driver ICUD14 allocates the timer TIM14 when enabled. + */ +#if STM32_ICU_USE_TIM14 || defined(__DOXYGEN__) +ICUDriver ICUD14; +#endif + +/** + * @brief ICUD15 driver identifier. + * @note The driver ICUD15 allocates the timer TIM15 when enabled. + */ +#if STM32_ICU_USE_TIM15 || defined(__DOXYGEN__) +ICUDriver ICUD15; +#endif + +/** + * @brief ICUD20 driver identifier. + * @note The driver ICUD20 allocates the timer TIM20 when enabled. + */ +#if STM32_ICU_USE_TIM20 || defined(__DOXYGEN__) +ICUDriver ICUD20; +#endif + +/** + * @brief ICUD21 driver identifier. + * @note The driver ICUD21 allocates the timer TIM21 when enabled. + */ +#if STM32_ICU_USE_TIM21 || defined(__DOXYGEN__) +ICUDriver ICUD21; +#endif + +/** + * @brief ICUD22 driver identifier. + * @note The driver ICUD22 allocates the timer TIM22 when enabled. + */ +#if STM32_ICU_USE_TIM22 || defined(__DOXYGEN__) +ICUDriver ICUD22; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static bool icu_lld_wait_edge(ICUDriver *icup) { + uint32_t sr; + bool result; + + /* Polled mode so re-enabling the interrupts while the operation is + performed.*/ + osalSysUnlock(); + + /* Polling the right bit depending on the input channel.*/ + if (icup->config->channel == ICU_CHANNEL_1) { + /* Waiting for an edge.*/ + while (((sr = icup->tim->SR) & + (STM32_TIM_SR_CC1IF | STM32_TIM_SR_UIF)) == 0) + ; + } + else { + /* Waiting for an edge.*/ + while (((sr = icup->tim->SR) & + (STM32_TIM_SR_CC2IF | STM32_TIM_SR_UIF)) == 0) + ; + } + + /* Edge or overflow?*/ + result = (sr & STM32_TIM_SR_UIF) != 0 ? true : false; + + /* Done, disabling interrupts again.*/ + osalSysLock(); + + /* Resetting all flags.*/ + icup->tim->SR &= ~(STM32_TIM_SR_CC1IF | + STM32_TIM_SR_CC2IF | + STM32_TIM_SR_UIF); + + return result; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_ICU_USE_TIM1 || defined(__DOXYGEN__) +#if !defined(STM32_TIM1_SUPPRESS_ISR) +#if !defined(STM32_TIM1_UP_HANDLER) +#error "STM32_TIM1_UP_HANDLER not defined" +#endif +/** + * @brief TIM1 compare interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + icu_lld_serve_interrupt(&ICUD1); + + OSAL_IRQ_EPILOGUE(); +} + +#if !defined(STM32_TIM1_CC_HANDLER) +#error "STM32_TIM1_CC_HANDLER not defined" +#endif +/** + * @brief TIM1 compare interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + icu_lld_serve_interrupt(&ICUD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM1_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM1 */ + +#if STM32_ICU_USE_TIM2 || defined(__DOXYGEN__) +#if !defined(STM32_TIM2_SUPPRESS_ISR) +#if !defined(STM32_TIM2_HANDLER) +#error "STM32_TIM2_HANDLER not defined" +#endif +/** + * @brief TIM2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + icu_lld_serve_interrupt(&ICUD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM2_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM2 */ + +#if STM32_ICU_USE_TIM3 || defined(__DOXYGEN__) +#if !defined(STM32_TIM3_SUPPRESS_ISR) +#if !defined(STM32_TIM3_HANDLER) +#error "STM32_TIM3_HANDLER not defined" +#endif +/** + * @brief TIM3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + icu_lld_serve_interrupt(&ICUD3); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM3_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM3 */ + +#if STM32_ICU_USE_TIM4 || defined(__DOXYGEN__) +#if !defined(STM32_TIM4_SUPPRESS_ISR) +#if !defined(STM32_TIM4_HANDLER) +#error "STM32_TIM4_HANDLER not defined" +#endif +/** + * @brief TIM4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + icu_lld_serve_interrupt(&ICUD4); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM4_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM4 */ + +#if STM32_ICU_USE_TIM5 || defined(__DOXYGEN__) +#if !defined(STM32_TIM5_SUPPRESS_ISR) +#if !defined(STM32_TIM5_HANDLER) +#error "STM32_TIM5_HANDLER not defined" +#endif +/** + * @brief TIM5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + icu_lld_serve_interrupt(&ICUD5); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM5_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM5 */ + +#if STM32_ICU_USE_TIM8 || defined(__DOXYGEN__) +#if !defined(STM32_TIM8_SUPPRESS_ISR) +#if !defined(STM32_TIM8_UP_HANDLER) +#error "STM32_TIM8_UP_HANDLER not defined" +#endif +/** + * @brief TIM8 compare interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + icu_lld_serve_interrupt(&ICUD8); + + OSAL_IRQ_EPILOGUE(); +} + +#if !defined(STM32_TIM8_CC_HANDLER) +#error "STM32_TIM8_CC_HANDLER not defined" +#endif +/** + * @brief TIM8 compare interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + icu_lld_serve_interrupt(&ICUD8); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM8_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM8 */ + +#if STM32_ICU_USE_TIM9 || defined(__DOXYGEN__) +#if !defined(STM32_TIM9_SUPPRESS_ISR) +#error "TIM9 ISR not defined by platform" +#endif /* !defined(STM32_TIM9_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM9 */ + +#if STM32_ICU_USE_TIM10 || defined(__DOXYGEN__) +#if !defined(STM32_TIM10_SUPPRESS_ISR) +#error "TIM10 ISR not defined by platform" +#endif /* !defined(STM32_TIM10_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM10 */ + +#if STM32_ICU_USE_TIM11 || defined(__DOXYGEN__) +#if !defined(STM32_TIM11_SUPPRESS_ISR) +#error "TIM11 ISR not defined by platform" +#endif /* !defined(STM32_TIM11_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM11 */ + +#if STM32_ICU_USE_TIM12 || defined(__DOXYGEN__) +#if !defined(STM32_TIM12_SUPPRESS_ISR) +#error "TIM12 ISR not defined by platform" +#endif /* !defined(STM32_TIM12_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM12 */ + +#if STM32_ICU_USE_TIM13 || defined(__DOXYGEN__) +#if !defined(STM32_TIM13_SUPPRESS_ISR) +#error "TIM13 ISR not defined by platform" +#endif /* !defined(STM32_TIM13_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM13 */ + +#if STM32_ICU_USE_TIM14 || defined(__DOXYGEN__) +#if !defined(STM32_TIM14_SUPPRESS_ISR) +#error "TIM14 ISR not defined by platform" +#endif /* !defined(STM32_TIM14_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM14 */ + +#if STM32_ICU_USE_TIM15 || defined(__DOXYGEN__) +#if !defined(STM32_TIM15_SUPPRESS_ISR) +#error "TIM15 ISR not defined by platform" +#endif /* !defined(STM32_TIM15_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM15 */ + +#if STM32_ICU_USE_TIM20 || defined(__DOXYGEN__) +#if !defined(STM32_TIM20_SUPPRESS_ISR) +#error "TIM20 ISR not defined by platform" +#endif /* !defined(STM32_TIM20_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM20 */ + +#if STM32_ICU_USE_TIM21 || defined(__DOXYGEN__) +#if !defined(STM32_TIM21_SUPPRESS_ISR) +#error "TIM21 ISR not defined by platform" +#endif /* !defined(STM32_TIM21_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM21 */ + +#if STM32_ICU_USE_TIM22 || defined(__DOXYGEN__) +#if !defined(STM32_TIM22_SUPPRESS_ISR) +#error "TIM22 ISR not defined by platform" +#endif /* !defined(STM32_TIM22_SUPPRESS_ISR) */ +#endif /* STM32_ICU_USE_TIM22 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ICU driver initialization. + * + * @notapi + */ +void icu_lld_init(void) { + +#if STM32_ICU_USE_TIM1 + /* Driver initialization.*/ + icuObjectInit(&ICUD1); + ICUD1.tim = STM32_TIM1; +#endif + +#if STM32_ICU_USE_TIM2 + /* Driver initialization.*/ + icuObjectInit(&ICUD2); + ICUD2.tim = STM32_TIM2; +#endif + +#if STM32_ICU_USE_TIM3 + /* Driver initialization.*/ + icuObjectInit(&ICUD3); + ICUD3.tim = STM32_TIM3; +#endif + +#if STM32_ICU_USE_TIM4 + /* Driver initialization.*/ + icuObjectInit(&ICUD4); + ICUD4.tim = STM32_TIM4; +#endif + +#if STM32_ICU_USE_TIM5 + /* Driver initialization.*/ + icuObjectInit(&ICUD5); + ICUD5.tim = STM32_TIM5; +#endif + +#if STM32_ICU_USE_TIM8 + /* Driver initialization.*/ + icuObjectInit(&ICUD8); + ICUD8.tim = STM32_TIM8; +#endif + +#if STM32_ICU_USE_TIM9 + /* Driver initialization.*/ + icuObjectInit(&ICUD9); + ICUD9.tim = STM32_TIM9; +#endif + +#if STM32_ICU_USE_TIM10 + /* Driver initialization.*/ + icuObjectInit(&ICUD10); + ICUD10.tim = STM32_TIM10; +#endif + +#if STM32_ICU_USE_TIM11 + /* Driver initialization.*/ + icuObjectInit(&ICUD11); + ICUD11.tim = STM32_TIM11; +#endif + +#if STM32_ICU_USE_TIM12 + /* Driver initialization.*/ + icuObjectInit(&ICUD12); + ICUD12.tim = STM32_TIM12; +#endif + +#if STM32_ICU_USE_TIM13 + /* Driver initialization.*/ + icuObjectInit(&ICUD13); + ICUD13.tim = STM32_TIM13; +#endif + +#if STM32_ICU_USE_TIM14 + /* Driver initialization.*/ + icuObjectInit(&ICUD14); + ICUD14.tim = STM32_TIM14; +#endif + +#if STM32_ICU_USE_TIM15 + /* Driver initialization.*/ + icuObjectInit(&ICUD15); + ICUD15.tim = STM32_TIM15; +#endif + +#if STM32_ICU_USE_TIM20 + /* Driver initialization.*/ + icuObjectInit(&ICUD20); + ICUD20.tim = STM32_TIM20; +#endif + +#if STM32_ICU_USE_TIM21 + /* Driver initialization.*/ + icuObjectInit(&ICUD21); + ICUD21.tim = STM32_TIM21; +#endif + +#if STM32_ICU_USE_TIM22 + /* Driver initialization.*/ + icuObjectInit(&ICUD22); + ICUD22.tim = STM32_TIM22; +#endif +} + +/** + * @brief Configures and activates the ICU peripheral. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @notapi + */ +void icu_lld_start(ICUDriver *icup) { + uint32_t psc; + + osalDbgAssert((icup->config->channel == ICU_CHANNEL_1) || + (icup->config->channel == ICU_CHANNEL_2), + "invalid input"); + + if (icup->state == ICU_STOP) { + /* Clock activation and timer reset.*/ +#if STM32_ICU_USE_TIM1 + if (&ICUD1 == icup) { + rccEnableTIM1(true); + rccResetTIM1(); +#if !defined(STM32_TIM1_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_ICU_TIM1_IRQ_PRIORITY); + nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_ICU_TIM1_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM1CLK) + icup->clock = STM32_TIM1CLK; +#else + icup->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_ICU_USE_TIM2 + if (&ICUD2 == icup) { + rccEnableTIM2(true); + rccResetTIM2(); +#if !defined(STM32_TIM2_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM2_NUMBER, STM32_ICU_TIM2_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM2CLK) + icup->clock = STM32_TIM2CLK; +#else + icup->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_ICU_USE_TIM3 + if (&ICUD3 == icup) { + rccEnableTIM3(true); + rccResetTIM3(); +#if !defined(STM32_TIM3_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM3_NUMBER, STM32_ICU_TIM3_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM3CLK) + icup->clock = STM32_TIM3CLK; +#else + icup->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_ICU_USE_TIM4 + if (&ICUD4 == icup) { + rccEnableTIM4(true); + rccResetTIM4(); +#if !defined(STM32_TIM4_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM4_NUMBER, STM32_ICU_TIM4_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM4CLK) + icup->clock = STM32_TIM4CLK; +#else + icup->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_ICU_USE_TIM5 + if (&ICUD5 == icup) { + rccEnableTIM5(true); + rccResetTIM5(); +#if !defined(STM32_TIM5_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM5_NUMBER, STM32_ICU_TIM5_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM5CLK) + icup->clock = STM32_TIM5CLK; +#else + icup->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_ICU_USE_TIM8 + if (&ICUD8 == icup) { + rccEnableTIM8(true); + rccResetTIM8(); +#if !defined(STM32_TIM8_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_ICU_TIM8_IRQ_PRIORITY); + nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_ICU_TIM8_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM8CLK) + icup->clock = STM32_TIM8CLK; +#else + icup->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_ICU_USE_TIM9 + if (&ICUD9 == icup) { + rccEnableTIM9(true); + rccResetTIM9(); +#if defined(STM32_TIM9CLK) + icup->clock = STM32_TIM9CLK; +#else + icup->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_ICU_USE_TIM10 + if (&ICUD10 == icup) { + rccEnableTIM10(true); + rccResetTIM10(); +#if defined(STM32_TIM10CLK) + icup->clock = STM32_TIM10CLK; +#else + icup->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_ICU_USE_TIM11 + if (&ICUD11 == icup) { + rccEnableTIM11(true); + rccResetTIM11(); +#if defined(STM32_TIM11CLK) + icup->clock = STM32_TIM11CLK; +#else + icup->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_ICU_USE_TIM12 + if (&ICUD12 == icup) { + rccEnableTIM12(true); + rccResetTIM12(); +#if defined(STM32_TIM12CLK) + icup->clock = STM32_TIM12CLK; +#else + icup->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_ICU_USE_TIM13 + if (&ICUD13 == icup) { + rccEnableTIM13(true); + rccResetTIM13(); +#if defined(STM32_TIM13CLK) + icup->clock = STM32_TIM13CLK; +#else + icup->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_ICU_USE_TIM14 + if (&ICUD14 == icup) { + rccEnableTIM14(true); + rccResetTIM14(); +#if defined(STM32_TIM14CLK) + icup->clock = STM32_TIM14CLK; +#else + icup->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_ICU_USE_TIM15 + if (&ICUD15 == icup) { + rccEnableTIM15(true); + rccResetTIM15(); +#if defined(STM32_TIM15CLK) + icup->clock = STM32_TIM15CLK; +#else + icup->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_ICU_USE_TIM20 + if (&ICUD20 == icup) { + rccEnableTIM20(true); + rccResetTIM20(); +#if defined(STM32_TIM20CLK) + icup->clock = STM32_TIM20CLK; +#else + icup->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_ICU_USE_TIM21 + if (&ICUD21 == icup) { + rccEnableTIM21(true); + rccResetTIM21(); +#if defined(STM32_TIM21CLK) + icup->clock = STM32_TIM21CLK; +#else + icup->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_ICU_USE_TIM22 + if (&ICUD22 == icup) { + rccEnableTIM22(true); + rccResetTIM22(); +#if defined(STM32_TIM22CLK) + icup->clock = STM32_TIM22CLK; +#else + icup->clock = STM32_TIMCLK1; +#endif + } +#endif + } + else { + /* Driver re-configuration scenario, it must be stopped first.*/ + icup->tim->CR1 = 0; /* Timer disabled. */ + icup->tim->CCR[0] = 0; /* Comparator 1 disabled. */ + icup->tim->CCR[1] = 0; /* Comparator 2 disabled. */ + icup->tim->CNT = 0; /* Counter reset to zero. */ + } + + /* Timer configuration.*/ + icup->tim->SR = 0; /* Clear eventual pending IRQs. */ + icup->tim->DIER = icup->config->dier & /* DMA-related DIER settings. */ + ~STM32_TIM_DIER_IRQ_MASK; + psc = (icup->clock / icup->config->frequency) - 1; + osalDbgAssert((psc <= 0xFFFF) && + ((psc + 1) * icup->config->frequency) == icup->clock, + "invalid frequency"); + icup->tim->PSC = psc; + if (icup->config->arr == 0U) { + /* Zero is an invalid value and is turned in maximum value, also for + legacy configurations compatibility.*/ + icup->tim->ARR = 0xFFFFFFFFU; + } + else { + icup->tim->ARR = icup->config->arr; + } + + if (icup->config->channel == ICU_CHANNEL_1) { + /* Selected input 1. + CCMR1_CC1S = 01 = CH1 Input on TI1. + CCMR1_CC2S = 10 = CH2 Input on TI1.*/ + icup->tim->CCMR1 = STM32_TIM_CCMR1_CC1S(1) | STM32_TIM_CCMR1_CC2S(2); + + /* SMCR_TS = 101, input is TI1FP1. + SMCR_SMS = 100, reset on rising edge.*/ + icup->tim->SMCR = STM32_TIM_SMCR_TS(5) | STM32_TIM_SMCR_SMS(4); + + /* The CCER settings depend on the selected trigger mode. + ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge. + ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/ + if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH) + icup->tim->CCER = STM32_TIM_CCER_CC1E | + STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P; + else + icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P | + STM32_TIM_CCER_CC2E; + + /* Direct pointers to the capture registers in order to make reading + data faster from within callbacks.*/ + icup->wccrp = &icup->tim->CCR[1]; + icup->pccrp = &icup->tim->CCR[0]; + } + else { + /* Selected input 2. + CCMR1_CC1S = 10 = CH1 Input on TI2. + CCMR1_CC2S = 01 = CH2 Input on TI2.*/ + icup->tim->CCMR1 = STM32_TIM_CCMR1_CC1S(2) | STM32_TIM_CCMR1_CC2S(1); + + /* SMCR_TS = 110, input is TI2FP2. + SMCR_SMS = 100, reset on rising edge.*/ + icup->tim->SMCR = STM32_TIM_SMCR_TS(6) | STM32_TIM_SMCR_SMS(4); + + /* The CCER settings depend on the selected trigger mode. + ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge. + ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/ + if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH) + icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P | + STM32_TIM_CCER_CC2E; + else + icup->tim->CCER = STM32_TIM_CCER_CC1E | + STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P; + + /* Direct pointers to the capture registers in order to make reading + data faster from within callbacks.*/ + icup->wccrp = &icup->tim->CCR[0]; + icup->pccrp = &icup->tim->CCR[1]; + } +} + +/** + * @brief Deactivates the ICU peripheral. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @notapi + */ +void icu_lld_stop(ICUDriver *icup) { + + if (icup->state == ICU_READY) { + /* Clock deactivation.*/ + icup->tim->CR1 = 0; /* Timer disabled. */ + icup->tim->DIER = 0; /* All IRQs disabled. */ + icup->tim->SR = 0; /* Clear eventual pending IRQs. */ + +#if STM32_ICU_USE_TIM1 + if (&ICUD1 == icup) { +#if !defined(STM32_TIM1_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM1_UP_NUMBER); + nvicDisableVector(STM32_TIM1_CC_NUMBER); +#endif + rccDisableTIM1(); + } +#endif + +#if STM32_ICU_USE_TIM2 + if (&ICUD2 == icup) { +#if !defined(STM32_TIM2_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM2_NUMBER); +#endif + rccDisableTIM2(); + } +#endif + +#if STM32_ICU_USE_TIM3 + if (&ICUD3 == icup) { +#if !defined(STM32_TIM3_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM3_NUMBER); +#endif + rccDisableTIM3(); + } +#endif + +#if STM32_ICU_USE_TIM4 + if (&ICUD4 == icup) { +#if !defined(STM32_TIM4_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM4_NUMBER); +#endif + rccDisableTIM4(); + } +#endif + +#if STM32_ICU_USE_TIM5 + if (&ICUD5 == icup) { +#if !defined(STM32_TIM5_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM5_NUMBER); +#endif + rccDisableTIM5(); + } +#endif + +#if STM32_ICU_USE_TIM8 + if (&ICUD8 == icup) { +#if !defined(STM32_TIM8_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM8_UP_NUMBER); + nvicDisableVector(STM32_TIM8_CC_NUMBER); +#endif + rccDisableTIM8(); + } +#endif + +#if STM32_ICU_USE_TIM9 + if (&ICUD9 == icup) { + rccDisableTIM9(); + } +#endif + +#if STM32_ICU_USE_TIM10 + if (&ICUD10 == icup) { + rccDisableTIM10(); + } +#endif + +#if STM32_ICU_USE_TIM11 + if (&ICUD11 == icup) { + rccDisableTIM11(); + } +#endif + +#if STM32_ICU_USE_TIM12 + if (&ICUD12 == icup) { + rccDisableTIM12(); + } +#endif + +#if STM32_ICU_USE_TIM13 + if (&ICUD13 == icup) { + rccDisableTIM13(); + } +#endif + +#if STM32_ICU_USE_TIM14 + if (&ICUD14 == icup) { + rccDisableTIM14(); + } +#endif + +#if STM32_ICU_USE_TIM15 + if (&ICUD15 == icup) { + rccDisableTIM15(); + } +#endif + +#if STM32_ICU_USE_TIM20 + if (&ICUD20 == icup) { + rccDisableTIM20(); + } +#endif + +#if STM32_ICU_USE_TIM21 + if (&ICUD21 == icup) { + rccDisableTIM21(); + } +#endif + +#if STM32_ICU_USE_TIM22 + if (&ICUD22 == icup) { + rccDisableTIM22(); + } +#endif + } +} + +/** + * @brief Starts the input capture. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @notapi + */ +void icu_lld_start_capture(ICUDriver *icup) { + + /* Triggering an UG and clearing the IRQ status.*/ + icup->tim->EGR |= STM32_TIM_EGR_UG; + icup->tim->SR = 0; + + /* Timer is started.*/ + icup->tim->CR1 = STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN; +} + +/** + * @brief Waits for a completed capture. + * @note The operation is performed in polled mode. + * @note In order to use this function notifications must be disabled. + * + * @param[in] icup pointer to the @p ICUDriver object + * @return The capture status. + * @retval false if the capture is successful. + * @retval true if a timer overflow occurred. + * + * @notapi + */ +bool icu_lld_wait_capture(ICUDriver *icup) { + + /* If the driver is still in the ICU_WAITING state then we need to wait + for the first activation edge.*/ + if (icup->state == ICU_WAITING) + if (icu_lld_wait_edge(icup)) + return true; + + /* This edge marks the availability of a capture result.*/ + return icu_lld_wait_edge(icup); +} + +/** + * @brief Stops the input capture. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @notapi + */ +void icu_lld_stop_capture(ICUDriver *icup) { + + /* Timer stopped.*/ + icup->tim->CR1 = 0; + + /* All interrupts disabled.*/ + icup->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK; +} + +/** + * @brief Enables notifications. + * @pre The ICU unit must have been activated using @p icuStart() and the + * capture started using @p icuStartCapture(). + * @note If the notification is already enabled then the call has no effect. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @notapi + */ +void icu_lld_enable_notifications(ICUDriver *icup) { + uint32_t dier = icup->tim->DIER; + + /* If interrupts were already enabled then the operation is skipped. + This is done in order to avoid clearing the SR and risk losing + pending interrupts.*/ + if ((dier & STM32_TIM_DIER_IRQ_MASK) == 0) { + /* Previously triggered IRQs are ignored, status cleared.*/ + icup->tim->SR = 0; + + if (icup->config->channel == ICU_CHANNEL_1) { + /* Enabling periodic callback on CC1.*/ + dier |= STM32_TIM_DIER_CC1IE; + + /* Optionally enabling width callback on CC2.*/ + if (icup->config->width_cb != NULL) + dier |= STM32_TIM_DIER_CC2IE; + } + else { + /* Enabling periodic callback on CC2.*/ + dier |= STM32_TIM_DIER_CC2IE; + + /* Optionally enabling width callback on CC1.*/ + if (icup->config->width_cb != NULL) + dier |= STM32_TIM_DIER_CC1IE; + } + + /* If an overflow callback is defined then also the overflow callback + is enabled.*/ + if (icup->config->overflow_cb != NULL) + dier |= STM32_TIM_DIER_UIE; + + /* One single atomic write.*/ + icup->tim->DIER = dier; + } +} + +/** + * @brief Disables notifications. + * @pre The ICU unit must have been activated using @p icuStart() and the + * capture started using @p icuStartCapture(). + * @note If the notification is already disabled then the call has no effect. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @notapi + */ +void icu_lld_disable_notifications(ICUDriver *icup) { + + /* All interrupts disabled.*/ + icup->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK; +} + +/** + * @brief Shared IRQ handler. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @notapi + */ +void icu_lld_serve_interrupt(ICUDriver *icup) { + uint32_t sr; + + sr = icup->tim->SR; + sr &= icup->tim->DIER & STM32_TIM_DIER_IRQ_MASK; + icup->tim->SR = ~sr; + if (icup->config->channel == ICU_CHANNEL_1) { + if ((sr & STM32_TIM_SR_CC2IF) != 0) + _icu_isr_invoke_width_cb(icup); + if ((sr & STM32_TIM_SR_CC1IF) != 0) + _icu_isr_invoke_period_cb(icup); + } + else { + if ((sr & STM32_TIM_SR_CC1IF) != 0) + _icu_isr_invoke_width_cb(icup); + if ((sr & STM32_TIM_SR_CC2IF) != 0) + _icu_isr_invoke_period_cb(icup); + } + if ((sr & STM32_TIM_SR_UIF) != 0) + _icu_isr_invoke_overflow_cb(icup); +} + +#endif /* HAL_USE_ICU */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.h new file mode 100644 index 0000000..38c1907 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.h @@ -0,0 +1,893 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/hal_icu_lld.h + * @brief STM32 ICU subsystem low level driver header. + * + * @addtogroup ICU + * @{ + */ + +#ifndef HAL_ICU_LLD_H +#define HAL_ICU_LLD_H + +#if HAL_USE_ICU || defined(__DOXYGEN__) + +#include "stm32_tim.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief ICUD1 driver enable switch. + * @details If set to @p TRUE the support for ICUD1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM1) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM1 FALSE +#endif + +/** + * @brief ICUD2 driver enable switch. + * @details If set to @p TRUE the support for ICUD2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM2) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM2 FALSE +#endif + +/** + * @brief ICUD3 driver enable switch. + * @details If set to @p TRUE the support for ICUD3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM3) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM3 FALSE +#endif + +/** + * @brief ICUD4 driver enable switch. + * @details If set to @p TRUE the support for ICUD4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM4) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM4 FALSE +#endif + +/** + * @brief ICUD5 driver enable switch. + * @details If set to @p TRUE the support for ICUD5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM5) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM5 FALSE +#endif + +/** + * @brief ICUD8 driver enable switch. + * @details If set to @p TRUE the support for ICUD8 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM8) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM8 FALSE +#endif + +/** + * @brief ICUD9 driver enable switch. + * @details If set to @p TRUE the support for ICUD9 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM9) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM9 FALSE +#endif + +/** + * @brief ICUD10 driver enable switch. + * @details If set to @p TRUE the support for ICUD10 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM10) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM10 FALSE +#endif + +/** + * @brief ICUD11 driver enable switch. + * @details If set to @p TRUE the support for ICUD11 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM11) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM11 FALSE +#endif + +/** + * @brief ICUD12 driver enable switch. + * @details If set to @p TRUE the support for ICUD12 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM12) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM12 FALSE +#endif + +/** + * @brief ICUD13 driver enable switch. + * @details If set to @p TRUE the support for ICUD13 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM13) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM13 FALSE +#endif + +/** + * @brief ICUD14 driver enable switch. + * @details If set to @p TRUE the support for ICUD14 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM14) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM14 FALSE +#endif + +/** + * @brief ICUD15 driver enable switch. + * @details If set to @p TRUE the support for ICUD15 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM15) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM15 FALSE +#endif + +/** + * @brief ICUD20 driver enable switch. + * @details If set to @p TRUE the support for ICUD20 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM20) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM20 FALSE +#endif + +/** + * @brief ICUD21 driver enable switch. + * @details If set to @p TRUE the support for ICUD21 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM21) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM21 FALSE +#endif + +/** + * @brief ICUD22 driver enable switch. + * @details If set to @p TRUE the support for ICUD22 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ICU_USE_TIM22) || defined(__DOXYGEN__) +#define STM32_ICU_USE_TIM22 FALSE +#endif + +/** + * @brief ICUD1 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM1_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD2 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM2_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD3 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM3_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD4 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM4_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD5 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM5_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD8 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM8_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD9 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM9_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD10 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM10_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM10_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD11 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM11_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM11_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD12 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM12_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM12_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD13 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM13_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM13_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD14 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM14_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM14_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD15 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM15_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM15_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD20 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM20_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM20_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD21 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM21_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM21_IRQ_PRIORITY 7 +#endif + +/** + * @brief ICUD22 interrupt priority level setting. + */ +#if !defined(STM32_ICU_TIM22_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ICU_TIM22_IRQ_PRIORITY 7 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_TIM1) +#define STM32_HAS_TIM1 FALSE +#endif + +#if !defined(STM32_HAS_TIM2) +#define STM32_HAS_TIM2 FALSE +#endif + +#if !defined(STM32_HAS_TIM3) +#define STM32_HAS_TIM3 FALSE +#endif + +#if !defined(STM32_HAS_TIM4) +#define STM32_HAS_TIM4 FALSE +#endif + +#if !defined(STM32_HAS_TIM5) +#define STM32_HAS_TIM5 FALSE +#endif + +#if !defined(STM32_HAS_TIM8) +#define STM32_HAS_TIM8 FALSE +#endif + +#if !defined(STM32_HAS_TIM9) +#define STM32_HAS_TIM9 FALSE +#endif + +#if !defined(STM32_HAS_TIM10) +#define STM32_HAS_TIM10 FALSE +#endif + +#if !defined(STM32_HAS_TIM11) +#define STM32_HAS_TIM11 FALSE +#endif + +#if !defined(STM32_HAS_TIM12) +#define STM32_HAS_TIM12 FALSE +#endif + +#if !defined(STM32_HAS_TIM13) +#define STM32_HAS_TIM13 FALSE +#endif + +#if !defined(STM32_HAS_TIM14) +#define STM32_HAS_TIM14 FALSE +#endif + +#if !defined(STM32_HAS_TIM15) +#define STM32_HAS_TIM15 FALSE +#endif + +#if !defined(STM32_HAS_TIM20) +#define STM32_HAS_TIM20 FALSE +#endif + +#if !defined(STM32_HAS_TIM21) +#define STM32_HAS_TIM21 FALSE +#endif + +#if !defined(STM32_HAS_TIM22) +#define STM32_HAS_TIM22 FALSE +#endif + +#if STM32_ICU_USE_TIM1 && !STM32_HAS_TIM1 +#error "TIM1 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM2 && !STM32_HAS_TIM2 +#error "TIM2 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM3 && !STM32_HAS_TIM3 +#error "TIM3 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM4 && !STM32_HAS_TIM4 +#error "TIM4 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM5 && !STM32_HAS_TIM5 +#error "TIM5 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM8 && !STM32_HAS_TIM8 +#error "TIM8 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM9 && !STM32_HAS_TIM9 +#error "TIM9 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM10 && !STM32_HAS_TIM10 +#error "TIM10 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM11 && !STM32_HAS_TIM11 +#error "TIM11 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM12 && !STM32_HAS_TIM12 +#error "TIM12 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM13 && !STM32_HAS_TIM13 +#error "TIM13 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM14 && !STM32_HAS_TIM14 +#error "TIM14 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM15 && !STM32_HAS_TIM15 +#error "TIM15 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM20 && !STM32_HAS_TIM20 +#error "TIM20 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM21 && !STM32_HAS_TIM21 +#error "TIM21 not present in the selected device" +#endif + +#if STM32_ICU_USE_TIM22 && !STM32_HAS_TIM22 +#error "TIM22 not present in the selected device" +#endif + +#if !STM32_ICU_USE_TIM1 && !STM32_ICU_USE_TIM2 && \ + !STM32_ICU_USE_TIM3 && !STM32_ICU_USE_TIM4 && \ + !STM32_ICU_USE_TIM5 && !STM32_ICU_USE_TIM8 && \ + !STM32_ICU_USE_TIM9 && !STM32_ICU_USE_TIM10 && \ + !STM32_ICU_USE_TIM11 && !STM32_ICU_USE_TIM12 && \ + !STM32_ICU_USE_TIM13 && !STM32_ICU_USE_TIM14 && \ + !STM32_ICU_USE_TIM15 && !STM32_ICU_USE_TIM20 && \ + !STM32_ICU_USE_TIM21 && !STM32_ICU_USE_TIM22 +#error "ICU driver activated but no TIM peripheral assigned" +#endif + +/* Checks on allocation of TIMx units.*/ +#if STM32_ICU_USE_TIM1 +#if defined(STM32_TIM1_IS_USED) +#error "ICUD1 requires TIM1 but the timer is already used" +#else +#define STM32_TIM1_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM2 +#if defined(STM32_TIM2_IS_USED) +#error "ICUD2 requires TIM2 but the timer is already used" +#else +#define STM32_TIM2_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM3 +#if defined(STM32_TIM3_IS_USED) +#error "ICUD3 requires TIM3 but the timer is already used" +#else +#define STM32_TIM3_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM4 +#if defined(STM32_TIM4_IS_USED) +#error "ICUD4 requires TIM4 but the timer is already used" +#else +#define STM32_TIM4_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM5 +#if defined(STM32_TIM5_IS_USED) +#error "ICUD5 requires TIM5 but the timer is already used" +#else +#define STM32_TIM5_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM8 +#if defined(STM32_TIM8_IS_USED) +#error "ICUD8 requires TIM8 but the timer is already used" +#else +#define STM32_TIM8_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM9 +#if defined(STM32_TIM9_IS_USED) +#error "ICUD9 requires TIM9 but the timer is already used" +#else +#define STM32_TIM9_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM10 +#if defined(STM32_TIM10_IS_USED) +#error "ICUD10 requires TIM10 but the timer is already used" +#else +#define STM32_TIM10_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM11 +#if defined(STM32_TIM11_IS_USED) +#error "ICUD11 requires TIM11 but the timer is already used" +#else +#define STM32_TIM11_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM12 +#if defined(STM32_TIM12_IS_USED) +#error "ICUD12 requires TIM12 but the timer is already used" +#else +#define STM32_TIM12_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM13 +#if defined(STM32_TIM13_IS_USED) +#error "ICUD13 requires TIM13 but the timer is already used" +#else +#define STM32_TIM13_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM14 +#if defined(STM32_TIM14_IS_USED) +#error "ICUD14 requires TIM14 but the timer is already used" +#else +#define STM32_TIM14_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM15 +#if defined(STM32_TIM15_IS_USED) +#error "ICUD15 requires TIM15 but the timer is already used" +#else +#define STM32_TIM15_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM20 +#if defined(STM32_TIM20_IS_USED) +#error "ICUD20 requires TIM20 but the timer is already used" +#else +#define STM32_TIM20_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM21 +#if defined(STM32_TIM21_IS_USED) +#error "ICUD21 requires TIM21 but the timer is already used" +#else +#define STM32_TIM21_IS_USED +#endif +#endif + +#if STM32_ICU_USE_TIM22 +#if defined(STM32_TIM22_IS_USED) +#error "ICUD22 requires TIM22 but the timer is already used" +#else +#define STM32_TIM22_IS_USED +#endif +#endif + +/* IRQ priority checks.*/ +#if STM32_ICU_USE_TIM1 && !defined(STM32_TIM1_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM1" +#endif + +#if STM32_ICU_USE_TIM2 && !defined(STM32_TIM2_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM2" +#endif + +#if STM32_ICU_USE_TIM3 && !defined(STM32_TIM3_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM3" +#endif + +#if STM32_ICU_USE_TIM4 && !defined(STM32_TIM4_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM4" +#endif + +#if STM32_ICU_USE_TIM5 && !defined(STM32_TIM5_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM5" +#endif + +#if STM32_ICU_USE_TIM8 && !defined(STM32_TIM8_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM8_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM8" +#endif + +#if STM32_ICU_USE_TIM9 && !defined(STM32_TIM9_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM9_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM9" +#endif + +#if STM32_ICU_USE_TIM10 && !defined(STM32_TIM10_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM10_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM10" +#endif + +#if STM32_ICU_USE_TIM11 && !defined(STM32_TIM11_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM11_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM11" +#endif + +#if STM32_ICU_USE_TIM12 && !defined(STM32_TIM12_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM12_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM12" +#endif + +#if STM32_ICU_USE_TIM13 && !defined(STM32_TIM13_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM13_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM13" +#endif + +#if STM32_ICU_USE_TIM14 && !defined(STM32_TIM14_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM14_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM14" +#endif + +#if STM32_ICU_USE_TIM15 && !defined(STM32_TIM15_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM15_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM15" +#endif + +#if STM32_ICU_USE_TIM20 && !defined(STM32_TIM20_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM20_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM20" +#endif + +#if STM32_ICU_USE_TIM21 && !defined(STM32_TIM21_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM21_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM21" +#endif + +#if STM32_ICU_USE_TIM22 && !defined(STM32_TIM22_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM22_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM22" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief ICU driver mode. + */ +typedef enum { + ICU_INPUT_ACTIVE_HIGH = 0, /**< Trigger on rising edge. */ + ICU_INPUT_ACTIVE_LOW = 1, /**< Trigger on falling edge. */ +} icumode_t; + +/** + * @brief ICU frequency type. + */ +typedef uint32_t icufreq_t; + +/** + * @brief ICU channel type. + */ +typedef enum { + ICU_CHANNEL_1 = 0, /**< Use TIMxCH1. */ + ICU_CHANNEL_2 = 1, /**< Use TIMxCH2. */ +} icuchannel_t; + +/** + * @brief ICU counter type. + */ +typedef uint32_t icucnt_t; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Driver mode. + */ + icumode_t mode; + /** + * @brief Timer clock in Hz. + * @note The low level can use assertions in order to catch invalid + * frequency specifications. + */ + icufreq_t frequency; + /** + * @brief Callback for pulse width measurement. + */ + icucallback_t width_cb; + /** + * @brief Callback for cycle period measurement. + */ + icucallback_t period_cb; + /** + * @brief Callback for timer overflow. + */ + icucallback_t overflow_cb; + /* End of the mandatory fields.*/ + /** + * @brief Timer input channel to be used. + * @note Only inputs TIMx 1 and 2 are supported. + */ + icuchannel_t channel; + /** + * @brief TIM DIER register initialization data. + * @note The value of this field should normally be equal to zero. + * @note Only the DMA-related bits can be specified in this field. + */ + uint32_t dier; + /** + * @brief TIM ARR register initialization data. + * @note The value of this field should normally be equal to 0xFFFFFFFFU. + */ + uint32_t arr; +} ICUConfig; + +/** + * @brief Structure representing an ICU driver. + */ +struct ICUDriver { + /** + * @brief Driver state. + */ + icustate_t state; + /** + * @brief Current configuration data. + */ + const ICUConfig *config; +#if defined(ICU_DRIVER_EXT_FIELDS) + ICU_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Timer base clock. + */ + uint32_t clock; + /** + * @brief Pointer to the TIMx registers block. + */ + stm32_tim_t *tim; + /** + * @brief CCR register used for width capture. + */ + volatile uint32_t *wccrp; + /** + * @brief CCR register used for period capture. + */ + volatile uint32_t *pccrp; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Returns the width of the latest pulse. + * @details The pulse width is defined as number of ticks between the start + * edge and the stop edge. + * + * @param[in] icup pointer to the @p ICUDriver object + * @return The number of ticks. + * + * @notapi + */ +#define icu_lld_get_width(icup) (*((icup)->wccrp) + 1) + +/** + * @brief Returns the width of the latest cycle. + * @details The cycle width is defined as number of ticks between a start + * edge and the next start edge. + * + * @param[in] icup pointer to the @p ICUDriver object + * @return The number of ticks. + * + * @notapi + */ +#define icu_lld_get_period(icup) (*((icup)->pccrp) + 1) + +/** + * @brief Check on notifications status. + * + * @param[in] icup pointer to the @p ICUDriver object + * @return The notifications status. + * @retval false if notifications are not enabled. + * @retval true if notifications are enabled. + * + * @notapi + */ +#define icu_lld_are_notifications_enabled(icup) \ + (bool)(((icup)->tim->DIER & STM32_TIM_DIER_IRQ_MASK) != 0) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_ICU_USE_TIM1 && !defined(__DOXYGEN__) +extern ICUDriver ICUD1; +#endif + +#if STM32_ICU_USE_TIM2 && !defined(__DOXYGEN__) +extern ICUDriver ICUD2; +#endif + +#if STM32_ICU_USE_TIM3 && !defined(__DOXYGEN__) +extern ICUDriver ICUD3; +#endif + +#if STM32_ICU_USE_TIM4 && !defined(__DOXYGEN__) +extern ICUDriver ICUD4; +#endif + +#if STM32_ICU_USE_TIM5 && !defined(__DOXYGEN__) +extern ICUDriver ICUD5; +#endif + +#if STM32_ICU_USE_TIM8 && !defined(__DOXYGEN__) +extern ICUDriver ICUD8; +#endif + +#if STM32_ICU_USE_TIM9 && !defined(__DOXYGEN__) +extern ICUDriver ICUD9; +#endif + +#if STM32_ICU_USE_TIM10 && !defined(__DOXYGEN__) +extern ICUDriver ICUD10; +#endif + +#if STM32_ICU_USE_TIM11 && !defined(__DOXYGEN__) +extern ICUDriver ICUD11; +#endif + +#if STM32_ICU_USE_TIM12 && !defined(__DOXYGEN__) +extern ICUDriver ICUD12; +#endif + +#if STM32_ICU_USE_TIM13 && !defined(__DOXYGEN__) +extern ICUDriver ICUD13; +#endif + +#if STM32_ICU_USE_TIM14 && !defined(__DOXYGEN__) +extern ICUDriver ICUD14; +#endif + +#if STM32_ICU_USE_TIM15 && !defined(__DOXYGEN__) +extern ICUDriver ICUD15; +#endif + +#if STM32_ICU_USE_TIM20 && !defined(__DOXYGEN__) +extern ICUDriver ICUD20; +#endif + +#if STM32_ICU_USE_TIM21 && !defined(__DOXYGEN__) +extern ICUDriver ICUD21; +#endif + +#if STM32_ICU_USE_TIM22 && !defined(__DOXYGEN__) +extern ICUDriver ICUD22; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void icu_lld_init(void); + void icu_lld_start(ICUDriver *icup); + void icu_lld_stop(ICUDriver *icup); + void icu_lld_start_capture(ICUDriver *icup); + bool icu_lld_wait_capture(ICUDriver *icup); + void icu_lld_stop_capture(ICUDriver *icup); + void icu_lld_enable_notifications(ICUDriver *icup); + void icu_lld_disable_notifications(ICUDriver *icup); + void icu_lld_serve_interrupt(ICUDriver *icup); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_ICU */ + +#endif /* HAL_ICU_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c new file mode 100644 index 0000000..eb6bebc --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c @@ -0,0 +1,1302 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/hal_pwm_lld.c + * @brief STM32 PWM subsystem low level driver header. + * + * @addtogroup PWM + * @{ + */ + +#include "hal.h" + +#if HAL_USE_PWM || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief PWMD1 driver identifier. + * @note The driver PWMD1 allocates the complex timer TIM1 when enabled. + */ +#if STM32_PWM_USE_TIM1 || defined(__DOXYGEN__) +PWMDriver PWMD1; +#endif + +/** + * @brief PWMD2 driver identifier. + * @note The driver PWMD2 allocates the timer TIM2 when enabled. + */ +#if STM32_PWM_USE_TIM2 || defined(__DOXYGEN__) +PWMDriver PWMD2; +#endif + +/** + * @brief PWMD3 driver identifier. + * @note The driver PWMD3 allocates the timer TIM3 when enabled. + */ +#if STM32_PWM_USE_TIM3 || defined(__DOXYGEN__) +PWMDriver PWMD3; +#endif + +/** + * @brief PWMD4 driver identifier. + * @note The driver PWMD4 allocates the timer TIM4 when enabled. + */ +#if STM32_PWM_USE_TIM4 || defined(__DOXYGEN__) +PWMDriver PWMD4; +#endif + +/** + * @brief PWMD5 driver identifier. + * @note The driver PWMD5 allocates the timer TIM5 when enabled. + */ +#if STM32_PWM_USE_TIM5 || defined(__DOXYGEN__) +PWMDriver PWMD5; +#endif + +/** + * @brief PWMD8 driver identifier. + * @note The driver PWMD8 allocates the timer TIM8 when enabled. + */ +#if STM32_PWM_USE_TIM8 || defined(__DOXYGEN__) +PWMDriver PWMD8; +#endif + +/** + * @brief PWMD9 driver identifier. + * @note The driver PWMD9 allocates the timer TIM9 when enabled. + */ +#if STM32_PWM_USE_TIM9 || defined(__DOXYGEN__) +PWMDriver PWMD9; +#endif + +/** + * @brief PWMD10 driver identifier. + * @note The driver PWMD10 allocates the timer TIM10 when enabled. + */ +#if STM32_PWM_USE_TIM10 || defined(__DOXYGEN__) +PWMDriver PWMD10; +#endif + +/** + * @brief PWMD11 driver identifier. + * @note The driver PWMD11 allocates the timer TIM11 when enabled. + */ +#if STM32_PWM_USE_TIM11 || defined(__DOXYGEN__) +PWMDriver PWMD11; +#endif + +/** + * @brief PWMD12 driver identifier. + * @note The driver PWMD12 allocates the timer TIM12 when enabled. + */ +#if STM32_PWM_USE_TIM12 || defined(__DOXYGEN__) +PWMDriver PWMD12; +#endif + +/** + * @brief PWMD13 driver identifier. + * @note The driver PWMD13 allocates the timer TIM13 when enabled. + */ +#if STM32_PWM_USE_TIM13 || defined(__DOXYGEN__) +PWMDriver PWMD13; +#endif + +/** + * @brief PWMD14 driver identifier. + * @note The driver PWMD14 allocates the timer TIM14 when enabled. + */ +#if STM32_PWM_USE_TIM14 || defined(__DOXYGEN__) +PWMDriver PWMD14; +#endif + +/** + * @brief PWMD15 driver identifier. + * @note The driver PWMD15 allocates the timer TIM15 when enabled. + */ +#if STM32_PWM_USE_TIM15 || defined(__DOXYGEN__) +PWMDriver PWMD15; +#endif + +/** + * @brief PWMD16 driver identifier. + * @note The driver PWMD16 allocates the timer TIM16 when enabled. + */ +#if STM32_PWM_USE_TIM16 || defined(__DOXYGEN__) +PWMDriver PWMD16; +#endif + +/** + * @brief PWMD17 driver identifier. + * @note The driver PWMD17 allocates the timer TIM17 when enabled. + */ +#if STM32_PWM_USE_TIM17 || defined(__DOXYGEN__) +PWMDriver PWMD17; +#endif + +/** + * @brief PWMD20 driver identifier. + * @note The driver PWMD20 allocates the timer TIM20 when enabled. + */ +#if STM32_PWM_USE_TIM20 || defined(__DOXYGEN__) +PWMDriver PWMD20; +#endif + +/** + * @brief PWMD21 driver identifier. + * @note The driver PWMD21 allocates the timer TIM21 when enabled. + */ +#if STM32_PWM_USE_TIM21 || defined(__DOXYGEN__) +PWMDriver PWMD21; +#endif + +/** + * @brief PWMD22 driver identifier. + * @note The driver PWMD22 allocates the timer TIM22 when enabled. + */ +#if STM32_PWM_USE_TIM22 || defined(__DOXYGEN__) +PWMDriver PWMD22; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_PWM_USE_TIM1 || defined(__DOXYGEN__) +#if !defined(STM32_TIM1_SUPPRESS_ISR) +#if !defined(STM32_TIM1_UP_HANDLER) +#error "STM32_TIM1_UP_HANDLER not defined" +#endif +/** + * @brief TIM1 update interrupt handler. + * @note It is assumed that this interrupt is only activated if the callback + * pointer is not equal to @p NULL in order to not perform an extra + * check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + pwm_lld_serve_interrupt(&PWMD1); + + OSAL_IRQ_EPILOGUE(); +} + +#if !defined(STM32_TIM1_CC_HANDLER) +#error "STM32_TIM1_CC_HANDLER not defined" +#endif +/** + * @brief TIM1 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + pwm_lld_serve_interrupt(&PWMD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM1_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM1 */ + +#if STM32_PWM_USE_TIM2 || defined(__DOXYGEN__) +#if !defined(STM32_TIM2_SUPPRESS_ISR) +#if !defined(STM32_TIM2_HANDLER) +#error "STM32_TIM2_HANDLER not defined" +#endif +/** + * @brief TIM2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + pwm_lld_serve_interrupt(&PWMD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM2_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM2 */ + +#if STM32_PWM_USE_TIM3 || defined(__DOXYGEN__) +#if !defined(STM32_TIM3_SUPPRESS_ISR) +#if !defined(STM32_TIM3_HANDLER) +#error "STM32_TIM3_HANDLER not defined" +#endif +/** + * @brief TIM3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + pwm_lld_serve_interrupt(&PWMD3); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM3_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM3 */ + +#if STM32_PWM_USE_TIM4 || defined(__DOXYGEN__) +#if !defined(STM32_TIM4_SUPPRESS_ISR) +#if !defined(STM32_TIM4_HANDLER) +#error "STM32_TIM4_HANDLER not defined" +#endif +/** + * @brief TIM4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + pwm_lld_serve_interrupt(&PWMD4); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM4_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM4 */ + +#if STM32_PWM_USE_TIM5 || defined(__DOXYGEN__) +#if !defined(STM32_TIM5_SUPPRESS_ISR) +#if !defined(STM32_TIM5_HANDLER) +#error "STM32_TIM5_HANDLER not defined" +#endif +/** + * @brief TIM5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + pwm_lld_serve_interrupt(&PWMD5); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM5_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM5 */ + +#if STM32_PWM_USE_TIM8 || defined(__DOXYGEN__) +#if !defined(STM32_TIM8_SUPPRESS_ISR) +#if !defined(STM32_TIM8_UP_HANDLER) +#error "STM32_TIM8_UP_HANDLER not defined" +#endif +/** + * @brief TIM8 update interrupt handler. + * @note It is assumed that this interrupt is only activated if the callback + * pointer is not equal to @p NULL in order to not perform an extra + * check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + pwm_lld_serve_interrupt(&PWMD8); + + OSAL_IRQ_EPILOGUE(); +} + +#if !defined(STM32_TIM8_CC_HANDLER) +#error "STM32_TIM8_CC_HANDLER not defined" +#endif +/** + * @brief TIM8 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + pwm_lld_serve_interrupt(&PWMD8); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_TIM8_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM8 */ + +#if STM32_PWM_USE_TIM9 || defined(__DOXYGEN__) +#if !defined(STM32_TIM9_SUPPRESS_ISR) +#error "TIM9 ISR not defined by platform" +#endif /* !defined(STM32_TIM9_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM9 */ + +#if STM32_PWM_USE_TIM10 || defined(__DOXYGEN__) +#if !defined(STM32_TIM10_SUPPRESS_ISR) +#error "TIM10 ISR not defined by platform" +#endif /* !defined(STM32_TIM10_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM10 */ + +#if STM32_PWM_USE_TIM11 || defined(__DOXYGEN__) +#if !defined(STM32_TIM11_SUPPRESS_ISR) +#error "TIM11 ISR not defined by platform" +#endif /* !defined(STM32_TIM11_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM11 */ + +#if STM32_PWM_USE_TIM12 || defined(__DOXYGEN__) +#if !defined(STM32_TIM12_SUPPRESS_ISR) +#error "TIM12 ISR not defined by platform" +#endif /* !defined(STM32_TIM12_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM12 */ + +#if STM32_PWM_USE_TIM13 || defined(__DOXYGEN__) +#if !defined(STM32_TIM13_SUPPRESS_ISR) +#error "TIM13 ISR not defined by platform" +#endif /* !defined(STM32_TIM13_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM13 */ + +#if STM32_PWM_USE_TIM14 || defined(__DOXYGEN__) +#if !defined(STM32_TIM14_SUPPRESS_ISR) +#error "TIM14 ISR not defined by platform" +#endif /* !defined(STM32_TIM14_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM14 */ + +#if STM32_PWM_USE_TIM15 || defined(__DOXYGEN__) +#if !defined(STM32_TIM15_SUPPRESS_ISR) +#error "TIM15 ISR not defined by platform" +#endif /* !defined(STM32_TIM15_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM15 */ + +#if STM32_PWM_USE_TIM16 || defined(__DOXYGEN__) +#if !defined(STM32_TIM16_SUPPRESS_ISR) +#error "TIM16 ISR not defined by platform" +#endif /* !defined(STM32_TIM16_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM16 */ + +#if STM32_PWM_USE_TIM17 || defined(__DOXYGEN__) +#if !defined(STM32_TIM17_SUPPRESS_ISR) +#error "TIM17 ISR not defined by platform" +#endif /* !defined(STM32_TIM17_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM17 */ + +#if STM32_PWM_USE_TIM20 || defined(__DOXYGEN__) +#if !defined(STM32_TIM20_SUPPRESS_ISR) +#error "TIM20 ISR not defined by platform" +#endif /* !defined(STM32_TIM20_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM20 */ + +#if STM32_PWM_USE_TIM21 || defined(__DOXYGEN__) +#if !defined(STM32_TIM21_SUPPRESS_ISR) +#error "TIM21 ISR not defined by platform" +#endif /* !defined(STM32_TIM21_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM21 */ + +#if STM32_PWM_USE_TIM22 || defined(__DOXYGEN__) +#if !defined(STM32_TIM22_SUPPRESS_ISR) +#error "TIM22 ISR not defined by platform" +#endif /* !defined(STM32_TIM22_SUPPRESS_ISR) */ +#endif /* STM32_PWM_USE_TIM22 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level PWM driver initialization. + * + * @notapi + */ +void pwm_lld_init(void) { + +#if STM32_PWM_USE_TIM1 + /* Driver initialization.*/ + pwmObjectInit(&PWMD1); + PWMD1.channels = STM32_TIM1_CHANNELS; + PWMD1.tim = STM32_TIM1; +#endif + +#if STM32_PWM_USE_TIM2 + /* Driver initialization.*/ + pwmObjectInit(&PWMD2); + PWMD2.channels = STM32_TIM2_CHANNELS; + PWMD2.tim = STM32_TIM2; +#endif + +#if STM32_PWM_USE_TIM3 + /* Driver initialization.*/ + pwmObjectInit(&PWMD3); + PWMD3.channels = STM32_TIM3_CHANNELS; + PWMD3.tim = STM32_TIM3; +#endif + +#if STM32_PWM_USE_TIM4 + /* Driver initialization.*/ + pwmObjectInit(&PWMD4); + PWMD4.channels = STM32_TIM4_CHANNELS; + PWMD4.tim = STM32_TIM4; +#endif + +#if STM32_PWM_USE_TIM5 + /* Driver initialization.*/ + pwmObjectInit(&PWMD5); + PWMD5.channels = STM32_TIM5_CHANNELS; + PWMD5.tim = STM32_TIM5; +#endif + +#if STM32_PWM_USE_TIM8 + /* Driver initialization.*/ + pwmObjectInit(&PWMD8); + PWMD8.channels = STM32_TIM8_CHANNELS; + PWMD8.tim = STM32_TIM8; +#endif + +#if STM32_PWM_USE_TIM9 + /* Driver initialization.*/ + pwmObjectInit(&PWMD9); + PWMD9.channels = STM32_TIM9_CHANNELS; + PWMD9.tim = STM32_TIM9; +#endif + +#if STM32_PWM_USE_TIM10 + /* Driver initialization.*/ + pwmObjectInit(&PWMD10); + PWMD10.channels = STM32_TIM10_CHANNELS; + PWMD10.tim = STM32_TIM10; +#endif + +#if STM32_PWM_USE_TIM11 + /* Driver initialization.*/ + pwmObjectInit(&PWMD11); + PWMD11.channels = STM32_TIM11_CHANNELS; + PWMD11.tim = STM32_TIM11; +#endif + +#if STM32_PWM_USE_TIM12 + /* Driver initialization.*/ + pwmObjectInit(&PWMD12); + PWMD12.channels = STM32_TIM12_CHANNELS; + PWMD12.tim = STM32_TIM12; +#endif + +#if STM32_PWM_USE_TIM13 + /* Driver initialization.*/ + pwmObjectInit(&PWMD13); + PWMD13.channels = STM32_TIM13_CHANNELS; + PWMD13.tim = STM32_TIM13; +#endif + +#if STM32_PWM_USE_TIM14 + /* Driver initialization.*/ + pwmObjectInit(&PWMD14); + PWMD14.channels = STM32_TIM14_CHANNELS; + PWMD14.tim = STM32_TIM14; +#endif + +#if STM32_PWM_USE_TIM15 + /* Driver initialization.*/ + pwmObjectInit(&PWMD15); + PWMD15.channels = STM32_TIM15_CHANNELS; + PWMD15.tim = STM32_TIM15; +#endif + +#if STM32_PWM_USE_TIM16 + /* Driver initialization.*/ + pwmObjectInit(&PWMD16); + PWMD16.channels = STM32_TIM16_CHANNELS; + PWMD16.tim = STM32_TIM16; +#endif + +#if STM32_PWM_USE_TIM17 + /* Driver initialization.*/ + pwmObjectInit(&PWMD17); + PWMD17.channels = STM32_TIM17_CHANNELS; + PWMD17.tim = STM32_TIM17; +#endif + +#if STM32_PWM_USE_TIM20 + /* Driver initialization.*/ + pwmObjectInit(&PWMD20); + PWMD20.channels = STM32_TIM20_CHANNELS; + PWMD20.tim = STM32_TIM20; +#endif + +#if STM32_PWM_USE_TIM21 + /* Driver initialization.*/ + pwmObjectInit(&PWMD21); + PWMD21.channels = STM32_TIM21_CHANNELS; + PWMD21.tim = STM32_TIM21; +#endif + +#if STM32_PWM_USE_TIM22 + /* Driver initialization.*/ + pwmObjectInit(&PWMD22); + PWMD22.channels = STM32_TIM22_CHANNELS; + PWMD22.tim = STM32_TIM22; +#endif +} + +/** + * @brief Configures and activates the PWM peripheral. + * @note Starting a driver that is already in the @p PWM_READY state + * disables all the active channels. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @notapi + */ +void pwm_lld_start(PWMDriver *pwmp) { + uint32_t psc; + uint32_t ccer; + + if (pwmp->state == PWM_STOP) { + /* Clock activation and timer reset.*/ +#if STM32_PWM_USE_TIM1 + if (&PWMD1 == pwmp) { + rccEnableTIM1(true); + rccResetTIM1(); +#if !defined(STM32_TIM1_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_PWM_TIM1_IRQ_PRIORITY); + nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_PWM_TIM1_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM1CLK) + pwmp->clock = STM32_TIM1CLK; +#else + pwmp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_PWM_USE_TIM2 + if (&PWMD2 == pwmp) { + rccEnableTIM2(true); + rccResetTIM2(); +#if !defined(STM32_TIM2_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM2_NUMBER, STM32_PWM_TIM2_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM2CLK) + pwmp->clock = STM32_TIM2CLK; +#else + pwmp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_PWM_USE_TIM3 + if (&PWMD3 == pwmp) { + rccEnableTIM3(true); + rccResetTIM3(); +#if !defined(STM32_TIM3_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM3_NUMBER, STM32_PWM_TIM3_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM3CLK) + pwmp->clock = STM32_TIM3CLK; +#else + pwmp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_PWM_USE_TIM4 + if (&PWMD4 == pwmp) { + rccEnableTIM4(true); + rccResetTIM4(); +#if !defined(STM32_TIM4_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM4_NUMBER, STM32_PWM_TIM4_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM4CLK) + pwmp->clock = STM32_TIM4CLK; +#else + pwmp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_PWM_USE_TIM5 + if (&PWMD5 == pwmp) { + rccEnableTIM5(true); + rccResetTIM5(); +#if !defined(STM32_TIM5_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM5_NUMBER, STM32_PWM_TIM5_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM5CLK) + pwmp->clock = STM32_TIM5CLK; +#else + pwmp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_PWM_USE_TIM8 + if (&PWMD8 == pwmp) { + rccEnableTIM8(true); + rccResetTIM8(); +#if !defined(STM32_TIM8_SUPPRESS_ISR) + nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_PWM_TIM8_IRQ_PRIORITY); + nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_PWM_TIM8_IRQ_PRIORITY); +#endif +#if defined(STM32_TIM8CLK) + pwmp->clock = STM32_TIM8CLK; +#else + pwmp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_PWM_USE_TIM9 + if (&PWMD9 == pwmp) { + rccEnableTIM9(true); + rccResetTIM9(); +#if defined(STM32_TIM9CLK) + pwmp->clock = STM32_TIM9CLK; +#else + pwmp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_PWM_USE_TIM10 + if (&PWMD10 == pwmp) { + rccEnableTIM10(true); + rccResetTIM10(); +#if defined(STM32_TIM10CLK) + pwmp->clock = STM32_TIM10CLK; +#else + pwmp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_PWM_USE_TIM11 + if (&PWMD11 == pwmp) { + rccEnableTIM11(true); + rccResetTIM11(); +#if defined(STM32_TIM11CLK) + pwmp->clock = STM32_TIM11CLK; +#else + pwmp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_PWM_USE_TIM12 + if (&PWMD12 == pwmp) { + rccEnableTIM12(true); + rccResetTIM12(); +#if defined(STM32_TIM12CLK) + pwmp->clock = STM32_TIM12CLK; +#else + pwmp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_PWM_USE_TIM13 + if (&PWMD13 == pwmp) { + rccEnableTIM13(true); + rccResetTIM13(); +#if defined(STM32_TIM13CLK) + pwmp->clock = STM32_TIM13CLK; +#else + pwmp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_PWM_USE_TIM14 + if (&PWMD14 == pwmp) { + rccEnableTIM14(true); + rccResetTIM14(); +#if defined(STM32_TIM14CLK) + pwmp->clock = STM32_TIM14CLK; +#else + pwmp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_PWM_USE_TIM15 + if (&PWMD15 == pwmp) { + rccEnableTIM15(true); + rccResetTIM15(); +#if defined(STM32_TIM15CLK) + pwmp->clock = STM32_TIM15CLK; +#else + pwmp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_PWM_USE_TIM16 + if (&PWMD16 == pwmp) { + rccEnableTIM16(true); + rccResetTIM16(); +#if defined(STM32_TIM16CLK) + pwmp->clock = STM32_TIM16CLK; +#else + pwmp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_PWM_USE_TIM17 + if (&PWMD17 == pwmp) { + rccEnableTIM17(true); + rccResetTIM17(); +#if defined(STM32_TIM17CLK) + pwmp->clock = STM32_TIM17CLK; +#else + pwmp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_PWM_USE_TIM20 + if (&PWMD20 == pwmp) { + rccEnableTIM20(true); + rccResetTIM20(); +#if defined(STM32_TIM20CLK) + pwmp->clock = STM32_TIM20CLK; +#else + pwmp->clock = STM32_TIMCLK2; +#endif + } +#endif + +#if STM32_PWM_USE_TIM21 + if (&PWMD21 == pwmp) { + rccEnableTIM21(true); + rccResetTIM21(); +#if defined(STM32_TIM21CLK) + pwmp->clock = STM32_TIM21CLK; +#else + pwmp->clock = STM32_TIMCLK1; +#endif + } +#endif + +#if STM32_PWM_USE_TIM22 + if (&PWMD22 == pwmp) { + rccEnableTIM22(true); + rccResetTIM22(); +#if defined(STM32_TIM22CLK) + pwmp->clock = STM32_TIM22CLK; +#else + pwmp->clock = STM32_TIMCLK1; +#endif + } +#endif + + /* All channels configured in PWM1 mode with preload enabled and will + stay that way until the driver is stopped.*/ + pwmp->tim->CCMR1 = STM32_TIM_CCMR1_OC1M(6) | STM32_TIM_CCMR1_OC1PE | + STM32_TIM_CCMR1_OC2M(6) | STM32_TIM_CCMR1_OC2PE; + pwmp->tim->CCMR2 = STM32_TIM_CCMR2_OC3M(6) | STM32_TIM_CCMR2_OC3PE | + STM32_TIM_CCMR2_OC4M(6) | STM32_TIM_CCMR2_OC4PE; +#if STM32_TIM_MAX_CHANNELS > 4 + pwmp->tim->CCMR3 = STM32_TIM_CCMR3_OC5M(6) | STM32_TIM_CCMR3_OC5PE | + STM32_TIM_CCMR3_OC6M(6) | STM32_TIM_CCMR3_OC6PE; +#endif + } + else { + /* Driver re-configuration scenario, it must be stopped first.*/ + pwmp->tim->CR1 = 0; /* Timer disabled. */ + pwmp->tim->CCR[0] = 0; /* Comparator 1 disabled. */ + pwmp->tim->CCR[1] = 0; /* Comparator 2 disabled. */ + pwmp->tim->CCR[2] = 0; /* Comparator 3 disabled. */ + pwmp->tim->CCR[3] = 0; /* Comparator 4 disabled. */ +#if STM32_TIM_MAX_CHANNELS > 4 + if (pwmp->channels > 4) { + pwmp->tim->CCXR[0] = 0; /* Comparator 5 disabled. */ + pwmp->tim->CCXR[1] = 0; /* Comparator 6 disabled. */ + } +#endif + pwmp->tim->CNT = 0; /* Counter reset to zero. */ + } + + /* Timer configuration.*/ + psc = (pwmp->clock / pwmp->config->frequency) - 1; + osalDbgAssert((psc <= 0xFFFF) && + ((psc + 1) * pwmp->config->frequency) == pwmp->clock, + "invalid frequency"); + pwmp->tim->PSC = psc; + pwmp->tim->ARR = pwmp->period - 1; + pwmp->tim->CR2 = pwmp->config->cr2; + + /* Output enables and polarities setup.*/ + ccer = 0; + switch (pwmp->config->channels[0].mode & PWM_OUTPUT_MASK) { + case PWM_OUTPUT_ACTIVE_LOW: + ccer |= STM32_TIM_CCER_CC1P; + /* Falls through.*/ + case PWM_OUTPUT_ACTIVE_HIGH: + ccer |= STM32_TIM_CCER_CC1E; + /* Falls through.*/ + default: + ; + } + switch (pwmp->config->channels[1].mode & PWM_OUTPUT_MASK) { + case PWM_OUTPUT_ACTIVE_LOW: + ccer |= STM32_TIM_CCER_CC2P; + /* Falls through.*/ + case PWM_OUTPUT_ACTIVE_HIGH: + ccer |= STM32_TIM_CCER_CC2E; + /* Falls through.*/ + default: + ; + } + switch (pwmp->config->channels[2].mode & PWM_OUTPUT_MASK) { + case PWM_OUTPUT_ACTIVE_LOW: + ccer |= STM32_TIM_CCER_CC3P; + /* Falls through.*/ + case PWM_OUTPUT_ACTIVE_HIGH: + ccer |= STM32_TIM_CCER_CC3E; + /* Falls through.*/ + default: + ; + } + switch (pwmp->config->channels[3].mode & PWM_OUTPUT_MASK) { + case PWM_OUTPUT_ACTIVE_LOW: + ccer |= STM32_TIM_CCER_CC4P; + /* Falls through.*/ + case PWM_OUTPUT_ACTIVE_HIGH: + ccer |= STM32_TIM_CCER_CC4E; + /* Falls through.*/ + default: + ; + } +#if STM32_PWM_USE_ADVANCED +#if STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 && !STM32_PWM_USE_TIM20 + if (&PWMD1 == pwmp) { +#endif +#if !STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 && !STM32_PWM_USE_TIM20 + if (&PWMD8 == pwmp) { +#endif +#if STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 && !STM32_PWM_USE_TIM20 + if ((&PWMD1 == pwmp) || (&PWMD8 == pwmp)) { +#endif +#if !STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 && STM32_PWM_USE_TIM20 + if (&PWMD20 == pwmp) { +#endif +#if STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 && STM32_PWM_USE_TIM20 + if ((&PWMD1 == pwmp) || (&PWMD20 == pwmp)) { +#endif +#if !STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 && STM32_PWM_USE_TIM20 + if ((&PWMD8 == pwmp) || (&PWMD20 == pwmp)) { +#endif +#if STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 && STM32_PWM_USE_TIM20 + if ((&PWMD1 == pwmp) || (&PWMD8 == pwmp) || (&PWMD20 == pwmp)) { +#endif + switch (pwmp->config->channels[0].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { + case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: + ccer |= STM32_TIM_CCER_CC1NP; + /* Falls through.*/ + case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: + ccer |= STM32_TIM_CCER_CC1NE; + /* Falls through.*/ + default: + ; + } + switch (pwmp->config->channels[1].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { + case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: + ccer |= STM32_TIM_CCER_CC2NP; + /* Falls through.*/ + case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: + ccer |= STM32_TIM_CCER_CC2NE; + /* Falls through.*/ + default: + ; + } + switch (pwmp->config->channels[2].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { + case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: + ccer |= STM32_TIM_CCER_CC3NP; + /* Falls through.*/ + case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: + ccer |= STM32_TIM_CCER_CC3NE; + /* Falls through.*/ + default: + ; + } + switch (pwmp->config->channels[3].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { + case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: + ccer |= STM32_TIM_CCER_CC4NP; + /* Falls through.*/ + case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: + ccer |= STM32_TIM_CCER_CC4NE; + /* Falls through.*/ + default: + ; + } + } +#endif /* STM32_PWM_USE_ADVANCED*/ + + pwmp->tim->CCER = ccer; + pwmp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */ + pwmp->tim->SR = 0; /* Clear pending IRQs. */ + pwmp->tim->DIER = pwmp->config->dier & /* DMA-related DIER settings. */ + ~STM32_TIM_DIER_IRQ_MASK; +#if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8 || STM32_PWM_USE_TIM20 +#if STM32_PWM_USE_ADVANCED + pwmp->tim->BDTR = pwmp->config->bdtr | STM32_TIM_BDTR_MOE; +#else + pwmp->tim->BDTR = STM32_TIM_BDTR_MOE; +#endif +#endif + /* Timer configured and started.*/ + pwmp->tim->CR1 = STM32_TIM_CR1_ARPE | STM32_TIM_CR1_URS | + STM32_TIM_CR1_CEN; +} + +/** + * @brief Deactivates the PWM peripheral. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @notapi + */ +void pwm_lld_stop(PWMDriver *pwmp) { + + /* If in ready state then disables the PWM clock.*/ + if (pwmp->state == PWM_READY) { + pwmp->tim->CR1 = 0; /* Timer disabled. */ + pwmp->tim->DIER = 0; /* All IRQs disabled. */ + pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */ +#if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8 || STM32_PWM_USE_TIM20 + pwmp->tim->BDTR = 0; +#endif + +#if STM32_PWM_USE_TIM1 + if (&PWMD1 == pwmp) { +#if !defined(STM32_TIM1_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM1_UP_NUMBER); + nvicDisableVector(STM32_TIM1_CC_NUMBER); +#endif + rccDisableTIM1(); + } +#endif + +#if STM32_PWM_USE_TIM2 + if (&PWMD2 == pwmp) { +#if !defined(STM32_TIM2_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM2_NUMBER); +#endif + rccDisableTIM2(); + } +#endif + +#if STM32_PWM_USE_TIM3 + if (&PWMD3 == pwmp) { +#if !defined(STM32_TIM3_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM3_NUMBER); +#endif + rccDisableTIM3(); + } +#endif + +#if STM32_PWM_USE_TIM4 + if (&PWMD4 == pwmp) { +#if !defined(STM32_TIM4_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM4_NUMBER); +#endif + rccDisableTIM4(); + } +#endif + +#if STM32_PWM_USE_TIM5 + if (&PWMD5 == pwmp) { +#if !defined(STM32_TIM5_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM5_NUMBER); +#endif + rccDisableTIM5(); + } +#endif + +#if STM32_PWM_USE_TIM8 + if (&PWMD8 == pwmp) { +#if !defined(STM32_TIM8_SUPPRESS_ISR) + nvicDisableVector(STM32_TIM8_UP_NUMBER); + nvicDisableVector(STM32_TIM8_CC_NUMBER); +#endif + rccDisableTIM8(); + } +#endif + +#if STM32_PWM_USE_TIM9 + if (&PWMD9 == pwmp) { + rccDisableTIM9(); + } +#endif + +#if STM32_PWM_USE_TIM10 + if (&PWMD10 == pwmp) { + rccDisableTIM10(); + } +#endif + +#if STM32_PWM_USE_TIM11 + if (&PWMD11 == pwmp) { + rccDisableTIM11(); + } +#endif + +#if STM32_PWM_USE_TIM12 + if (&PWMD12 == pwmp) { + rccDisableTIM12(); + } +#endif + +#if STM32_PWM_USE_TIM13 + if (&PWMD13 == pwmp) { + rccDisableTIM13(); + } +#endif + +#if STM32_PWM_USE_TIM14 + if (&PWMD14 == pwmp) { + rccDisableTIM14(); + } +#endif + +#if STM32_PWM_USE_TIM15 + if (&PWMD15 == pwmp) { + rccDisableTIM15(); + } +#endif + +#if STM32_PWM_USE_TIM16 + if (&PWMD16 == pwmp) { + rccDisableTIM16(); + } +#endif + +#if STM32_PWM_USE_TIM17 + if (&PWMD17 == pwmp) { + rccDisableTIM17(); + } +#endif + +#if STM32_PWM_USE_TIM20 + if (&PWMD20 == pwmp) { + rccDisableTIM20(); + } +#endif + +#if STM32_PWM_USE_TIM21 + if (&PWMD21 == pwmp) { + rccDisableTIM21(); + } +#endif + +#if STM32_PWM_USE_TIM22 + if (&PWMD22 == pwmp) { + rccDisableTIM22(); + } +#endif + } +} + +/** + * @brief Enables a PWM channel. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @post The channel is active using the specified configuration. + * @note The function has effect at the next cycle start. + * @note Channel notification is not enabled. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...channels-1) + * @param[in] width PWM pulse width as clock pulses number + * + * @notapi + */ +void pwm_lld_enable_channel(PWMDriver *pwmp, + pwmchannel_t channel, + pwmcnt_t width) { + + /* Changing channel duty cycle on the fly.*/ +#if STM32_TIM_MAX_CHANNELS <= 4 + pwmp->tim->CCR[channel] = width; +#else + if (channel < 4) + pwmp->tim->CCR[channel] = width; + else + pwmp->tim->CCXR[channel - 4] = width; +#endif +} + +/** + * @brief Disables a PWM channel and its notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @post The channel is disabled and its output line returned to the + * idle state. + * @note The function has effect at the next cycle start. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...channels-1) + * + * @notapi + */ +void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) { + +#if STM32_TIM_MAX_CHANNELS <= 4 + pwmp->tim->CCR[channel] = 0; + pwmp->tim->DIER &= ~(2 << channel); +#else + if (channel < 4) { + pwmp->tim->CCR[channel] = 0; + pwmp->tim->DIER &= ~(2 << channel); + } + else + pwmp->tim->CCXR[channel - 4] = 0; +#endif +} + +/** + * @brief Enables the periodic activation edge notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @note If the notification is already enabled then the call has no effect. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @notapi + */ +void pwm_lld_enable_periodic_notification(PWMDriver *pwmp) { + uint32_t dier = pwmp->tim->DIER; + + /* If the IRQ is not already enabled care must be taken to clear it, + it is probably already pending because the timer is running.*/ + if ((dier & STM32_TIM_DIER_UIE) == 0) { + pwmp->tim->SR = ~STM32_TIM_SR_UIF; + pwmp->tim->DIER = dier | STM32_TIM_DIER_UIE; + } +} + +/** + * @brief Disables the periodic activation edge notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @note If the notification is already disabled then the call has no effect. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @notapi + */ +void pwm_lld_disable_periodic_notification(PWMDriver *pwmp) { + + pwmp->tim->DIER &= ~STM32_TIM_DIER_UIE; +} + +/** + * @brief Enables a channel de-activation edge notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @pre The channel must have been activated using @p pwmEnableChannel(). + * @note If the notification is already enabled then the call has no effect. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...channels-1) + * + * @notapi + */ +void pwm_lld_enable_channel_notification(PWMDriver *pwmp, + pwmchannel_t channel) { + uint32_t dier = pwmp->tim->DIER; + +#if STM32_TIM_MAX_CHANNELS > 4 + /* Channels 4 and 5 do not support callbacks.*/ + osalDbgAssert(channel < 4, "callback not supported"); +#endif + + /* If the IRQ is not already enabled care must be taken to clear it, + it is probably already pending because the timer is running.*/ + if ((dier & (2 << channel)) == 0) { + pwmp->tim->SR = ~(2 << channel); + pwmp->tim->DIER = dier | (2 << channel); + } +} + +/** + * @brief Disables a channel de-activation edge notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @pre The channel must have been activated using @p pwmEnableChannel(). + * @note If the notification is already disabled then the call has no effect. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...channels-1) + * + * @notapi + */ +void pwm_lld_disable_channel_notification(PWMDriver *pwmp, + pwmchannel_t channel) { + + pwmp->tim->DIER &= ~(2 << channel); +} + +/** + * @brief Common TIM2...TIM5,TIM9 IRQ handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @notapi + */ +void pwm_lld_serve_interrupt(PWMDriver *pwmp) { + uint32_t sr; + + sr = pwmp->tim->SR; + sr &= pwmp->tim->DIER & STM32_TIM_DIER_IRQ_MASK; + pwmp->tim->SR = ~sr; + if (((sr & STM32_TIM_SR_CC1IF) != 0) && + (pwmp->config->channels[0].callback != NULL)) + pwmp->config->channels[0].callback(pwmp); + if (((sr & STM32_TIM_SR_CC2IF) != 0) && + (pwmp->config->channels[1].callback != NULL)) + pwmp->config->channels[1].callback(pwmp); + if (((sr & STM32_TIM_SR_CC3IF) != 0) && + (pwmp->config->channels[2].callback != NULL)) + pwmp->config->channels[2].callback(pwmp); + if (((sr & STM32_TIM_SR_CC4IF) != 0) && + (pwmp->config->channels[3].callback != NULL)) + pwmp->config->channels[3].callback(pwmp); + if (((sr & STM32_TIM_SR_UIF) != 0) && (pwmp->config->callback != NULL)) + pwmp->config->callback(pwmp); +} + +#endif /* HAL_USE_PWM */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.h new file mode 100644 index 0000000..4cf0f7c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.h @@ -0,0 +1,1034 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/hal_pwm_lld.h + * @brief STM32 PWM subsystem low level driver header. + * + * @addtogroup PWM + * @{ + */ + +#ifndef HAL_PWM_LLD_H +#define HAL_PWM_LLD_H + +#if HAL_USE_PWM || defined(__DOXYGEN__) + +#include "stm32_tim.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Number of PWM channels per PWM driver. + */ +#define PWM_CHANNELS STM32_TIM_MAX_CHANNELS + +/** + * @name STM32-specific PWM complementary output mode macros + * @{ + */ +/** + * @brief Complementary output modes mask. + * @note This is an STM32-specific setting. + */ +#define PWM_COMPLEMENTARY_OUTPUT_MASK 0xF0 + +/** + * @brief Complementary output not driven. + * @note This is an STM32-specific setting. + */ +#define PWM_COMPLEMENTARY_OUTPUT_DISABLED 0x00 + +/** + * @brief Complementary output, active is logic level one. + * @note This is an STM32-specific setting. + * @note This setting is only available if the configuration option + * @p STM32_PWM_USE_ADVANCED is set to TRUE and only for advanced + * timers TIM1 and TIM8. + */ +#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH 0x10 + +/** + * @brief Complementary output, active is logic level zero. + * @note This is an STM32-specific setting. + * @note This setting is only available if the configuration option + * @p STM32_PWM_USE_ADVANCED is set to TRUE and only for advanced + * timers TIM1 and TIM8. + */ +#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW 0x20 +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief If advanced timer features switch. + * @details If set to @p TRUE the advanced features for TIM1 and TIM8 are + * enabled. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_ADVANCED) || defined(__DOXYGEN__) +#define STM32_PWM_USE_ADVANCED FALSE +#endif + +/** + * @brief PWMD1 driver enable switch. + * @details If set to @p TRUE the support for PWMD1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM1) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM1 FALSE +#endif + +/** + * @brief PWMD2 driver enable switch. + * @details If set to @p TRUE the support for PWMD2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM2) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM2 FALSE +#endif + +/** + * @brief PWMD3 driver enable switch. + * @details If set to @p TRUE the support for PWMD3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM3) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM3 FALSE +#endif + +/** + * @brief PWMD4 driver enable switch. + * @details If set to @p TRUE the support for PWMD4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM4) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM4 FALSE +#endif + +/** + * @brief PWMD5 driver enable switch. + * @details If set to @p TRUE the support for PWMD5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM5) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM5 FALSE +#endif + +/** + * @brief PWMD8 driver enable switch. + * @details If set to @p TRUE the support for PWMD8 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM8) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM8 FALSE +#endif + +/** + * @brief PWMD9 driver enable switch. + * @details If set to @p TRUE the support for PWMD9 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM9) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM9 FALSE +#endif + +/** + * @brief PWMD10 driver enable switch. + * @details If set to @p TRUE the support for PWMD10 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM10) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM10 FALSE +#endif + +/** + * @brief PWMD11 driver enable switch. + * @details If set to @p TRUE the support for PWMD11 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM11) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM11 FALSE +#endif + +/** + * @brief PWMD12 driver enable switch. + * @details If set to @p TRUE the support for PWMD12 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM12) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM12 FALSE +#endif + +/** + * @brief PWMD13 driver enable switch. + * @details If set to @p TRUE the support for PWMD13 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM13) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM13 FALSE +#endif + +/** + * @brief PWMD14 driver enable switch. + * @details If set to @p TRUE the support for PWMD14 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM14) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM14 FALSE +#endif + +/** + * @brief PWMD15 driver enable switch. + * @details If set to @p TRUE the support for PWMD15 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM15) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM15 FALSE +#endif + +/** + * @brief PWMD16 driver enable switch. + * @details If set to @p TRUE the support for PWMD16 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM16) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM16 FALSE +#endif + +/** + * @brief PWMD17 driver enable switch. + * @details If set to @p TRUE the support for PWMD17 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM17) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM17 FALSE +#endif + +/** + * @brief PWMD20 driver enable switch. + * @details If set to @p TRUE the support for PWMD20 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM20) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM20 FALSE +#endif + +/** + * @brief PWMD21 driver enable switch. + * @details If set to @p TRUE the support for PWMD21 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM21) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM21 FALSE +#endif + +/** + * @brief PWMD22 driver enable switch. + * @details If set to @p TRUE the support for PWMD22 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_PWM_USE_TIM22) || defined(__DOXYGEN__) +#define STM32_PWM_USE_TIM22 FALSE +#endif + +/** + * @brief PWMD1 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM1_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD2 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM2_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD3 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM3_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD4 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM4_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD5 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM5_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD8 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM8_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD9 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM9_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD10 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM10_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM10_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD11 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM11_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM11_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD12 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM12_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM12_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD13 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM13_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM13_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD14 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM14_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM14_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD15 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM15_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM15_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD16 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM16_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM16_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD17 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM17_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM17_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD20 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM20_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM20_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD21 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM21_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM21_IRQ_PRIORITY 7 +#endif + +/** + * @brief PWMD22 interrupt priority level setting. + */ +#if !defined(STM32_PWM_TIM22_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_PWM_TIM22_IRQ_PRIORITY 7 +#endif +/** @} */ + +/*===========================================================================*/ +/* Configuration checks. */ +/*===========================================================================*/ + +#if !defined(STM32_HAS_TIM1) +#define STM32_HAS_TIM1 FALSE +#endif + +#if !defined(STM32_HAS_TIM2) +#define STM32_HAS_TIM2 FALSE +#endif + +#if !defined(STM32_HAS_TIM3) +#define STM32_HAS_TIM3 FALSE +#endif + +#if !defined(STM32_HAS_TIM4) +#define STM32_HAS_TIM4 FALSE +#endif + +#if !defined(STM32_HAS_TIM5) +#define STM32_HAS_TIM5 FALSE +#endif + +#if !defined(STM32_HAS_TIM8) +#define STM32_HAS_TIM8 FALSE +#endif + +#if !defined(STM32_HAS_TIM9) +#define STM32_HAS_TIM9 FALSE +#endif + +#if !defined(STM32_HAS_TIM10) +#define STM32_HAS_TIM10 FALSE +#endif + +#if !defined(STM32_HAS_TIM11) +#define STM32_HAS_TIM11 FALSE +#endif + +#if !defined(STM32_HAS_TIM12) +#define STM32_HAS_TIM12 FALSE +#endif + +#if !defined(STM32_HAS_TIM13) +#define STM32_HAS_TIM13 FALSE +#endif + +#if !defined(STM32_HAS_TIM14) +#define STM32_HAS_TIM14 FALSE +#endif + +#if !defined(STM32_HAS_TIM15) +#define STM32_HAS_TIM15 FALSE +#endif + +#if !defined(STM32_HAS_TIM16) +#define STM32_HAS_TIM16 FALSE +#endif + +#if !defined(STM32_HAS_TIM17) +#define STM32_HAS_TIM17 FALSE +#endif + +#if !defined(STM32_HAS_TIM20) +#define STM32_HAS_TIM20 FALSE +#endif + +#if !defined(STM32_HAS_TIM21) +#define STM32_HAS_TIM21 FALSE +#endif + +#if !defined(STM32_HAS_TIM22) +#define STM32_HAS_TIM22 FALSE +#endif + +#if STM32_PWM_USE_TIM1 && !STM32_HAS_TIM1 +#error "TIM1 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM2 && !STM32_HAS_TIM2 +#error "TIM2 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM3 && !STM32_HAS_TIM3 +#error "TIM3 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM4 && !STM32_HAS_TIM4 +#error "TIM4 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM5 && !STM32_HAS_TIM5 +#error "TIM5 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM8 && !STM32_HAS_TIM8 +#error "TIM8 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM9 && !STM32_HAS_TIM9 +#error "TIM9 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM10 && !STM32_HAS_TIM10 +#error "TIM10 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM11 && !STM32_HAS_TIM11 +#error "TIM11 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM12 && !STM32_HAS_TIM12 +#error "TIM12 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM13 && !STM32_HAS_TIM13 +#error "TIM13 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM14 && !STM32_HAS_TIM14 +#error "TIM14 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM15 && !STM32_HAS_TIM15 +#error "TIM15 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM16 && !STM32_HAS_TIM16 +#error "TIM16 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM17 && !STM32_HAS_TIM17 +#error "TIM17 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM20 && !STM32_HAS_TIM20 +#error "TIM20 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM21 && !STM32_HAS_TIM21 +#error "TIM21 not present in the selected device" +#endif + +#if STM32_PWM_USE_TIM22 && !STM32_HAS_TIM22 +#error "TIM22 not present in the selected device" +#endif + +#if !STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM2 && \ + !STM32_PWM_USE_TIM3 && !STM32_PWM_USE_TIM4 && \ + !STM32_PWM_USE_TIM5 && !STM32_PWM_USE_TIM8 && \ + !STM32_PWM_USE_TIM9 && !STM32_PWM_USE_TIM10 && \ + !STM32_PWM_USE_TIM11 && !STM32_PWM_USE_TIM11 && \ + !STM32_PWM_USE_TIM13 && !STM32_PWM_USE_TIM13 && \ + !STM32_PWM_USE_TIM15 && !STM32_PWM_USE_TIM15 && \ + !STM32_PWM_USE_TIM17 && !STM32_PWM_USE_TIM20 && \ + !STM32_PWM_USE_TIM21 && !STM32_PWM_USE_TIM22 +#error "PWM driver activated but no TIM peripheral assigned" +#endif + +#if STM32_PWM_USE_ADVANCED && !STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 && \ + !STM32_PWM_USE_TIM20 +#error "advanced mode selected but no advanced timer assigned" +#endif + +/* Checks on allocation of TIMx units.*/ +#if STM32_PWM_USE_TIM1 +#if defined(STM32_TIM1_IS_USED) +#error "PWMD1 requires TIM1 but the timer is already used" +#else +#define STM32_TIM1_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM2 +#if defined(STM32_TIM2_IS_USED) +#error "PWMD2 requires TIM2 but the timer is already used" +#else +#define STM32_TIM2_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM3 +#if defined(STM32_TIM3_IS_USED) +#error "PWMD3 requires TIM3 but the timer is already used" +#else +#define STM32_TIM3_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM4 +#if defined(STM32_TIM4_IS_USED) +#error "PWMD4 requires TIM4 but the timer is already used" +#else +#define STM32_TIM4_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM5 +#if defined(STM32_TIM5_IS_USED) +#error "PWMD5 requires TIM5 but the timer is already used" +#else +#define STM32_TIM5_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM8 +#if defined(STM32_TIM8_IS_USED) +#error "PWMD8 requires TIM8 but the timer is already used" +#else +#define STM32_TIM8_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM9 +#if defined(STM32_TIM9_IS_USED) +#error "PWMD9 requires TIM9 but the timer is already used" +#else +#define STM32_TIM9_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM10 +#if defined(STM32_TIM10_IS_USED) +#error "PWMD10 requires TIM10 but the timer is already used" +#else +#define STM32_TIM10_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM11 +#if defined(STM32_TIM11_IS_USED) +#error "PWMD11 requires TIM11 but the timer is already used" +#else +#define STM32_TIM11_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM12 +#if defined(STM32_TIM12_IS_USED) +#error "PWMD12 requires TIM12 but the timer is already used" +#else +#define STM32_TIM12_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM13 +#if defined(STM32_TIM13_IS_USED) +#error "PWMD13 requires TIM13 but the timer is already used" +#else +#define STM32_TIM13_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM14 +#if defined(STM32_TIM14_IS_USED) +#error "PWMD14 requires TIM14 but the timer is already used" +#else +#define STM32_TIM14_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM15 +#if defined(STM32_TIM15_IS_USED) +#error "PWMD15 requires TIM15 but the timer is already used" +#else +#define STM32_TIM15_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM16 +#if defined(STM32_TIM16_IS_USED) +#error "PWMD16 requires TIM16 but the timer is already used" +#else +#define STM32_TIM16_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM17 +#if defined(STM32_TIM17_IS_USED) +#error "PWMD17 requires TIM17 but the timer is already used" +#else +#define STM32_TIM17_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM20 +#if defined(STM32_TIM20_IS_USED) +#error "PWMD20 requires TIM20 but the timer is already used" +#else +#define STM32_TIM20_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM21 +#if defined(STM32_TIM21_IS_USED) +#error "PWMD21 requires TIM21 but the timer is already used" +#else +#define STM32_TIM21_IS_USED +#endif +#endif + +#if STM32_PWM_USE_TIM22 +#if defined(STM32_TIM22_IS_USED) +#error "PWMD22 requires TIM22 but the timer is already used" +#else +#define STM32_TIM22_IS_USED +#endif +#endif + +/* IRQ priority checks.*/ +#if STM32_PWM_USE_TIM1 && !defined(STM32_TIM1_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM1" +#endif + +#if STM32_PWM_USE_TIM2 && !defined(STM32_TIM2_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM2" +#endif + +#if STM32_PWM_USE_TIM3 && !defined(STM32_TIM3_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM3" +#endif + +#if STM32_PWM_USE_TIM4 && !defined(STM32_TIM4_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM4" +#endif + +#if STM32_PWM_USE_TIM5 && !defined(STM32_TIM5_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM5" +#endif + +#if STM32_PWM_USE_TIM8 && !defined(STM32_TIM8_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM8_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM8" +#endif + +#if STM32_PWM_USE_TIM9 && !defined(STM32_TIM9_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM9_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM9" +#endif + +#if STM32_PWM_USE_TIM10 && !defined(STM32_TIM10_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM10_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM10" +#endif + +#if STM32_PWM_USE_TIM11 && !defined(STM32_TIM11_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM11_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM11" +#endif + +#if STM32_PWM_USE_TIM12 && !defined(STM32_TIM12_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM12_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM12" +#endif + +#if STM32_PWM_USE_TIM13 && !defined(STM32_TIM13_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM13_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM13" +#endif + +#if STM32_PWM_USE_TIM14 && !defined(STM32_TIM14_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM14_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM14" +#endif + +#if STM32_PWM_USE_TIM15 && !defined(STM32_TIM15_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM15_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM15" +#endif + +#if STM32_PWM_USE_TIM16 && !defined(STM32_TIM16_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM16_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM16" +#endif + +#if STM32_PWM_USE_TIM17 && !defined(STM32_TIM17_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM17_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM17" +#endif + +#if STM32_PWM_USE_TIM20 && !defined(STM32_TIM20_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM20_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM20" +#endif + +#if STM32_PWM_USE_TIM21 && !defined(STM32_TIM21_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM21_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM21" +#endif + +#if STM32_PWM_USE_TIM22 && !defined(STM32_TIM22_SUPPRESS_ISR) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM22_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM22" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a PWM mode. + */ +typedef uint32_t pwmmode_t; + +/** + * @brief Type of a PWM channel. + */ +typedef uint8_t pwmchannel_t; + +/** + * @brief Type of a channels mask. + */ +typedef uint32_t pwmchnmsk_t; + +/** + * @brief Type of a PWM counter. + */ +typedef uint32_t pwmcnt_t; + +/** + * @brief Type of a PWM driver channel configuration structure. + */ +typedef struct { + /** + * @brief Channel active logic level. + */ + pwmmode_t mode; + /** + * @brief Channel callback pointer. + * @note This callback is invoked on the channel compare event. If set to + * @p NULL then the callback is disabled. + */ + pwmcallback_t callback; + /* End of the mandatory fields.*/ +} PWMChannelConfig; + +/** + * @brief Type of a PWM driver configuration structure. + */ +typedef struct { + /** + * @brief Timer clock in Hz. + * @note The low level can use assertions in order to catch invalid + * frequency specifications. + */ + uint32_t frequency; + /** + * @brief PWM period in ticks. + * @note The low level can use assertions in order to catch invalid + * period specifications. + */ + pwmcnt_t period; + /** + * @brief Periodic callback pointer. + * @note This callback is invoked on PWM counter reset. If set to + * @p NULL then the callback is disabled. + */ + pwmcallback_t callback; + /** + * @brief Channels configurations. + */ + PWMChannelConfig channels[PWM_CHANNELS]; + /* End of the mandatory fields.*/ + /** + * @brief TIM CR2 register initialization data. + * @note The value of this field should normally be equal to zero. + */ + uint32_t cr2; +#if STM32_PWM_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief TIM BDTR (break & dead-time) register initialization data. + * @note The value of this field should normally be equal to zero. + */ \ + uint32_t bdtr; +#endif + /** + * @brief TIM DIER register initialization data. + * @note The value of this field should normally be equal to zero. + * @note Only the DMA-related bits can be specified in this field. + */ + uint32_t dier; +} PWMConfig; + +/** + * @brief Structure representing a PWM driver. + */ +struct PWMDriver { + /** + * @brief Driver state. + */ + pwmstate_t state; + /** + * @brief Current driver configuration data. + */ + const PWMConfig *config; + /** + * @brief Current PWM period in ticks. + */ + pwmcnt_t period; + /** + * @brief Mask of the enabled channels. + */ + pwmchnmsk_t enabled; + /** + * @brief Number of channels in this instance. + */ + pwmchannel_t channels; +#if defined(PWM_DRIVER_EXT_FIELDS) + PWM_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Timer base clock. + */ + uint32_t clock; + /** + * @brief Pointer to the TIMx registers block. + */ + stm32_tim_t *tim; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Changes the period the PWM peripheral. + * @details This function changes the period of a PWM unit that has already + * been activated using @p pwmStart(). + * @pre The PWM unit must have been activated using @p pwmStart(). + * @post The PWM unit period is changed to the new value. + * @note The function has effect at the next cycle start. + * @note If a period is specified that is shorter than the pulse width + * programmed in one of the channels then the behavior is not + * guaranteed. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] period new cycle time in ticks + * + * @notapi + */ +#define pwm_lld_change_period(pwmp, period) \ + ((pwmp)->tim->ARR = ((period) - 1)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_PWM_USE_TIM1 && !defined(__DOXYGEN__) +extern PWMDriver PWMD1; +#endif + +#if STM32_PWM_USE_TIM2 && !defined(__DOXYGEN__) +extern PWMDriver PWMD2; +#endif + +#if STM32_PWM_USE_TIM3 && !defined(__DOXYGEN__) +extern PWMDriver PWMD3; +#endif + +#if STM32_PWM_USE_TIM4 && !defined(__DOXYGEN__) +extern PWMDriver PWMD4; +#endif + +#if STM32_PWM_USE_TIM5 && !defined(__DOXYGEN__) +extern PWMDriver PWMD5; +#endif + +#if STM32_PWM_USE_TIM8 && !defined(__DOXYGEN__) +extern PWMDriver PWMD8; +#endif + +#if STM32_PWM_USE_TIM9 && !defined(__DOXYGEN__) +extern PWMDriver PWMD9; +#endif + +#if STM32_PWM_USE_TIM10 && !defined(__DOXYGEN__) +extern PWMDriver PWMD10; +#endif + +#if STM32_PWM_USE_TIM11 && !defined(__DOXYGEN__) +extern PWMDriver PWMD11; +#endif + +#if STM32_PWM_USE_TIM12 && !defined(__DOXYGEN__) +extern PWMDriver PWMD12; +#endif + +#if STM32_PWM_USE_TIM13 && !defined(__DOXYGEN__) +extern PWMDriver PWMD13; +#endif + +#if STM32_PWM_USE_TIM14 && !defined(__DOXYGEN__) +extern PWMDriver PWMD14; +#endif + +#if STM32_PWM_USE_TIM15 && !defined(__DOXYGEN__) +extern PWMDriver PWMD15; +#endif + +#if STM32_PWM_USE_TIM16 && !defined(__DOXYGEN__) +extern PWMDriver PWMD16; +#endif + +#if STM32_PWM_USE_TIM17 && !defined(__DOXYGEN__) +extern PWMDriver PWMD17; +#endif + +#if STM32_PWM_USE_TIM20 && !defined(__DOXYGEN__) +extern PWMDriver PWMD20; +#endif + +#if STM32_PWM_USE_TIM21 && !defined(__DOXYGEN__) +extern PWMDriver PWMD21; +#endif + +#if STM32_PWM_USE_TIM22 && !defined(__DOXYGEN__) +extern PWMDriver PWMD22; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void pwm_lld_init(void); + void pwm_lld_start(PWMDriver *pwmp); + void pwm_lld_stop(PWMDriver *pwmp); + void pwm_lld_enable_channel(PWMDriver *pwmp, + pwmchannel_t channel, + pwmcnt_t width); + void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel); + void pwm_lld_enable_periodic_notification(PWMDriver *pwmp); + void pwm_lld_disable_periodic_notification(PWMDriver *pwmp); + void pwm_lld_enable_channel_notification(PWMDriver *pwmp, + pwmchannel_t channel); + void pwm_lld_disable_channel_notification(PWMDriver *pwmp, + pwmchannel_t channel); + void pwm_lld_serve_interrupt(PWMDriver *pwmp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_PWM */ + +#endif /* HAL_PWM_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c new file mode 100644 index 0000000..4c657b5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c @@ -0,0 +1,492 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/hal_st_lld.c + * @brief ST Driver subsystem low level driver code. + * + * @addtogroup ST + * @{ + */ + +#include "hal.h" + +#if (OSAL_ST_MODE != OSAL_ST_MODE_NONE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING + +#if (OSAL_ST_RESOLUTION == 32) +#define ST_ARR_INIT 0xFFFFFFFFU +#else +#define ST_ARR_INIT 0x0000FFFFU +#endif + +#if STM32_ST_USE_TIMER == 2 + +#if !STM32_HAS_TIM2 +#error "TIM2 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM2_IS_32BITS +#error "TIM2 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM2_HANDLER +#define ST_NUMBER STM32_TIM2_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK1 +#define ST_ENABLE_CLOCK() rccEnableTIM2(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM2_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM2_STOP +#elif defined(STM32G0XX) +#define ST_ENABLE_STOP() DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM2_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM2 +#else +#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM2_STOP +#endif + +#elif STM32_ST_USE_TIMER == 3 + +#if !STM32_HAS_TIM3 +#error "TIM3 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM3_IS_32BITS +#error "TIM3 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM3_HANDLER +#define ST_NUMBER STM32_TIM3_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK1 +#define ST_ENABLE_CLOCK() rccEnableTIM3(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM3_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM3_STOP +#elif defined(STM32G0XX) +#define ST_ENABLE_STOP() DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM3 +#else +#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM3_STOP +#endif + +#elif STM32_ST_USE_TIMER == 4 + +#if !STM32_HAS_TIM4 +#error "TIM4 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM4_IS_32BITS +#error "TIM4 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM4_HANDLER +#define ST_NUMBER STM32_TIM4_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK1 +#define ST_ENABLE_CLOCK() rccEnableTIM4(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM4_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM4_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM4 +#else +#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM4_STOP +#endif + +#elif STM32_ST_USE_TIMER == 5 + +#if !STM32_HAS_TIM5 +#error "TIM5 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM5_IS_32BITS +#error "TIM5 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM5_HANDLER +#define ST_NUMBER STM32_TIM5_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK1 +#define ST_ENABLE_CLOCK() rccEnableTIM5(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM5_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM5_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM5 +#else +#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM5_STOP +#endif + +#elif STM32_ST_USE_TIMER == 9 + +#if !STM32_HAS_TIM9 +#error "TIM9 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM9_IS_32BITS +#error "TIM9 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM9_HANDLER +#define ST_NUMBER STM32_TIM9_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK2 +#define ST_ENABLE_CLOCK() rccEnableTIM9(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM9_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB2FZR1 |= DBGMCU_APB2FZR1_DBG_TIM9_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB2LFZ1 |= DBGMCU_APB2LFZ1_DBG_TIM9 +#else +#define ST_ENABLE_STOP() DBGMCU->APB2FZ |= DBGMCU_APB2_FZ_DBG_TIM9_STOP +#endif + +#elif STM32_ST_USE_TIMER == 10 + +#if !STM32_HAS_TIM10 +#error "TIM10 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM10_IS_32BITS +#error "TIM10 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM10_HANDLER +#define ST_NUMBER STM32_TIM10_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK2 +#define ST_ENABLE_CLOCK() rccEnableTIM10(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM10_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB2FZR1 |= DBGMCU_APB2FZR1_DBG_TIM10_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB2LFZ1 |= DBGMCU_APB2LFZ1_DBG_TIM10 +#else +#define ST_ENABLE_STOP() DBGMCU->APB2FZ |= DBGMCU_APB2_FZ_DBG_TIM10_STOP +#endif + +#elif STM32_ST_USE_TIMER == 11 + +#if !STM32_HAS_TIM11 +#error "TIM11 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM11_IS_32BITS +#error "TIM11 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM11_HANDLER +#define ST_NUMBER STM32_TIM11_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK2 +#define ST_ENABLE_CLOCK() rccEnableTIM11(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM11_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB2FZR1 |= DBGMCU_APB2FZR1_DBG_TIM11_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB2LFZ1 |= DBGMCU_APB2LFZ1_DBG_TIM11 +#else +#define ST_ENABLE_STOP() DBGMCU->APB2FZ |= DBGMCU_APB2_FZ_DBG_TIM11_STOP +#endif + +#elif STM32_ST_USE_TIMER == 12 + +#if !STM32_HAS_TIM12 +#error "TIM12 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM12_IS_32BITS +#error "TIM12 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM12_HANDLER +#define ST_NUMBER STM32_TIM12_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK1 +#define ST_ENABLE_CLOCK() rccEnableTIM12(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM12_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM12_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM12 +#else +#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM12_STOP +#endif + +#elif STM32_ST_USE_TIMER == 13 + +#if !STM32_HAS_TIM13 +#error "TIM13 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM13_IS_32BITS +#error "TIM13 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM13_HANDLER +#define ST_NUMBER STM32_TIM13_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK1 +#define ST_ENABLE_CLOCK() rccEnableTIM13(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM13_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM13_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM13 +#else +#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM13_STOP +#endif + +#elif STM32_ST_USE_TIMER == 14 + +#if !STM32_HAS_TIM14 +#error "TIM14 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM14_IS_32BITS +#error "TIM14 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM14_HANDLER +#define ST_NUMBER STM32_TIM14_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK1 +#define ST_ENABLE_CLOCK() rccEnableTIM14(true) +#if defined(STM32F1XX) +#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM14_STOP +#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) +#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM14_STOP +#elif defined(STM32H7XX) +#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM14 +#else +#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM14_STOP +#endif + +#elif STM32_ST_USE_TIMER == 21 + +#if !STM32_HAS_TIM21 +#error "TIM21 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM21_IS_32BITS +#error "TIM21 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM21_HANDLER +#define ST_NUMBER STM32_TIM21_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK2 +#define ST_ENABLE_CLOCK() rccEnableTIM21(true) +#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB2_FZ_DBG_TIM21_STOP + +#elif STM32_ST_USE_TIMER == 22 + +#if !STM32_HAS_TIM22 +#error "TIM22 not present in the selected device" +#endif + +#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM22_IS_32BITS +#error "TIM21 is not a 32bits timer" +#endif + +#define ST_HANDLER STM32_TIM22_HANDLER +#define ST_NUMBER STM32_TIM22_NUMBER +#define ST_CLOCK_SRC STM32_TIMCLK2 +#define ST_ENABLE_CLOCK() rccEnableTIM22(true) +#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB2_FZ_DBG_TIM21_STOP + +#else +#error "STM32_ST_USE_TIMER specifies an unsupported timer" +#endif + +#if ST_CLOCK_SRC % OSAL_ST_FREQUENCY != 0 +#error "the selected ST frequency is not obtainable because integer rounding" +#endif + +#if (ST_CLOCK_SRC / OSAL_ST_FREQUENCY) - 1 > 0xFFFF +#error "the selected ST frequency is not obtainable because TIM timer prescaler limits" +#endif + +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */ + +#if OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC + +#define ST_HANDLER SysTick_Handler + +#if defined(STM32_CORE_CK) +#define SYSTICK_CK STM32_CORE_CK +#else +#define SYSTICK_CK STM32_HCLK +#endif + +#if SYSTICK_CK % OSAL_ST_FREQUENCY != 0 +#error "the selected ST frequency is not obtainable because integer rounding" +#endif + +#if (SYSTICK_CK / OSAL_ST_FREQUENCY) - 1 > 0xFFFFFF +#error "the selected ST frequency is not obtainable because SysTick timer counter limits" +#endif + +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if !defined(STM32_SYSTICK_SUPPRESS_ISR) +/** + * @brief Interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(ST_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + st_lld_serve_interrupt(); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ST driver initialization. + * + * @notapi + */ +void st_lld_init(void) { + +#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING + /* Free running counter mode.*/ + + /* Enabling timer clock.*/ + ST_ENABLE_CLOCK(); + + /* Enabling the stop mode during debug for this timer.*/ + ST_ENABLE_STOP(); + + /* Initializing the counter in free running mode.*/ + STM32_ST_TIM->PSC = (ST_CLOCK_SRC / OSAL_ST_FREQUENCY) - 1; + STM32_ST_TIM->ARR = ST_ARR_INIT; + STM32_ST_TIM->CCMR1 = 0; + STM32_ST_TIM->CCR[0] = 0; +#if ST_LLD_NUM_ALARMS > 1 + STM32_ST_TIM->CCR[1] = 0; +#endif +#if ST_LLD_NUM_ALARMS > 2 + STM32_ST_TIM->CCR[2] = 0; +#endif +#if ST_LLD_NUM_ALARMS > 3 + STM32_ST_TIM->CCR[3] = 0; +#endif + STM32_ST_TIM->DIER = 0; + STM32_ST_TIM->CR2 = 0; + STM32_ST_TIM->EGR = TIM_EGR_UG; + STM32_ST_TIM->CR1 = TIM_CR1_CEN; + +#if !defined(STM32_SYSTICK_SUPPRESS_ISR) + /* IRQ enabled.*/ + nvicEnableVector(ST_NUMBER, STM32_ST_IRQ_PRIORITY); +#endif +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */ + +#if OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC + /* Periodic systick mode, the Cortex-Mx internal systick timer is used + in this mode.*/ + SysTick->LOAD = (SYSTICK_CK / OSAL_ST_FREQUENCY) - 1; + SysTick->VAL = 0; + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_ENABLE_Msk | + SysTick_CTRL_TICKINT_Msk; + + /* IRQ enabled.*/ + nvicSetSystemHandlerPriority(HANDLER_SYSTICK, STM32_ST_IRQ_PRIORITY); +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */ +} + +/** + * @brief IRQ handling code. + */ +void st_lld_serve_interrupt(void) { +#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING + uint32_t sr; + stm32_tim_t *timp = STM32_ST_TIM; + + sr = timp->SR; + sr &= timp->DIER & STM32_TIM_DIER_IRQ_MASK; + timp->SR = ~sr; + + if ((sr & TIM_SR_CC1IF) != 0U) +#endif + { + osalSysLockFromISR(); + osalOsTimerHandlerI(); + osalSysUnlockFromISR(); + } +#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING +#if ST_LLD_NUM_ALARMS > 1 + if ((sr & TIM_SR_CC2IF) != 0U) { + if (st_callbacks[2] != NULL) { + st_callbacks[0](1U); + } + } +#endif +#if ST_LLD_NUM_ALARMS > 2 + if ((sr & TIM_SR_CC3IF) != 0U) { + if (st_callbacks[2] != NULL) { + st_callbacks[1](2U); + } + } +#endif +#if ST_LLD_NUM_ALARMS > 3 + if ((sr & TIM_SR_CC4IF) != 0U) { + if (st_callbacks[2] != NULL) { + st_callbacks[2](3U); + } + } +#endif +#endif +} + +#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.h new file mode 100644 index 0000000..2b7f537 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.h @@ -0,0 +1,701 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/hal_st_lld.h + * @brief ST Driver subsystem low level driver header. + * @details This header is designed to be include-able without having to + * include other files from the HAL. + * + * @addtogroup ST + * @{ + */ + +#ifndef HAL_ST_LLD_H +#define HAL_ST_LLD_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* Feature currently disabled.*/ +#define STM32_ST_ENFORCE_ALARMS 1 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SysTick timer IRQ priority. + */ +#if !defined(STM32_ST_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ST_IRQ_PRIORITY 8 +#endif + +/** + * @brief TIMx unit (by number) to be used for free running operations. + * @note You must select a 32 bits timer if a 32 bits @p systick_t type + * is required. + * @note Timers 2, 3, 4, 5, 21 and 22 are supported. + */ +#if !defined(STM32_ST_USE_TIMER) || defined(__DOXYGEN__) +#define STM32_ST_USE_TIMER 2 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* This has to go after transition to shared handlers is complete for all + platforms.*/ +#if !defined(STM32_HAS_TIM2) +#define STM32_HAS_TIM2 FALSE +#endif + +#if !defined(STM32_HAS_TIM3) +#define STM32_HAS_TIM3 FALSE +#endif + +#if !defined(STM32_HAS_TIM4) +#define STM32_HAS_TIM4 FALSE +#endif + +#if !defined(STM32_HAS_TIM5) +#define STM32_HAS_TIM5 FALSE +#endif + +#if !defined(STM32_HAS_TIM9) +#define STM32_HAS_TIM9 FALSE +#endif + +#if !defined(STM32_HAS_TIM10) +#define STM32_HAS_TIM10 FALSE +#endif + +#if !defined(STM32_HAS_TIM11) +#define STM32_HAS_TIM11 FALSE +#endif + +#if !defined(STM32_HAS_TIM12) +#define STM32_HAS_TIM12 FALSE +#endif + +#if !defined(STM32_HAS_TIM13) +#define STM32_HAS_TIM13 FALSE +#endif + +#if !defined(STM32_HAS_TIM14) +#define STM32_HAS_TIM14 FALSE +#endif + +#if !defined(STM32_HAS_TIM21) +#define STM32_HAS_TIM21 FALSE +#endif + +#if !defined(STM32_HAS_TIM22) +#define STM32_HAS_TIM22 FALSE +#endif +/**/ + +#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING + +#if STM32_ST_USE_TIMER == 2 + +#if defined(STM32_TIM2_IS_USED) +#error "ST requires TIM2 but the timer is already used" +#else +#define STM32_TIM2_IS_USED +#endif + +#if defined(STM32_TIM2_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM2 +#define ST_LLD_NUM_ALARMS STM32_TIM2_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 TRUE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 3 + +#if defined(STM32_TIM3_IS_USED) +#error "ST requires TIM3 but the timer is already used" +#else +#define STM32_TIM3_IS_USED +#endif + +#if defined(STM32_TIM3_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM3 +#define ST_LLD_NUM_ALARMS STM32_TIM3_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 TRUE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 4 + +#if defined(STM32_TIM4_IS_USED) +#error "ST requires TIM4 but the timer is already used" +#else +#define STM32_TIM4_IS_USED +#endif + +#if defined(STM32_TIM4_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM4 +#define ST_LLD_NUM_ALARMS STM32_TIM4_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 TRUE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 5 + +#if defined(STM32_TIM5_IS_USED) +#error "ST requires TIM5 but the timer is already used" +#else +#define STM32_TIM5_IS_USED +#endif + +#if defined(STM32_TIM5_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM5 +#define ST_LLD_NUM_ALARMS STM32_TIM5_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 TRUE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 9 + +#if defined(STM32_TIM9_IS_USED) +#error "ST requires TIM9 but the timer is already used" +#else +#define STM32_TIM9_IS_USED +#endif + +#if defined(STM32_TIM9_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM9 +#define ST_LLD_NUM_ALARMS STM32_TIM9_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 TRUE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 10 + +#if defined(STM32_TIM10_IS_USED) +#error "ST requires TIM10 but the timer is already used" +#else +#define STM32_TIM10_IS_USED +#endif + +#if defined(STM32_TIM10_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM10 +#define ST_LLD_NUM_ALARMS STM32_TIM10_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 TRUE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 11 + +#if defined(STM32_TIM11_IS_USED) +#error "ST requires TIM11 but the timer is already used" +#else +#define STM32_TIM11_IS_USED +#endif + +#if defined(STM32_TIM11_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM11 +#define ST_LLD_NUM_ALARMS STM32_TIM11_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 TRUE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 12 + +#if defined(STM32_TIM12_IS_USED) +#error "ST requires TIM12 but the timer is already used" +#else +#define STM32_TIM12_IS_USED +#endif + +#if defined(STM32_TIM12_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM12 +#define ST_LLD_NUM_ALARMS STM32_TIM12_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 TRUE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 13 + +#if defined(STM32_TIM13_IS_USED) +#error "ST requires TIM13 but the timer is already used" +#else +#define STM32_TIM13_IS_USED +#endif + +#if defined(STM32_TIM13_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM13 +#define ST_LLD_NUM_ALARMS STM32_TIM13_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 TRUE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 14 + +#if defined(STM32_TIM14_IS_USED) +#error "ST requires TIM14 but the timer is already used" +#else +#define STM32_TIM14_IS_USED +#endif + +#if defined(STM32_TIM14_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM14 +#define ST_LLD_NUM_ALARMS STM32_TIM14_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 TRUE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 21 + +#if defined(STM32_TIM21_IS_USED) +#error "ST requires TIM21 but the timer is already used" +#else +#define STM32_TIM21_IS_USED +#endif + +#if defined(STM32_TIM21_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM21 +#define ST_LLD_NUM_ALARMS STM32_TIM21_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 TRUE +#define STM32_ST_USE_TIM22 FALSE + +#elif STM32_ST_USE_TIMER == 22 + +#if defined(STM32_TIM22_IS_USED) +#error "ST requires TIM22 but the timer is already used" +#else +#define STM32_TIM22_IS_USED +#endif + +#if defined(STM32_TIM22_SUPPRESS_ISR) +#define STM32_SYSTICK_SUPPRESS_ISR +#endif + +#define STM32_ST_TIM STM32_TIM22 +#define ST_LLD_NUM_ALARMS STM32_TIM22_CHANNELS +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 TRUE + +#else +#error "STM32_ST_USE_TIMER specifies an unsupported timer" +#endif + +#if defined(STM32_ST_ENFORCE_ALARMS) + +#if (STM32_ST_ENFORCE_ALARMS < 1) || (STM32_ST_ENFORCE_ALARMS > ST_LLD_NUM_ALARMS) +#error "invalid STM32_ST_ENFORCE_ALARMS value" +#endif + +#undef ST_LLD_NUM_ALARMS +#define ST_LLD_NUM_ALARMS STM32_ST_ENFORCE_ALARMS +#endif + +#elif OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING + +#define STM32_ST_USE_SYSTICK TRUE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#else + +#define STM32_ST_USE_SYSTICK FALSE +#define STM32_ST_USE_TIM2 FALSE +#define STM32_ST_USE_TIM3 FALSE +#define STM32_ST_USE_TIM4 FALSE +#define STM32_ST_USE_TIM5 FALSE +#define STM32_ST_USE_TIM9 FALSE +#define STM32_ST_USE_TIM10 FALSE +#define STM32_ST_USE_TIM11 FALSE +#define STM32_ST_USE_TIM12 FALSE +#define STM32_ST_USE_TIM13 FALSE +#define STM32_ST_USE_TIM14 FALSE +#define STM32_ST_USE_TIM21 FALSE +#define STM32_ST_USE_TIM22 FALSE + +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void st_lld_init(void); + void st_lld_serve_interrupt(void); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Driver inline functions. */ +/*===========================================================================*/ + + +#if (OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING) || defined(__DOXYGEN__) + +/** + * @brief Returns the time counter value. + * + * @return The counter value. + * + * @notapi + */ +static inline systime_t st_lld_get_counter(void) { + + return (systime_t)STM32_ST_TIM->CNT; +} + +/** + * @brief Starts the alarm. + * @note Makes sure that no spurious alarms are triggered after + * this call. + * + * @param[in] abstime the time to be set for the first alarm + * + * @notapi + */ +static inline void st_lld_start_alarm(systime_t abstime) { + + STM32_ST_TIM->CCR[0] = (uint32_t)abstime; + STM32_ST_TIM->SR = 0; +#if ST_LLD_NUM_ALARMS == 1 + STM32_ST_TIM->DIER = STM32_TIM_DIER_CC1IE; +#else + STM32_ST_TIM->DIER |= STM32_TIM_DIER_CC1IE; +#endif +} + +/** + * @brief Stops the alarm interrupt. + * + * @notapi + */ +static inline void st_lld_stop_alarm(void) { + +#if ST_LLD_NUM_ALARMS == 1 + STM32_ST_TIM->DIER = 0U; +#else + STM32_ST_TIM->DIER &= ~STM32_TIM_DIER_CC1IE; +#endif +} + +/** + * @brief Sets the alarm time. + * + * @param[in] abstime the time to be set for the next alarm + * + * @notapi + */ +static inline void st_lld_set_alarm(systime_t abstime) { + + STM32_ST_TIM->CCR[0] = (uint32_t)abstime; +} + +/** + * @brief Returns the current alarm time. + * + * @return The currently set alarm time. + * + * @notapi + */ +static inline systime_t st_lld_get_alarm(void) { + + return (systime_t)STM32_ST_TIM->CCR[0]; +} + +/** + * @brief Determines if the alarm is active. + * + * @return The alarm status. + * @retval false if the alarm is not active. + * @retval true is the alarm is active + * + * @notapi + */ +static inline bool st_lld_is_alarm_active(void) { + + return (bool)((STM32_ST_TIM->DIER & STM32_TIM_DIER_CC1IE) != 0); +} + +#if (ST_LLD_NUM_ALARMS > 1) || defined(__DOXYGEN__) +/** + * @brief Starts an alarm. + * @note Makes sure that no spurious alarms are triggered after + * this call. + * @note This functionality is only available in free running mode, the + * behavior in periodic mode is undefined. + * + * @param[in] abstime the time to be set for the first alarm + * @param[in] alarm alarm channel number + * + * @notapi + */ +static inline void st_lld_start_alarm_n(unsigned alarm, systime_t abstime) { + + + STM32_ST_TIM->CCR[alarm] = (uint32_t)abstime; + STM32_ST_TIM->SR = 0; + STM32_ST_TIM->DIER |= (STM32_TIM_DIER_CC1IE << alarm); +} + +/** + * @brief Stops an alarm interrupt. + * @note This functionality is only available in free running mode, the + * behavior in periodic mode is undefined. + * + * @param[in] alarm alarm channel number + * + * @notapi + */ +static inline void st_lld_stop_alarm_n(unsigned alarm) { + + STM32_ST_TIM->DIER &= ~(STM32_TIM_DIER_CC1IE << alarm); +} + +/** + * @brief Sets an alarm time. + * @note This functionality is only available in free running mode, the + * behavior in periodic mode is undefined. + * + * @param[in] alarm alarm channel number + * @param[in] abstime the time to be set for the next alarm + * + * @notapi + */ +static inline void st_lld_set_alarm_n(unsigned alarm, systime_t abstime) { + + STM32_ST_TIM->CCR[alarm] = (uint32_t)abstime; +} + +/** + * @brief Returns an alarm current time. + * @note This functionality is only available in free running mode, the + * behavior in periodic mode is undefined. + * + * @param[in] alarm alarm channel number + * @return The currently set alarm time. + * + * @notapi + */ +static inline systime_t st_lld_get_alarm_n(unsigned alarm) { + + return (systime_t)STM32_ST_TIM->CCR[alarm]; +} + +/** + * @brief Determines if an alarm is active. + * + * @param[in] alarm alarm channel number + * @return The alarm status. + * @retval false if the alarm is not active. + * @retval true is the alarm is active + * + * @notapi + */ +static inline bool st_lld_is_alarm_active_n(unsigned alarm) { + + return (bool)((STM32_ST_TIM->DIER & (STM32_TIM_DIER_CC1IE << alarm)) != 0); +} +#endif /* ST_LLD_NUM_ALARMS > 1 */ + +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */ + +#endif /* HAL_ST_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h new file mode 100644 index 0000000..8f158fe --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h @@ -0,0 +1,552 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim.h + * @brief STM32 TIM units common header. + * @note This file requires definitions from the ST STM32 header file. + * + * @addtogroup STM32_TIMv1 + * @{ + */ + +#ifndef STM32_TIM_H +#define STM32_TIM_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name TIM_CR1 register + * @{ + */ +#define STM32_TIM_CR1_CEN (1U << 0) +#define STM32_TIM_CR1_UDIS (1U << 1) +#define STM32_TIM_CR1_URS (1U << 2) +#define STM32_TIM_CR1_OPM (1U << 3) +#define STM32_TIM_CR1_DIR (1U << 4) + +#define STM32_TIM_CR1_CMS_MASK (3U << 5) +#define STM32_TIM_CR1_CMS(n) ((n) << 5) + +#define STM32_TIM_CR1_ARPE (1U << 7) + +#define STM32_TIM_CR1_CKD_MASK (3U << 8) +#define STM32_TIM_CR1_CKD(n) ((n) << 8) + +#define STM32_TIM_CR1_UIFREMAP (1U << 11) +/** @} */ + +/** + * @name TIM_CR2 register + * @{ + */ +#define STM32_TIM_CR2_CCPC (1U << 0) +#define STM32_TIM_CR2_CCUS (1U << 2) +#define STM32_TIM_CR2_CCDS (1U << 3) + +#define STM32_TIM_CR2_MMS_MASK (7U << 4) +#define STM32_TIM_CR2_MMS(n) ((n) << 4) + +#define STM32_TIM_CR2_TI1S (1U << 7) +#define STM32_TIM_CR2_OIS1 (1U << 8) +#define STM32_TIM_CR2_OIS1N (1U << 9) +#define STM32_TIM_CR2_OIS2 (1U << 10) +#define STM32_TIM_CR2_OIS2N (1U << 11) +#define STM32_TIM_CR2_OIS3 (1U << 12) +#define STM32_TIM_CR2_OIS3N (1U << 13) +#define STM32_TIM_CR2_OIS4 (1U << 14) +#define STM32_TIM_CR2_OIS5 (1U << 16) +#define STM32_TIM_CR2_OIS6 (1U << 18) + +#define STM32_TIM_CR2_MMS2_MASK (15U << 20) +#define STM32_TIM_CR2_MMS2(n) ((n) << 20) +/** @} */ + +/** + * @name TIM_SMCR register + * @{ + */ +#define STM32_TIM_SMCR_SMS_MASK ((7U << 0) | (1U << 16)) +#define STM32_TIM_SMCR_SMS(n) ((((n) & 7) << 0) | \ + (((n) >> 3) << 16)) + +#define STM32_TIM_SMCR_OCCS (1U << 3) + +#define STM32_TIM_SMCR_TS_MASK (7U << 4) +#define STM32_TIM_SMCR_TS(n) ((n) << 4) + +#define STM32_TIM_SMCR_MSM (1U << 7) + +#define STM32_TIM_SMCR_ETF_MASK (15U << 8) +#define STM32_TIM_SMCR_ETF(n) ((n) << 8) + +#define STM32_TIM_SMCR_ETPS_MASK (3U << 12) +#define STM32_TIM_SMCR_ETPS(n) ((n) << 12) + +#define STM32_TIM_SMCR_ECE (1U << 14) +#define STM32_TIM_SMCR_ETP (1U << 15) +/** @} */ + +/** + * @name TIM_DIER register + * @{ + */ +#define STM32_TIM_DIER_UIE (1U << 0) +#define STM32_TIM_DIER_CC1IE (1U << 1) +#define STM32_TIM_DIER_CC2IE (1U << 2) +#define STM32_TIM_DIER_CC3IE (1U << 3) +#define STM32_TIM_DIER_CC4IE (1U << 4) +#define STM32_TIM_DIER_COMIE (1U << 5) +#define STM32_TIM_DIER_TIE (1U << 6) +#define STM32_TIM_DIER_BIE (1U << 7) +#define STM32_TIM_DIER_UDE (1U << 8) +#define STM32_TIM_DIER_CC1DE (1U << 9) +#define STM32_TIM_DIER_CC2DE (1U << 10) +#define STM32_TIM_DIER_CC3DE (1U << 11) +#define STM32_TIM_DIER_CC4DE (1U << 12) +#define STM32_TIM_DIER_COMDE (1U << 13) +#define STM32_TIM_DIER_TDE (1U << 14) + +#define STM32_TIM_DIER_IRQ_MASK (STM32_TIM_DIER_UIE | \ + STM32_TIM_DIER_CC1IE | \ + STM32_TIM_DIER_CC2IE | \ + STM32_TIM_DIER_CC3IE | \ + STM32_TIM_DIER_CC4IE | \ + STM32_TIM_DIER_COMIE | \ + STM32_TIM_DIER_TIE | \ + STM32_TIM_DIER_BIE) + +/** @} */ + +/** + * @name TIM_SR register + * @{ + */ +#define STM32_TIM_SR_UIF (1U << 0) +#define STM32_TIM_SR_CC1IF (1U << 1) +#define STM32_TIM_SR_CC2IF (1U << 2) +#define STM32_TIM_SR_CC3IF (1U << 3) +#define STM32_TIM_SR_CC4IF (1U << 4) +#define STM32_TIM_SR_COMIF (1U << 5) +#define STM32_TIM_SR_TIF (1U << 6) +#define STM32_TIM_SR_BIF (1U << 7) +#define STM32_TIM_SR_B2IF (1U << 8) +#define STM32_TIM_SR_CC1OF (1U << 9) +#define STM32_TIM_SR_CC2OF (1U << 10) +#define STM32_TIM_SR_CC3OF (1U << 11) +#define STM32_TIM_SR_CC4OF (1U << 12) +#define STM32_TIM_SR_CC5IF (1U << 16) +#define STM32_TIM_SR_CC6IF (1U << 17) +/** @} */ + +/** + * @name TIM_EGR register + * @{ + */ +#define STM32_TIM_EGR_UG (1U << 0) +#define STM32_TIM_EGR_CC1G (1U << 1) +#define STM32_TIM_EGR_CC2G (1U << 2) +#define STM32_TIM_EGR_CC3G (1U << 3) +#define STM32_TIM_EGR_CC4G (1U << 4) +#define STM32_TIM_EGR_COMG (1U << 5) +#define STM32_TIM_EGR_TG (1U << 6) +#define STM32_TIM_EGR_BG (1U << 7) +#define STM32_TIM_EGR_B2G (1U << 8) +/** @} */ + +/** + * @name TIM_CCMR1 register (output) + * @{ + */ +#define STM32_TIM_CCMR1_CC1S_MASK (3U << 0) +#define STM32_TIM_CCMR1_CC1S(n) ((n) << 0) + +#define STM32_TIM_CCMR1_OC1FE (1U << 2) +#define STM32_TIM_CCMR1_OC1PE (1U << 3) + +#define STM32_TIM_CCMR1_OC1M_MASK ((7U << 4) | (1U << 16)) +#define STM32_TIM_CCMR1_OC1M(n) ((((n) & 7) << 4) | \ + (((n) >> 3) << 16)) + +#define STM32_TIM_CCMR1_OC1CE (1U << 7) + +#define STM32_TIM_CCMR1_CC2S_MASK (3U << 8) +#define STM32_TIM_CCMR1_CC2S(n) ((n) << 8) + +#define STM32_TIM_CCMR1_OC2FE (1U << 10) +#define STM32_TIM_CCMR1_OC2PE (1U << 11) + +#define STM32_TIM_CCMR1_OC2M_MASK ((7U << 12) | (1U << 24)) +#define STM32_TIM_CCMR1_OC2M(n) ((((n) & 7) << 12) | \ + (((n) >> 3) << 24)) + +#define STM32_TIM_CCMR1_OC2CE (1U << 15) +/** @} */ + +/** + * @name CCMR1 register (input) + * @{ + */ +#define STM32_TIM_CCMR1_IC1PSC_MASK (3U << 2) +#define STM32_TIM_CCMR1_IC1PSC(n) ((n) << 2) + +#define STM32_TIM_CCMR1_IC1F_MASK (15U << 4) +#define STM32_TIM_CCMR1_IC1F(n) ((n) << 4) + +#define STM32_TIM_CCMR1_IC2PSC_MASK (3U << 10) +#define STM32_TIM_CCMR1_IC2PSC(n) ((n) << 10) + +#define STM32_TIM_CCMR1_IC2F_MASK (15U << 12) +#define STM32_TIM_CCMR1_IC2F(n) ((n) << 12) +/** @} */ + +/** + * @name TIM_CCMR2 register (output) + * @{ + */ +#define STM32_TIM_CCMR2_CC3S_MASK (3U << 0) +#define STM32_TIM_CCMR2_CC3S(n) ((n) << 0) + +#define STM32_TIM_CCMR2_OC3FE (1U << 2) +#define STM32_TIM_CCMR2_OC3PE (1U << 3) + +#define STM32_TIM_CCMR2_OC3M_MASK ((7U << 4) | (1U << 16)) +#define STM32_TIM_CCMR2_OC3M(n) ((((n) & 7) << 4) | \ + (((n) >> 3) << 16)) + +#define STM32_TIM_CCMR2_OC3CE (1U << 7) + +#define STM32_TIM_CCMR2_CC4S_MASK (3U << 8) +#define STM32_TIM_CCMR2_CC4S(n) ((n) << 8) + +#define STM32_TIM_CCMR2_OC4FE (1U << 10) +#define STM32_TIM_CCMR2_OC4PE (1U << 11) + +#define STM32_TIM_CCMR2_OC4M_MASK ((7U << 12) | (1U << 24)) +#define STM32_TIM_CCMR2_OC4M(n) ((((n) & 7) << 12) | \ + (((n) >> 3) << 24)) + +#define STM32_TIM_CCMR2_OC4CE (1U << 15) +/** @} */ + +/** + * @name TIM_CCMR2 register (input) + * @{ + */ +#define STM32_TIM_CCMR2_IC3PSC_MASK (3U << 2) +#define STM32_TIM_CCMR2_IC3PSC(n) ((n) << 2) + +#define STM32_TIM_CCMR2_IC3F_MASK (15U << 4) +#define STM32_TIM_CCMR2_IC3F(n) ((n) << 4) + +#define STM32_TIM_CCMR2_IC4PSC_MASK (3U << 10) +#define STM32_TIM_CCMR2_IC4PSC(n) ((n) << 10) + +#define STM32_TIM_CCMR2_IC4F_MASK (15U << 12) +#define STM32_TIM_CCMR2_IC4F(n) ((n) << 12) +/** @} */ + +/** + * @name TIM_CCER register + * @{ + */ +#define STM32_TIM_CCER_CC1E (1U << 0) +#define STM32_TIM_CCER_CC1P (1U << 1) +#define STM32_TIM_CCER_CC1NE (1U << 2) +#define STM32_TIM_CCER_CC1NP (1U << 3) +#define STM32_TIM_CCER_CC2E (1U << 4) +#define STM32_TIM_CCER_CC2P (1U << 5) +#define STM32_TIM_CCER_CC2NE (1U << 6) +#define STM32_TIM_CCER_CC2NP (1U << 7) +#define STM32_TIM_CCER_CC3E (1U << 8) +#define STM32_TIM_CCER_CC3P (1U << 9) +#define STM32_TIM_CCER_CC3NE (1U << 10) +#define STM32_TIM_CCER_CC3NP (1U << 11) +#define STM32_TIM_CCER_CC4E (1U << 12) +#define STM32_TIM_CCER_CC4P (1U << 13) +#define STM32_TIM_CCER_CC4NE (1U << 14) +#define STM32_TIM_CCER_CC4NP (1U << 15) +#define STM32_TIM_CCER_CC5E (1U << 16) +#define STM32_TIM_CCER_CC5P (1U << 17) +#define STM32_TIM_CCER_CC6E (1U << 20) +#define STM32_TIM_CCER_CC6P (1U << 21) +/** @} */ + +/** + * @name TIM_CNT register + * @{ + */ +#define STM32_TIM_CNT_UIFCPY (1U << 31) +/** @} */ + +/** + * @name TIM_BDTR register + * @{ + */ +#define STM32_TIM_BDTR_DTG_MASK (255U << 0) +#define STM32_TIM_BDTR_DTG(n) ((n) << 0) + +#define STM32_TIM_BDTR_LOCK_MASK (3U << 8) +#define STM32_TIM_BDTR_LOCK(n) ((n) << 8) + +#define STM32_TIM_BDTR_OSSI (1U << 10) +#define STM32_TIM_BDTR_OSSR (1U << 11) +#define STM32_TIM_BDTR_BKE (1U << 12) +#define STM32_TIM_BDTR_BKP (1U << 13) +#define STM32_TIM_BDTR_AOE (1U << 14) +#define STM32_TIM_BDTR_MOE (1U << 15) + +#define STM32_TIM_BDTR_BKF_MASK (15U << 16) +#define STM32_TIM_BDTR_BKF(n) ((n) << 16) +#define STM32_TIM_BDTR_BK2F_MASK (15U << 20) +#define STM32_TIM_BDTR_BK2F(n) ((n) << 20) + +#define STM32_TIM_BDTR_BK2E (1U << 24) +#define STM32_TIM_BDTR_BK2P (1U << 25) +/** @} */ + +/** + * @name TIM_DCR register + * @{ + */ +#define STM32_TIM_DCR_DBA_MASK (31U << 0) +#define STM32_TIM_DCR_DBA(n) ((n) << 0) + +#define STM32_TIM_DCR_DBL_MASK (31U << 8) +#define STM32_TIM_DCR_DBL(n) ((n) << 8) +/** @} */ + +/** + * @name TIM16_OR register + * @{ + */ +#define STM32_TIM16_OR_TI1_RMP_MASK (3U << 6) +#define STM32_TIM16_OR_TI1_RMP(n) ((n) << 6) +/** @} */ + +/** + * @name TIM_OR register + * @{ + */ +#define STM32_TIM_OR_ETR_RMP_MASK (15U << 0) +#define STM32_TIM_OR_ETR_RMP(n) ((n) << 0) +/** @} */ + +/** + * @name TIM_CCMR3 register + * @{ + */ +#define STM32_TIM_CCMR3_OC5FE (1U << 2) +#define STM32_TIM_CCMR3_OC5PE (1U << 3) + +#define STM32_TIM_CCMR3_OC5M_MASK ((7U << 4) | (1U << 16)) +#define STM32_TIM_CCMR3_OC5M(n) ((((n) & 7) << 4) | \ + (((n) >> 2) << 16)) + +#define STM32_TIM_CCMR3_OC5CE (1U << 7) + +#define STM32_TIM_CCMR3_OC6FE (1U << 10) +#define STM32_TIM_CCMR3_OC6PE (1U << 11) + +#define STM32_TIM_CCMR3_OC6M_MASK ((7U << 12) | (1U << 24)) +#define STM32_TIM_CCMR3_OC6M(n) ((((n) & 7) << 12) | \ + (((n) >> 2) << 24)) + +#define STM32_TIM_CCMR3_OC6CE (1U << 15) +/** @} */ + +/** + * @name LPTIM_ISR register + * @{ + */ +#define STM32_LPTIM_ISR_CMPM (1U << 0) +#define STM32_LPTIM_ISR_ARRM (1U << 1) +#define STM32_LPTIM_ISR_EXTTRIG (1U << 2) +#define STM32_LPTIM_ISR_CMPOK (1U << 3) +#define STM32_LPTIM_ISR_ARROK (1U << 4) +#define STM32_LPTIM_ISR_UP (1U << 5) +#define STM32_LPTIM_ISR_DOWN (1U << 6) +/** @} */ + +/** + * @name LPTIM_ICR register + * @{ + */ +#define STM32_LPTIM_ICR_CMPMCF (1U << 0) +#define STM32_LPTIM_ICR_ARRMCF (1U << 1) +#define STM32_LPTIM_ICR_EXTTRIGCF (1U << 2) +#define STM32_LPTIM_ICR_CMPOKCF (1U << 3) +#define STM32_LPTIM_ICR_ARROKCF (1U << 4) +#define STM32_LPTIM_ICR_UPCF (1U << 5) +#define STM32_LPTIM_ICR_DOWNCF (1U << 6) +/** @} */ + +/** + * @name LPTIM_IER register + * @{ + */ +#define STM32_LPTIM_IER_CMPMIE (1U << 0) +#define STM32_LPTIM_IER_ARRMIE (1U << 1) +#define STM32_LPTIM_IER_EXTTRIGIE (1U << 2) +#define STM32_LPTIM_IER_CMPOKIE (1U << 3) +#define STM32_LPTIM_IER_ARROKIE (1U << 4) +#define STM32_LPTIM_IER_UPIE (1U << 5) +#define STM32_LPTIM_IER_DOWNIE (1U << 6) +/** @} */ + +/** + * @name LPTIM_CFGR register + * @{ + */ +#define STM32_LPTIM_CFGR_CKSEL (1U << 0) +#define STM32_LPTIM_CFGR_CKPOL_MASK (3U << 1) +#define STM32_LPTIM_CFGR_CKPOL(n) ((n) << 1) +#define STM32_LPTIM_CFGR_CKFLT_MASK (3U << 3) +#define STM32_LPTIM_CFGR_CKFLT(n) ((n) << 3) +#define STM32_LPTIM_CFGR_TRGFLT_MASK (3U << 6) +#define STM32_LPTIM_CFGR_TRGFLT(n) ((n) << 6) +#define STM32_LPTIM_CFGR_PRESC_MASK (7U << 9) +#define STM32_LPTIM_CFGR_PRESC(n) ((n) << 9) +#define STM32_LPTIM_CFGR_TRIGSEL_MASK (7U << 13) +#define STM32_LPTIM_CFGR_TRIGSEL(n) ((n) << 13) +#define STM32_LPTIM_CFGR_TRIGEN_MASK (3U << 17) +#define STM32_LPTIM_CFGR_TRIGEN(n) ((n) << 17) +#define STM32_LPTIM_CFGR_TIMOUT (1U << 19) +#define STM32_LPTIM_CFGR_WAVE (1U << 20) +#define STM32_LPTIM_CFGR_WAVPOL (1U << 21) +#define STM32_LPTIM_CFGR_PRELOAD (1U << 22) +#define STM32_LPTIM_CFGR_COUNTMODE (1U << 23) +#define STM32_LPTIM_CFGR_ENC (1U << 24) +/** @} */ + +/** + * @name LPTIM_CR register + * @{ + */ +#define STM32_LPTIM_CR_ENABLE (1U << 0) +#define STM32_LPTIM_CR_SNGSTRT (1U << 1) +#define STM32_LPTIM_CR_CNTSTRT (1U << 2) +/** @} */ + +/** + * @name LPTIM_OR register + * @{ + */ +#define STM32_LPTIM_OR_0 (1U << 0) +#define STM32_LPTIM_OR_1 (1U << 1) +/** @} */ + +/** + * @name TIM units references + * @{ + */ +#define STM32_TIM1 ((stm32_tim_t *)TIM1_BASE) +#define STM32_TIM2 ((stm32_tim_t *)TIM2_BASE) +#define STM32_TIM3 ((stm32_tim_t *)TIM3_BASE) +#define STM32_TIM4 ((stm32_tim_t *)TIM4_BASE) +#define STM32_TIM5 ((stm32_tim_t *)TIM5_BASE) +#define STM32_TIM6 ((stm32_tim_t *)TIM6_BASE) +#define STM32_TIM7 ((stm32_tim_t *)TIM7_BASE) +#define STM32_TIM8 ((stm32_tim_t *)TIM8_BASE) +#define STM32_TIM9 ((stm32_tim_t *)TIM9_BASE) +#define STM32_TIM10 ((stm32_tim_t *)TIM10_BASE) +#define STM32_TIM11 ((stm32_tim_t *)TIM11_BASE) +#define STM32_TIM12 ((stm32_tim_t *)TIM12_BASE) +#define STM32_TIM13 ((stm32_tim_t *)TIM13_BASE) +#define STM32_TIM14 ((stm32_tim_t *)TIM14_BASE) +#define STM32_TIM15 ((stm32_tim_t *)TIM15_BASE) +#define STM32_TIM16 ((stm32_tim_t *)TIM16_BASE) +#define STM32_TIM17 ((stm32_tim_t *)TIM17_BASE) +#define STM32_TIM18 ((stm32_tim_t *)TIM18_BASE) +#define STM32_TIM19 ((stm32_tim_t *)TIM19_BASE) +#define STM32_TIM20 ((stm32_tim_t *)TIM20_BASE) +#define STM32_TIM21 ((stm32_tim_t *)TIM21_BASE) +#define STM32_TIM22 ((stm32_tim_t *)TIM22_BASE) + +#define STM32_LPTIM1 ((stm32_lptim_t *)LPTIM1_BASE) +#define STM32_LPTIM2 ((stm32_lptim_t *)LPTIM2_BASE) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief STM32 TIM registers block. + * @note This is the most general known form, not all timers have + * necessarily all registers and bits. + */ +typedef struct { + volatile uint32_t CR1; + volatile uint32_t CR2; + volatile uint32_t SMCR; + volatile uint32_t DIER; + volatile uint32_t SR; + volatile uint32_t EGR; + volatile uint32_t CCMR1; + volatile uint32_t CCMR2; + volatile uint32_t CCER; + volatile uint32_t CNT; + volatile uint32_t PSC; + volatile uint32_t ARR; + volatile uint32_t RCR; + volatile uint32_t CCR[4]; + volatile uint32_t BDTR; + volatile uint32_t DCR; + volatile uint32_t DMAR; + volatile uint32_t OR; + volatile uint32_t CCMR3; + volatile uint32_t CCXR[2]; +} stm32_tim_t; + +/** + * @brief STM32 LPTIM registers block. + * @note This is the most general known form, not all timers have + * necessarily all registers and bits. + */ +typedef struct { + volatile uint32_t ISR; + volatile uint32_t ICR; + volatile uint32_t IER; + volatile uint32_t CFGR; + volatile uint32_t CR; + volatile uint32_t CMP; + volatile uint32_t ARR; + volatile uint32_t CNT; + volatile uint32_t OR; +} stm32_lptim_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#endif /* STM32_TIM_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1.inc new file mode 100644 index 0000000..eebaa8b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1.inc @@ -0,0 +1,172 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim1_tim15_tim16_tim17.inc + * @brief Shared TIM1 handler. + * + * @addtogroup STM32_TIM1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM1) +#error "STM32_HAS_TIM1 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM1) +#define STM32_GPT_USE_TIM1 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM1) +#define STM32_ICU_USE_TIM1 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM1) +#define STM32_PWM_USE_TIM1 FALSE +#endif +#if !defined(STM32_ST_USE_TIM1) +#define STM32_ST_USE_TIM1 FALSE +#endif + +#if STM32_HAS_TIM1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM1_UP_PRIORITY) +#error "STM32_IRQ_TIM1_UP_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_CC_PRIORITY) +#error "STM32_IRQ_TIM1_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_UP_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_UP_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM1 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim1_irq_init(void) { +#if defined(STM32_TIM1_IS_USED) + nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_IRQ_TIM1_UP_PRIORITY); + nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_IRQ_TIM1_CC_PRIORITY); +#endif +} + +static inline void tim1_irq_deinit(void) { +#if defined(STM32_TIM1_IS_USED) + nvicDisableVector(STM32_TIM1_UP_NUMBER); + nvicDisableVector(STM32_TIM1_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM1_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM1-UP interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM1 + gpt_lld_serve_interrupt(&GPTD1); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM1 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief TIM1-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#endif +#if 1 + /* Not used by ST.*/ +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim14.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim14.inc new file mode 100644 index 0000000..920af71 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim14.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim14.inc + * @brief Shared TIM14 handler. + * + * @addtogroup STM32_TIM14_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM14) +#error "STM32_HAS_TIM14 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM14) +#define STM32_GPT_USE_TIM14 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM14) +#define STM32_ICU_USE_TIM14 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM14) +#define STM32_PWM_USE_TIM14 FALSE +#endif +#if !defined(STM32_ST_USE_TIM14) +#define STM32_ST_USE_TIM14 FALSE +#endif + +#if STM32_HAS_TIM14 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM14_PRIORITY) +#error "STM32_IRQ_TIM14_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM14_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM14_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM14 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim14_irq_init(void) { +#if defined(STM32_TIM14_IS_USED) + nvicEnableVector(STM32_TIM14_NUMBER, STM32_IRQ_TIM14_PRIORITY); +#endif +} + +static inline void tim14_irq_deinit(void) { +#if defined(STM32_TIM14_IS_USED) + nvicDisableVector(STM32_TIM14_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM14_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM14 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM14_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM14 + gpt_lld_serve_interrupt(&GPTD14); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM14 + icu_lld_serve_interrupt(&ICUD14); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM14 + pwm_lld_serve_interrupt(&PWMD14); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM14 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim15.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim15.inc new file mode 100644 index 0000000..da90531 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim15.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim15.inc + * @brief Shared TIM15 handler. + * + * @addtogroup STM32_TIM15_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM15) +#error "STM32_HAS_TIM15 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM15) +#define STM32_GPT_USE_TIM15 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM15) +#define STM32_ICU_USE_TIM15 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM15) +#define STM32_PWM_USE_TIM15 FALSE +#endif +#if !defined(STM32_ST_USE_TIM15) +#define STM32_ST_USE_TIM15 FALSE +#endif + +#if STM32_HAS_TIM15 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM15_PRIORITY) +#error "STM32_IRQ_TIM15_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM15_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM15_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM15 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim15_irq_init(void) { +#if defined(STM32_TIM15_IS_USED) + nvicEnableVector(STM32_TIM15_NUMBER, STM32_IRQ_TIM15_PRIORITY); +#endif +} + +static inline void tim15_irq_deinit(void) { +#if defined(STM32_TIM15_IS_USED) + nvicDisableVector(STM32_TIM15_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM15_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM15 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM15_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM15 + gpt_lld_serve_interrupt(&GPTD15); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM15 + icu_lld_serve_interrupt(&ICUD15); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM15 + pwm_lld_serve_interrupt(&PWMD15); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM15 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim16.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim16.inc new file mode 100644 index 0000000..56517b1 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim16.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim16.inc + * @brief Shared TIM16 handler. + * + * @addtogroup STM32_TIM16_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM16) +#error "STM32_HAS_TIM16 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM16) +#define STM32_GPT_USE_TIM16 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM16) +#define STM32_ICU_USE_TIM16 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM16) +#define STM32_PWM_USE_TIM16 FALSE +#endif +#if !defined(STM32_ST_USE_TIM16) +#define STM32_ST_USE_TIM16 FALSE +#endif + +#if STM32_HAS_TIM16 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM16_PRIORITY) +#error "STM32_IRQ_TIM16_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM16_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM16_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM16 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim16_irq_init(void) { +#if defined(STM32_TIM16_IS_USED) + nvicEnableVector(STM32_TIM16_NUMBER, STM32_IRQ_TIM16_PRIORITY); +#endif +} + +static inline void tim16_irq_deinit(void) { +#if defined(STM32_TIM16_IS_USED) + nvicDisableVector(STM32_TIM16_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM16_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM16 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM16_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM16 + gpt_lld_serve_interrupt(&GPTD16); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM16 + icu_lld_serve_interrupt(&ICUD16); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM16 + pwm_lld_serve_interrupt(&PWMD16); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM16 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim17.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim17.inc new file mode 100644 index 0000000..eb6725b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim17.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim17.inc + * @brief Shared TIM17 handler. + * + * @addtogroup STM32_TIM17_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM17) +#error "STM32_HAS_TIM17 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM17) +#define STM32_GPT_USE_TIM17 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM17) +#define STM32_ICU_USE_TIM17 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM17) +#define STM32_PWM_USE_TIM17 FALSE +#endif +#if !defined(STM32_ST_USE_TIM17) +#define STM32_ST_USE_TIM17 FALSE +#endif + +#if STM32_HAS_TIM17 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM17_PRIORITY) +#error "STM32_IRQ_TIM17_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM17_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM17_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM17 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim17_irq_init(void) { +#if defined(STM32_TIM17_IS_USED) + nvicEnableVector(STM32_TIM17_NUMBER, STM32_IRQ_TIM17_PRIORITY); +#endif +} + +static inline void tim17_irq_deinit(void) { +#if defined(STM32_TIM17_IS_USED) + nvicDisableVector(STM32_TIM17_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM17_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM17 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM17_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM17 + gpt_lld_serve_interrupt(&GPTD17); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM17 + icu_lld_serve_interrupt(&ICUD17); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM17 + pwm_lld_serve_interrupt(&PWMD17); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM17 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_15_16_17.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_15_16_17.inc new file mode 100644 index 0000000..c40da37 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_15_16_17.inc @@ -0,0 +1,341 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim1_15_16_17.inc + * @brief Shared TIM1, TIM15, TIM16, TIM17 handler. + * + * @addtogroup STM32_TIM1_TIM15_TIM16_TIM17_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM1) +#error "STM32_HAS_TIM1 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM15) +#error "STM32_HAS_TIM15 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM16) +#error "STM32_HAS_TIM16 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM17) +#error "STM32_HAS_TIM17 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM1) +#define STM32_GPT_USE_TIM1 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM1) +#define STM32_ICU_USE_TIM1 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM1) +#define STM32_PWM_USE_TIM1 FALSE +#endif +#if !defined(STM32_ST_USE_TIM1) +#define STM32_ST_USE_TIM1 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM15) +#define STM32_GPT_USE_TIM15 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM15) +#define STM32_ICU_USE_TIM15 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM15) +#define STM32_PWM_USE_TIM15 FALSE +#endif +#if !defined(STM32_ST_USE_TIM15) +#define STM32_ST_USE_TIM15 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM16) +#define STM32_GPT_USE_TIM16 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM16) +#define STM32_ICU_USE_TIM16 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM16) +#define STM32_PWM_USE_TIM16 FALSE +#endif +#if !defined(STM32_ST_USE_TIM16) +#define STM32_ST_USE_TIM16 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM17) +#define STM32_GPT_USE_TIM17 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM17) +#define STM32_ICU_USE_TIM17 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM17) +#define STM32_PWM_USE_TIM17 FALSE +#endif +#if !defined(STM32_ST_USE_TIM17) +#define STM32_ST_USE_TIM17 FALSE +#endif + +#if STM32_HAS_TIM1 || STM32_HAS_TIM15 || STM32_HAS_TIM16 || STM32_HAS_TIM17 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM1_BRK_TIM15_PRIORITY) +#error "STM32_IRQ_TIM1_BRK_TIM15_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_UP_TIM16_PRIORITY) +#error "STM32_IRQ_TIM1_UP_TIM16_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY) +#error "STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_CC_PRIORITY) +#error "STM32_IRQ_TIM1_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_BRK_TIM15_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_BRK_TIM15_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_UP_TIM16_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_UP_TIM16_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM1 || STM32_HAS_TIM15 || STM32_HAS_TIM16 || STM32_HAS_TIM17 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim1_tim15_tim16_tim17_irq_init(void) { +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM15_IS_USED) + nvicEnableVector(STM32_TIM1_BRK_TIM15_NUMBER, + STM32_IRQ_TIM1_BRK_TIM15_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM16_IS_USED) + nvicEnableVector(STM32_TIM1_UP_TIM16_NUMBER, + STM32_IRQ_TIM1_UP_TIM16_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM17_IS_USED) + nvicEnableVector(STM32_TIM1_TRGCO_TIM17_NUMBER, + STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) + nvicEnableVector(STM32_TIM1_CC_NUMBER, + STM32_IRQ_TIM1_CC_PRIORITY); +#endif +} + +static inline void tim1_tim15_tim16_tim17_irq_deinit(void) { +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM15_IS_USED) + nvicDisableVector(STM32_TIM1_BRK_TIM15_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM16_IS_USED) + nvicDisableVector(STM32_TIM1_UP_TIM16_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM17_IS_USED) + nvicDisableVector(STM32_TIM1_TRGCO_TIM17_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) + nvicDisableVector(STM32_TIM1_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM15_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-BRK, TIM15 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_BRK_TIM15_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM15 + gpt_lld_serve_interrupt(&GPTD15); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM15 + icu_lld_serve_interrupt(&ICUD15); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM15 + pwm_lld_serve_interrupt(&PWMD15); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM15 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM16_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-UP, TIM16 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_TIM16_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM1 + gpt_lld_serve_interrupt(&GPTD1); +#endif +#if STM32_GPT_USE_TIM16 + gpt_lld_serve_interrupt(&GPTD16); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#if STM32_PWM_USE_TIM16 + pwm_lld_serve_interrupt(&PWMD16); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM1 + st_lld_serve_interrupt(); +#endif +#if STM32_ST_USE_TIM16 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM17_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-TRG-COM, TIM17 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_TRGCO_TIM17_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM17 + gpt_lld_serve_interrupt(&GPTD17); +#endif +#endif +#if HAL_USE_ICU + /* Not used by ICU.*/ +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM17 + pwm_lld_serve_interrupt(&PWMD17); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM17 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM1-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#endif +#if 1 + /* Not used by ST.*/ +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_9_10_11.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_9_10_11.inc new file mode 100644 index 0000000..bebcf54 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_9_10_11.inc @@ -0,0 +1,343 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim1_9_10_11.inc + * @brief Shared TIM1, TIM9, TIM10, TIM11 handler. + * + * @addtogroup STM32_TIM1_TIM9_TIM10_TIM11_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM1) +#error "STM32_HAS_TIM1 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM9) +#error "STM32_HAS_TIM9 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM10) +#error "STM32_HAS_TIM10 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM11) +#error "STM32_HAS_TIM11 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM1) +#define STM32_GPT_USE_TIM1 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM1) +#define STM32_ICU_USE_TIM1 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM1) +#define STM32_PWM_USE_TIM1 FALSE +#endif +#if !defined(STM32_ST_USE_TIM1) +#define STM32_ST_USE_TIM1 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM9) +#define STM32_GPT_USE_TIM9 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM9) +#define STM32_ICU_USE_TIM9 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM9) +#define STM32_PWM_USE_TIM9 FALSE +#endif +#if !defined(STM32_ST_USE_TIM9) +#define STM32_ST_USE_TIM9 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM10) +#define STM32_GPT_USE_TIM10 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM10) +#define STM32_ICU_USE_TIM10 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM10) +#define STM32_PWM_USE_TIM10 FALSE +#endif +#if !defined(STM32_ST_USE_TIM10) +#define STM32_ST_USE_TIM10 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM11) +#define STM32_GPT_USE_TIM11 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM11) +#define STM32_ICU_USE_TIM11 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM11) +#define STM32_PWM_USE_TIM11 FALSE +#endif +#if !defined(STM32_ST_USE_TIM11) +#define STM32_ST_USE_TIM11 FALSE +#endif + +#if STM32_HAS_TIM1 || STM32_HAS_TIM9 || STM32_HAS_TIM10 || STM32_HAS_TIM11 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM1_BRK_TIM9_PRIORITY) +#error "STM32_IRQ_TIM1_BRK_TIM9_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_UP_TIM10_PRIORITY) +#error "STM32_IRQ_TIM1_UP_TIM10_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY) +#error "STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_CC_PRIORITY) +#error "STM32_IRQ_TIM1_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_BRK_TIM9_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_BRK_TIM9_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_UP_TIM10_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_UP_TIM10_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM1 || STM32_HAS_TIM9 || STM32_HAS_TIM10 || STM32_HAS_TIM11 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim1_tim9_tim10_tim11_irq_init(void) { +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM9_IS_USED) + nvicEnableVector(STM32_TIM1_BRK_TIM9_NUMBER, + STM32_IRQ_TIM1_BRK_TIM9_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM10_IS_USED) + nvicEnableVector(STM32_TIM1_UP_TIM10_NUMBER, + STM32_IRQ_TIM1_UP_TIM10_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM11_IS_USED) + nvicEnableVector(STM32_TIM1_TRGCO_TIM11_NUMBER, + STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) + nvicEnableVector(STM32_TIM1_CC_NUMBER, + STM32_IRQ_TIM1_CC_PRIORITY); +#endif +} + +static inline void tim1_tim9_tim10_tim11_irq_deinit(void) { +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM9_IS_USED) + nvicDisableVector(STM32_TIM1_BRK_TIM9_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM10_IS_USED) + nvicDisableVector(STM32_TIM1_UP_TIM10_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM11_IS_USED) + nvicDisableVector(STM32_TIM1_TRGCO_TIM11_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) + nvicDisableVector(STM32_TIM1_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM19_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-BRK, TIM9 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_BRK_TIM9_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM9 + gpt_lld_serve_interrupt(&GPTD9); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM9 + icu_lld_serve_interrupt(&ICUD9); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM9 + pwm_lld_serve_interrupt(&PWMD9); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM9 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM10_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-UP, TIM10 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_TIM10_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM1 + gpt_lld_serve_interrupt(&GPTD1); +#endif +#if STM32_GPT_USE_TIM10 + gpt_lld_serve_interrupt(&GPTD10); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#if STM32_ICU_USE_TIM10 + icu_lld_serve_interrupt(&ICUD10); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#if STM32_PWM_USE_TIM10 + pwm_lld_serve_interrupt(&PWMD10); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM1 + st_lld_serve_interrupt(); +#endif +#if STM32_ST_USE_TIM10 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM11_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-TRG-COM, TIM11 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_TRGCO_TIM11_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM11 + gpt_lld_serve_interrupt(&GPTD11); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM11 + icu_lld_serve_interrupt(&ICUD11); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM11 + pwm_lld_serve_interrupt(&PWMD11); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM11 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) +/** + * @brief TIM1-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim2.inc new file mode 100644 index 0000000..435deae --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim2.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim2.inc + * @brief Shared TIM2 handler. + * + * @addtogroup STM32_TIM2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM2) +#error "STM32_HAS_TIM2 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM2) +#define STM32_GPT_USE_TIM2 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM2) +#define STM32_ICU_USE_TIM2 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM2) +#define STM32_PWM_USE_TIM2 FALSE +#endif +#if !defined(STM32_ST_USE_TIM2) +#define STM32_ST_USE_TIM2 FALSE +#endif + +#if STM32_HAS_TIM2 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM2_PRIORITY) +#error "STM32_IRQ_TIM2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM2_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM2 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim2_irq_init(void) { +#if defined(STM32_TIM2_IS_USED) + nvicEnableVector(STM32_TIM2_NUMBER, STM32_IRQ_TIM2_PRIORITY); +#endif +} + +static inline void tim2_irq_deinit(void) { +#if defined(STM32_TIM2_IS_USED) + nvicDisableVector(STM32_TIM2_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM2_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM2 + gpt_lld_serve_interrupt(&GPTD2); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM2 + icu_lld_serve_interrupt(&ICUD2); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM2 + pwm_lld_serve_interrupt(&PWMD2); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM2 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim20.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim20.inc new file mode 100644 index 0000000..1b08998 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim20.inc @@ -0,0 +1,170 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim20.inc + * @brief Shared TIM20 handler. + * + * @addtogroup STM32_TIM20_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM20) +#error "STM32_HAS_TIM20 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM20) +#define STM32_GPT_USE_TIM20 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM20) +#define STM32_ICU_USE_TIM20 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM20) +#define STM32_PWM_USE_TIM20 FALSE +#endif +#if !defined(STM32_ST_USE_TIM20) +#define STM32_ST_USE_TIM20 FALSE +#endif + +#if STM32_HAS_TIM20 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM20_UP_PRIORITY) +#error "STM32_IRQ_TIM20_UP_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM20_CC_PRIORITY) +#error "STM32_IRQ_TIM20_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM20_UP_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM20_UP_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM20_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM20_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM20 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim20_irq_init(void) { +#if defined(STM32_TIM20_IS_USED) + nvicEnableVector(STM32_TIM20_UP_NUMBER, STM32_IRQ_TIM20_UP_PRIORITY); + nvicEnableVector(STM32_TIM20_CC_NUMBER, STM32_IRQ_TIM20_CC_PRIORITY); +#endif +} + +static inline void tim20_irq_deinit(void) { +#if defined(STM32_TIM20_IS_USED) + nvicDisableVector(STM32_TIM20_UP_NUMBER); + nvicDisableVector(STM32_TIM20_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM20_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM20-UP interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM20_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM20 + pwm_lld_serve_interrupt(&GPTD20); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM20 + pwm_lld_serve_interrupt(&ICUD20); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM20 + pwm_lld_serve_interrupt(&PWMD20); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM20 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief TIM20-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM20_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if STM32_ICU_USE_TIM20 + pwm_lld_serve_interrupt(&ICUD20); +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM20 + pwm_lld_serve_interrupt(&PWMD20); +#endif +#endif +#if 1 + /* Not used by ST.*/ +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim21.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim21.inc new file mode 100644 index 0000000..4f98960 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim21.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim21.inc + * @brief Shared TIM21 handler. + * + * @addtogroup STM32_TIM21_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM21) +#error "STM32_HAS_TIM21 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM21) +#define STM32_GPT_USE_TIM21 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM21) +#define STM32_ICU_USE_TIM21 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM21) +#define STM32_PWM_USE_TIM21 FALSE +#endif +#if !defined(STM32_ST_USE_TIM21) +#define STM32_ST_USE_TIM21 FALSE +#endif + +#if STM32_HAS_TIM21 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM21_PRIORITY) +#error "STM32_IRQ_TIM21_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM21_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM21_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM21 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim21_irq_init(void) { +#if defined(STM32_TIM21_IS_USED) + nvicEnableVector(STM32_TIM21_NUMBER, STM32_IRQ_TIM21_PRIORITY); +#endif +} + +static inline void tim21_irq_deinit(void) { +#if defined(STM32_TIM21_IS_USED) + nvicDisableVector(STM32_TIM21_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM21_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM21 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM21_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM21 + gpt_lld_serve_interrupt(&GPTD21); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM21 + icu_lld_serve_interrupt(&ICUD21); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM21 + pwm_lld_serve_interrupt(&PWMD21); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM21 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim22.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim22.inc new file mode 100644 index 0000000..05ee7d3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim22.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim22.inc + * @brief Shared TIM22 handler. + * + * @addtogroup STM32_TIM22_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM22) +#error "STM32_HAS_TIM22 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM22) +#define STM32_GPT_USE_TIM22 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM22) +#define STM32_ICU_USE_TIM22 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM22) +#define STM32_PWM_USE_TIM22 FALSE +#endif +#if !defined(STM32_ST_USE_TIM22) +#define STM32_ST_USE_TIM22 FALSE +#endif + +#if STM32_HAS_TIM22 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM22_PRIORITY) +#error "STM32_IRQ_TIM22_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM22_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM22_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM22 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim22_irq_init(void) { +#if defined(STM32_TIM22_IS_USED) + nvicEnableVector(STM32_TIM22_NUMBER, STM32_IRQ_TIM22_PRIORITY); +#endif +} + +static inline void tim22_irq_deinit(void) { +#if defined(STM32_TIM22_IS_USED) + nvicDisableVector(STM32_TIM22_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM22_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM22 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM22_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM22 + gpt_lld_serve_interrupt(&GPTD22); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM22 + icu_lld_serve_interrupt(&ICUD22); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM22 + pwm_lld_serve_interrupt(&PWMD22); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM22 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim3.inc new file mode 100644 index 0000000..4521a92 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim3.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim3.inc + * @brief Shared TIM3 handler. + * + * @addtogroup STM32_TIM3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM3) +#error "STM32_HAS_TIM3 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM3) +#define STM32_GPT_USE_TIM3 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM3) +#define STM32_ICU_USE_TIM3 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM3) +#define STM32_PWM_USE_TIM3 FALSE +#endif +#if !defined(STM32_ST_USE_TIM3) +#define STM32_ST_USE_TIM3 FALSE +#endif + +#if STM32_HAS_TIM3 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM3_PRIORITY) +#error "STM32_IRQ_TIM3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM3_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM3 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim3_irq_init(void) { +#if defined(STM32_TIM3_IS_USED) + nvicEnableVector(STM32_TIM3_NUMBER, STM32_IRQ_TIM3_PRIORITY); +#endif +} + +static inline void tim3_irq_deinit(void) { +#if defined(STM32_TIM3_IS_USED) + nvicDisableVector(STM32_TIM3_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM3_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM3 + gpt_lld_serve_interrupt(&GPTD3); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM3 + icu_lld_serve_interrupt(&ICUD3); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM3 + pwm_lld_serve_interrupt(&PWMD3); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM3 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim4.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim4.inc new file mode 100644 index 0000000..6df48dc --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim4.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim4.inc + * @brief Shared TIM4 handler. + * + * @addtogroup STM32_TIM4_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM4) +#error "STM32_HAS_TIM4 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM4) +#define STM32_GPT_USE_TIM4 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM4) +#define STM32_ICU_USE_TIM4 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM4) +#define STM32_PWM_USE_TIM4 FALSE +#endif +#if !defined(STM32_ST_USE_TIM4) +#define STM32_ST_USE_TIM4 FALSE +#endif + +#if STM32_HAS_TIM4 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM4_PRIORITY) +#error "STM32_IRQ_TIM4_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM4_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM4_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM4 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim4_irq_init(void) { +#if defined(STM32_TIM4_IS_USED) + nvicEnableVector(STM32_TIM4_NUMBER, STM32_IRQ_TIM4_PRIORITY); +#endif +} + +static inline void tim4_irq_deinit(void) { +#if defined(STM32_TIM4_IS_USED) + nvicDisableVector(STM32_TIM4_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM4_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM4 + gpt_lld_serve_interrupt(&GPTD4); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM4 + icu_lld_serve_interrupt(&ICUD4); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM4 + pwm_lld_serve_interrupt(&PWMD4); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM4 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim5.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim5.inc new file mode 100644 index 0000000..35158b3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim5.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim5.inc + * @brief Shared TIM5 handler. + * + * @addtogroup STM32_TIM5_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM5) +#error "STM32_HAS_TIM5 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM5) +#define STM32_GPT_USE_TIM5 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM5) +#define STM32_ICU_USE_TIM5 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM5) +#define STM32_PWM_USE_TIM5 FALSE +#endif +#if !defined(STM32_ST_USE_TIM5) +#define STM32_ST_USE_TIM5 FALSE +#endif + +#if STM32_HAS_TIM5 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM5_PRIORITY) +#error "STM32_IRQ_TIM5_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM5_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM5_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM5 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim5_irq_init(void) { +#if defined(STM32_TIM5_IS_USED) + nvicEnableVector(STM32_TIM5_NUMBER, STM32_IRQ_TIM5_PRIORITY); +#endif +} + +static inline void tim5_irq_deinit(void) { +#if defined(STM32_TIM5_IS_USED) + nvicDisableVector(STM32_TIM5_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM5_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM5 + gpt_lld_serve_interrupt(&GPTD5); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM5 + icu_lld_serve_interrupt(&ICUD5); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM5 + pwm_lld_serve_interrupt(&PWMD5); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM5 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim6.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim6.inc new file mode 100644 index 0000000..200d103 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim6.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim6.inc + * @brief Shared TIM6 handler. + * + * @addtogroup STM32_TIM6_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM6) +#error "STM32_HAS_TIM6 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM6) +#define STM32_GPT_USE_TIM6 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM6) +#define STM32_ICU_USE_TIM6 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM6) +#define STM32_PWM_USE_TIM6 FALSE +#endif +#if !defined(STM32_ST_USE_TIM6) +#define STM32_ST_USE_TIM6 FALSE +#endif + +#if STM32_HAS_TIM6 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM6_PRIORITY) +#error "STM32_IRQ_TIM6_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM6_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM6_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM6 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim6_irq_init(void) { +#if defined(STM32_TIM6_IS_USED) + nvicEnableVector(STM32_TIM6_NUMBER, STM32_IRQ_TIM6_PRIORITY); +#endif +} + +static inline void tim6_irq_deinit(void) { +#if defined(STM32_TIM6_IS_USED) + nvicDisableVector(STM32_TIM6_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM6_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM6 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM6 + gpt_lld_serve_interrupt(&GPTD6); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM6 + icu_lld_serve_interrupt(&ICUD6); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM6 + pwm_lld_serve_interrupt(&PWMD6); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM6 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim7.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim7.inc new file mode 100644 index 0000000..8ea4e0f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim7.inc @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim7.inc + * @brief Shared TIM7 handler. + * + * @addtogroup STM32_TIM7_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM7) +#error "STM32_HAS_TIM7 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM7) +#define STM32_GPT_USE_TIM7 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM7) +#define STM32_ICU_USE_TIM7 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM7) +#define STM32_PWM_USE_TIM7 FALSE +#endif +#if !defined(STM32_ST_USE_TIM7) +#define STM32_ST_USE_TIM7 FALSE +#endif + +#if STM32_HAS_TIM7 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM7_PRIORITY) +#error "STM32_IRQ_TIM7_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM7_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM7_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM7 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim7_irq_init(void) { +#if defined(STM32_TIM7_IS_USED) + nvicEnableVector(STM32_TIM7_NUMBER, STM32_IRQ_TIM7_PRIORITY); +#endif +} + +static inline void tim7_irq_deinit(void) { +#if defined(STM32_TIM7_IS_USED) + nvicDisableVector(STM32_TIM7_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM7_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM7 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM7 + gpt_lld_serve_interrupt(&GPTD7); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM7 + icu_lld_serve_interrupt(&ICUD7); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM7 + pwm_lld_serve_interrupt(&PWMD7); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM7 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8.inc new file mode 100644 index 0000000..db9219c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8.inc @@ -0,0 +1,172 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim8.inc + * @brief Shared TIM8 handler. + * + * @addtogroup STM32_TIM8_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM8) +#error "STM32_HAS_TIM8 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM8) +#define STM32_GPT_USE_TIM8 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM8) +#define STM32_ICU_USE_TIM8 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM8) +#define STM32_PWM_USE_TIM8 FALSE +#endif +#if !defined(STM32_ST_USE_TIM8) +#define STM32_ST_USE_TIM8 FALSE +#endif + +#if STM32_HAS_TIM8 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM8_UP_PRIORITY) +#error "STM32_IRQ_TIM8_UP_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM8_CC_PRIORITY) +#error "STM32_IRQ_TIM8_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_UP_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_UP_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM8 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim8_irq_init(void) { +#if defined(STM32_TIM8_IS_USED) + nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_IRQ_TIM8_UP_PRIORITY); + nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_IRQ_TIM8_CC_PRIORITY); +#endif +} + +static inline void tim8_irq_deinit(void) { +#if defined(STM32_TIM8_IS_USED) + nvicDisableVector(STM32_TIM8_UP_NUMBER); + nvicDisableVector(STM32_TIM8_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM8_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM8-UP interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM8 + gpt_lld_serve_interrupt(&GPTD8); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM8 + icu_lld_serve_interrupt(&ICUD8); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM8 + pwm_lld_serve_interrupt(&PWMD8); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM8 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief TIM8-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM8 + icu_lld_serve_interrupt(&ICUD8); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM8 + pwm_lld_serve_interrupt(&PWMD8); +#endif +#endif +#if 1 + /* Not used by ST.*/ +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8_12_13_14.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8_12_13_14.inc new file mode 100644 index 0000000..fe23514 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8_12_13_14.inc @@ -0,0 +1,343 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file TIMv1/stm32_tim8_12_13_14.inc + * @brief Shared TIM8, TIM12, TIM13, TIM14 handler. + * + * @addtogroup STM32_TIM8_TIM12_TIM13_TIM14_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM8) +#error "STM32_HAS_TIM8 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM12) +#error "STM32_HAS_TIM12 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM13) +#error "STM32_HAS_TIM13 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM14) +#error "STM32_HAS_TIM14 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM8) +#define STM32_GPT_USE_TIM8 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM8) +#define STM32_ICU_USE_TIM8 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM8) +#define STM32_PWM_USE_TIM8 FALSE +#endif +#if !defined(STM32_ST_USE_TIM8) +#define STM32_ST_USE_TIM8 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM12) +#define STM32_GPT_USE_TIM12 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM12) +#define STM32_ICU_USE_TIM12 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM12) +#define STM32_PWM_USE_TIM12 FALSE +#endif +#if !defined(STM32_ST_USE_TIM12) +#define STM32_ST_USE_TIM12 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM13) +#define STM32_GPT_USE_TIM13 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM13) +#define STM32_ICU_USE_TIM13 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM13) +#define STM32_PWM_USE_TIM13 FALSE +#endif +#if !defined(STM32_ST_USE_TIM13) +#define STM32_ST_USE_TIM13 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM14) +#define STM32_GPT_USE_TIM14 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM14) +#define STM32_ICU_USE_TIM14 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM14) +#define STM32_PWM_USE_TIM14 FALSE +#endif +#if !defined(STM32_ST_USE_TIM14) +#define STM32_ST_USE_TIM14 FALSE +#endif + +#if STM32_HAS_TIM8 || STM32_HAS_TIM12 || STM32_HAS_TIM13 || STM32_HAS_TIM14 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM8_BRK_TIM12_PRIORITY) +#error "STM32_IRQ_TIM8_BRK_TIM12_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM8_UP_TIM13_PRIORITY) +#error "STM32_IRQ_TIM8_UP_TIM13_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY) +#error "STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM8_CC_PRIORITY) +#error "STM32_IRQ_TIM8_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_BRK_TIM12_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_BRK_TIM12_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_UP_TIM13_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_UP_TIM13_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM8 || STM32_HAS_TIM12 || STM32_HAS_TIM13 || STM32_HAS_TIM14 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim8_tim12_tim13_tim14_irq_init(void) { +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM12_IS_USED) + nvicEnableVector(STM32_TIM8_BRK_TIM12_NUMBER, + STM32_IRQ_TIM8_BRK_TIM12_PRIORITY); +#endif +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM13_IS_USED) + nvicEnableVector(STM32_TIM8_UP_TIM13_NUMBER, + STM32_IRQ_TIM8_UP_TIM13_PRIORITY); +#endif +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM14_IS_USED) + nvicEnableVector(STM32_TIM8_TRGCO_TIM14_NUMBER, + STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY); +#endif +#if defined(STM32_TIM8_IS_USED) + nvicEnableVector(STM32_TIM8_CC_NUMBER, + STM32_IRQ_TIM8_CC_PRIORITY); +#endif +} + +static inline void tim8_tim12_tim13_tim14_irq_deinit(void) { +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM12_IS_USED) + nvicDisableVector(STM32_TIM8_BRK_TIM12_NUMBER); +#endif +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM13_IS_USED) + nvicDisableVector(STM32_TIM8_UP_TIM13_NUMBER); +#endif +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM14_IS_USED) + nvicDisableVector(STM32_TIM8_TRGCO_TIM14_NUMBER); +#endif +#if defined(STM32_TIM8_IS_USED) + nvicDisableVector(STM32_TIM8_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM12_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM8-BRK, TIM12 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_BRK_TIM12_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM12 + gpt_lld_serve_interrupt(&GPTD12); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM12 + icu_lld_serve_interrupt(&ICUD12); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM12 + pwm_lld_serve_interrupt(&PWMD12); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM12 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM13_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM8-UP, TIM13 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_UP_TIM13_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM8 + gpt_lld_serve_interrupt(&GPTD8); +#endif +#if STM32_GPT_USE_TIM13 + gpt_lld_serve_interrupt(&GPTD13); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM8 + icu_lld_serve_interrupt(&ICUD8); +#endif +#if STM32_ICU_USE_TIM13 + icu_lld_serve_interrupt(&ICUD13); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM8 + pwm_lld_serve_interrupt(&PWMD8); +#endif +#if STM32_PWM_USE_TIM13 + pwm_lld_serve_interrupt(&PWMD13); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM8 + st_lld_serve_interrupt(); +#endif +#if STM32_ST_USE_TIM13 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM14_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM8-TRG-COM, TIM14 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_TRGCO_TIM14_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM14 + gpt_lld_serve_interrupt(&GPTD14); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM14 + icu_lld_serve_interrupt(&ICUD14); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM14 + pwm_lld_serve_interrupt(&PWMD14); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM14 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM8_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM8-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM8 + icu_lld_serve_interrupt(&ICUD8); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM8 + pwm_lld_serve_interrupt(&PWMD8); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/tim_irq_mapping.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/tim_irq_mapping.txt new file mode 100644 index 0000000..ed21572 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/tim_irq_mapping.txt @@ -0,0 +1,14 @@ +TIM units IRQ collisions mapping. + + 1B 1UP 1TC 1CC 2 3 4 5 6 7 8B 8UP 8TC 8CC 9 10 11 12 13 14 15 16 17 18 19 20 21 22 LP1 LP2 +F0xx 1---1 2---2 * * * * * * * * +F030 1---1 2---2 * * * * * +F1xx 1 2 3 * * * * * * * 1 2 3 +F100 1 2 3 * * * * * * * 1 2 3 +F3xx 1 2 3 * * * * * * * * * * 1 2 3 +F37x * * * * * * * * * * * * * * +F4xx 1 2 3 * * * * * * * 4 5 6 * 1 2 3 4 5 6 +F7xx 1 2 3 * * * * * * * 4 5 6 * 1 2 3 4 5 6 * +L0xx * * * * * * * +L1xx * * * * * * * * * +L4xx 1 2 3 * * * * * * * * * * * 1 2 3 * * diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/driver.mk new file mode 100644 index 0000000..2f65c1f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/driver.mk @@ -0,0 +1,13 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_SERIAL TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c +endif +ifneq ($(findstring HAL_USE_UART TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c new file mode 100644 index 0000000..188740e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c @@ -0,0 +1,650 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv1/hal_serial_lld.c + * @brief STM32 low level serial driver code. + * + * @addtogroup SERIAL + * @{ + */ + +#include "hal.h" + +#if HAL_USE_SERIAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief USART1 serial driver identifier.*/ +#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__) +SerialDriver SD1; +#endif + +/** @brief USART2 serial driver identifier.*/ +#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__) +SerialDriver SD2; +#endif + +/** @brief USART3 serial driver identifier.*/ +#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__) +SerialDriver SD3; +#endif + +/** @brief UART4 serial driver identifier.*/ +#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__) +SerialDriver SD4; +#endif + +/** @brief UART5 serial driver identifier.*/ +#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__) +SerialDriver SD5; +#endif + +/** @brief USART6 serial driver identifier.*/ +#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__) +SerialDriver SD6; +#endif + +/** @brief UART7 serial driver identifier.*/ +#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__) +SerialDriver SD7; +#endif + +/** @brief UART8 serial driver identifier.*/ +#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__) +SerialDriver SD8; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** @brief Driver default configuration.*/ +static const SerialConfig default_config = +{ + SERIAL_DEFAULT_BITRATE, + 0, + USART_CR2_STOP1_BITS, + 0 +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief USART initialization. + * @details This function must be invoked with interrupts disabled. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] config the architecture-dependent serial driver configuration + */ +static void usart_init(SerialDriver *sdp, const SerialConfig *config) { + uint32_t fck; + USART_TypeDef *u = sdp->usart; + + /* Baud rate setting.*/ +#if STM32_HAS_USART6 + if ((sdp->usart == USART1) || (sdp->usart == USART6)) +#else + if (sdp->usart == USART1) +#endif + fck = STM32_PCLK2 / config->speed; + else + fck = STM32_PCLK1 / config->speed; + + /* Correcting USARTDIV when oversampling by 8 instead of 16. + Fraction is still 4 bits wide, but only lower 3 bits used. + Mantissa is doubled, but Fraction is left the same.*/ +#if defined(USART_CR1_OVER8) + if (config->cr1 & USART_CR1_OVER8) + fck = ((fck & ~7) * 2) | (fck & 7); +#endif + u->BRR = fck; + + /* Note that some bits are enforced.*/ + u->CR2 = config->cr2 | USART_CR2_LBDIE; + u->CR3 = config->cr3 | USART_CR3_EIE; + u->CR1 = config->cr1 | USART_CR1_UE | USART_CR1_PEIE | + USART_CR1_RXNEIE | USART_CR1_TE | + USART_CR1_RE; + u->SR = 0; + (void)u->SR; /* SR reset step 1.*/ + (void)u->DR; /* SR reset step 2.*/ + + /* Deciding mask to be applied on the data register on receive, this is + required in order to mask out the parity bit.*/ + if ((config->cr1 & (USART_CR1_M | USART_CR1_PCE)) == USART_CR1_PCE) { + sdp->rxmask = 0x7F; + } + else { + sdp->rxmask = 0xFF; + } +} + +/** + * @brief USART de-initialization. + * @details This function must be invoked with interrupts disabled. + * + * @param[in] u pointer to an USART I/O block + */ +static void usart_deinit(USART_TypeDef *u) { + + u->CR1 = 0; + u->CR2 = 0; + u->CR3 = 0; +} + +/** + * @brief Error handling routine. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] sr USART SR register value + */ +static void set_error(SerialDriver *sdp, uint16_t sr) { + eventflags_t sts = 0; + + if (sr & USART_SR_ORE) + sts |= SD_OVERRUN_ERROR; + if (sr & USART_SR_PE) + sts |= SD_PARITY_ERROR; + if (sr & USART_SR_FE) + sts |= SD_FRAMING_ERROR; + if (sr & USART_SR_NE) + sts |= SD_NOISE_ERROR; + chnAddFlagsI(sdp, sts); +} + +/** + * @brief Common IRQ handler. + * + * @param[in] sdp communication channel associated to the USART + */ +static void serve_interrupt(SerialDriver *sdp) { + USART_TypeDef *u = sdp->usart; + uint16_t cr1 = u->CR1; + uint16_t sr = u->SR; + + /* Special case, LIN break detection.*/ + if (sr & USART_SR_LBD) { + osalSysLockFromISR(); + chnAddFlagsI(sdp, SD_BREAK_DETECTED); + u->SR = ~USART_SR_LBD; + osalSysUnlockFromISR(); + } + + /* Data available.*/ + osalSysLockFromISR(); + while (sr & (USART_SR_RXNE | USART_SR_ORE | USART_SR_NE | USART_SR_FE | + USART_SR_PE)) { + uint8_t b; + + /* Error condition detection.*/ + if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) + set_error(sdp, sr); + b = (uint8_t)u->DR & sdp->rxmask; + if (sr & USART_SR_RXNE) + sdIncomingDataI(sdp, b); + sr = u->SR; + } + osalSysUnlockFromISR(); + + /* Transmission buffer empty.*/ + if ((cr1 & USART_CR1_TXEIE) && (sr & USART_SR_TXE)) { + msg_t b; + osalSysLockFromISR(); + b = oqGetI(&sdp->oqueue); + if (b < MSG_OK) { + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + u->CR1 = cr1 & ~USART_CR1_TXEIE; + } + else + u->DR = b; + osalSysUnlockFromISR(); + } + + /* Physical transmission end.*/ + if ((cr1 & USART_CR1_TCIE) && (sr & USART_SR_TC)) { + osalSysLockFromISR(); + if (oqIsEmptyI(&sdp->oqueue)) { + chnAddFlagsI(sdp, CHN_TRANSMISSION_END); + u->CR1 = cr1 & ~USART_CR1_TCIE; + } + osalSysUnlockFromISR(); + } +} + +#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__) +static void notify1(io_queue_t *qp) { + + (void)qp; + USART1->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__) +static void notify2(io_queue_t *qp) { + + (void)qp; + USART2->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__) +static void notify3(io_queue_t *qp) { + + (void)qp; + USART3->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__) +static void notify4(io_queue_t *qp) { + + (void)qp; + UART4->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__) +static void notify5(io_queue_t *qp) { + + (void)qp; + UART5->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__) +static void notify6(io_queue_t *qp) { + + (void)qp; + USART6->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__) +static void notify7(io_queue_t *qp) { + + (void)qp; + UART7->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__) +static void notify8(io_queue_t *qp) { + + (void)qp; + UART8->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__) +#if !defined(STM32_USART1_HANDLER) +#error "STM32_USART1_HANDLER not defined" +#endif +/** + * @brief USART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_interrupt(&SD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__) +#if !defined(STM32_USART2_HANDLER) +#error "STM32_USART2_HANDLER not defined" +#endif +/** + * @brief USART2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_interrupt(&SD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__) +#if !defined(STM32_USART3_HANDLER) +#error "STM32_USART3_HANDLER not defined" +#endif +/** + * @brief USART3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_interrupt(&SD3); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__) +#if !defined(STM32_UART4_HANDLER) +#error "STM32_UART4_HANDLER not defined" +#endif +/** + * @brief UART4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_interrupt(&SD4); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__) +#if !defined(STM32_UART5_HANDLER) +#error "STM32_UART5_HANDLER not defined" +#endif +/** + * @brief UART5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_interrupt(&SD5); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__) +#if !defined(STM32_USART6_HANDLER) +#error "STM32_USART6_HANDLER not defined" +#endif +/** + * @brief USART6 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_interrupt(&SD6); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__) +#if !defined(STM32_UART7_HANDLER) +#error "STM32_UART7_HANDLER not defined" +#endif +/** + * @brief UART7 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_interrupt(&SD7); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__) +#if !defined(STM32_UART8_HANDLER) +#error "STM32_UART8_HANDLER not defined" +#endif +/** + * @brief UART8 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_interrupt(&SD8); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level serial driver initialization. + * + * @notapi + */ +void sd_lld_init(void) { + +#if STM32_SERIAL_USE_USART1 + sdObjectInit(&SD1, NULL, notify1); + SD1.usart = USART1; +#endif + +#if STM32_SERIAL_USE_USART2 + sdObjectInit(&SD2, NULL, notify2); + SD2.usart = USART2; +#endif + +#if STM32_SERIAL_USE_USART3 + sdObjectInit(&SD3, NULL, notify3); + SD3.usart = USART3; +#endif + +#if STM32_SERIAL_USE_UART4 + sdObjectInit(&SD4, NULL, notify4); + SD4.usart = UART4; +#endif + +#if STM32_SERIAL_USE_UART5 + sdObjectInit(&SD5, NULL, notify5); + SD5.usart = UART5; +#endif + +#if STM32_SERIAL_USE_USART6 + sdObjectInit(&SD6, NULL, notify6); + SD6.usart = USART6; +#endif + +#if STM32_SERIAL_USE_UART7 + sdObjectInit(&SD7, NULL, notify7); + SD7.usart = UART7; +#endif + +#if STM32_SERIAL_USE_UART8 + sdObjectInit(&SD8, NULL, notify8); + SD8.usart = UART8; +#endif +} + +/** + * @brief Low level serial driver configuration and (re)start. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] config the architecture-dependent serial driver configuration. + * If this parameter is set to @p NULL then a default + * configuration is used. + * + * @notapi + */ +void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { + + if (config == NULL) + config = &default_config; + + if (sdp->state == SD_STOP) { +#if STM32_SERIAL_USE_USART1 + if (&SD1 == sdp) { + rccEnableUSART1(true); + nvicEnableVector(STM32_USART1_NUMBER, STM32_SERIAL_USART1_PRIORITY); + } +#endif +#if STM32_SERIAL_USE_USART2 + if (&SD2 == sdp) { + rccEnableUSART2(true); + nvicEnableVector(STM32_USART2_NUMBER, STM32_SERIAL_USART2_PRIORITY); + } +#endif +#if STM32_SERIAL_USE_USART3 + if (&SD3 == sdp) { + rccEnableUSART3(true); + nvicEnableVector(STM32_USART3_NUMBER, STM32_SERIAL_USART3_PRIORITY); + } +#endif +#if STM32_SERIAL_USE_UART4 + if (&SD4 == sdp) { + rccEnableUART4(true); + nvicEnableVector(STM32_UART4_NUMBER, STM32_SERIAL_UART4_PRIORITY); + } +#endif +#if STM32_SERIAL_USE_UART5 + if (&SD5 == sdp) { + rccEnableUART5(true); + nvicEnableVector(STM32_UART5_NUMBER, STM32_SERIAL_UART5_PRIORITY); + } +#endif +#if STM32_SERIAL_USE_USART6 + if (&SD6 == sdp) { + rccEnableUSART6(true); + nvicEnableVector(STM32_USART6_NUMBER, STM32_SERIAL_USART6_PRIORITY); + } +#endif +#if STM32_SERIAL_USE_UART7 + if (&SD7 == sdp) { + rccEnableUART7(true); + nvicEnableVector(STM32_UART7_NUMBER, STM32_SERIAL_UART7_PRIORITY); + } +#endif +#if STM32_SERIAL_USE_UART8 + if (&SD8 == sdp) { + rccEnableUART8(true); + nvicEnableVector(STM32_UART8_NUMBER, STM32_SERIAL_UART8_PRIORITY); + } +#endif + } + usart_init(sdp, config); +} + +/** + * @brief Low level serial driver stop. + * @details De-initializes the USART, stops the associated clock, resets the + * interrupt vector. + * + * @param[in] sdp pointer to a @p SerialDriver object + * + * @notapi + */ +void sd_lld_stop(SerialDriver *sdp) { + + if (sdp->state == SD_READY) { + usart_deinit(sdp->usart); +#if STM32_SERIAL_USE_USART1 + if (&SD1 == sdp) { + rccDisableUSART1(); + nvicDisableVector(STM32_USART1_NUMBER); + return; + } +#endif +#if STM32_SERIAL_USE_USART2 + if (&SD2 == sdp) { + rccDisableUSART2(); + nvicDisableVector(STM32_USART2_NUMBER); + return; + } +#endif +#if STM32_SERIAL_USE_USART3 + if (&SD3 == sdp) { + rccDisableUSART3(); + nvicDisableVector(STM32_USART3_NUMBER); + return; + } +#endif +#if STM32_SERIAL_USE_UART4 + if (&SD4 == sdp) { + rccDisableUART4(); + nvicDisableVector(STM32_UART4_NUMBER); + return; + } +#endif +#if STM32_SERIAL_USE_UART5 + if (&SD5 == sdp) { + rccDisableUART5(); + nvicDisableVector(STM32_UART5_NUMBER); + return; + } +#endif +#if STM32_SERIAL_USE_USART6 + if (&SD6 == sdp) { + rccDisableUSART6(); + nvicDisableVector(STM32_USART6_NUMBER); + return; + } +#endif +#if STM32_SERIAL_USE_UART7 + if (&SD7 == sdp) { + rccDisableUART7(); + nvicDisableVector(STM32_UART7_NUMBER); + return; + } +#endif +#if STM32_SERIAL_USE_UART8 + if (&SD8 == sdp) { + rccDisableUART8(); + nvicDisableVector(STM32_UART8_NUMBER); + return; + } +#endif + } +} + +#endif /* HAL_USE_SERIAL */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.h new file mode 100644 index 0000000..de259a7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.h @@ -0,0 +1,362 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv1/hal_serial_lld.h + * @brief STM32 low level serial driver header. + * + * @addtogroup SERIAL + * @{ + */ + +#ifndef HAL_SERIAL_LLD_H +#define HAL_SERIAL_LLD_H + +#if HAL_USE_SERIAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief USART1 driver enable switch. + * @details If set to @p TRUE the support for USART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_USART1) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_USART1 FALSE +#endif + +/** + * @brief USART2 driver enable switch. + * @details If set to @p TRUE the support for USART2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_USART2) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_USART2 FALSE +#endif + +/** + * @brief USART3 driver enable switch. + * @details If set to @p TRUE the support for USART3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_USART3) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_USART3 FALSE +#endif + +/** + * @brief UART4 driver enable switch. + * @details If set to @p TRUE the support for UART4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_UART4) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_UART4 FALSE +#endif + +/** + * @brief UART5 driver enable switch. + * @details If set to @p TRUE the support for UART5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_UART5) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_UART5 FALSE +#endif + +/** + * @brief USART6 driver enable switch. + * @details If set to @p TRUE the support for USART6 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_USART6) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_USART6 FALSE +#endif + +/** + * @brief UART7 driver enable switch. + * @details If set to @p TRUE the support for UART7 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_UART7) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_UART7 FALSE +#endif + +/** + * @brief UART8 driver enable switch. + * @details If set to @p TRUE the support for UART8 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_UART8) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_UART8 FALSE +#endif + +/** + * @brief USART1 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_USART1_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART1_PRIORITY 12 +#endif + +/** + * @brief USART2 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_USART2_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART2_PRIORITY 12 +#endif + +/** + * @brief USART3 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_USART3_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART3_PRIORITY 12 +#endif + +/** + * @brief UART4 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_UART4_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART4_PRIORITY 12 +#endif + +/** + * @brief UART5 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_UART5_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART5_PRIORITY 12 +#endif + +/** + * @brief USART6 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_USART6_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART6_PRIORITY 12 +#endif + +/** + * @brief UART7 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_UART7_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART7_PRIORITY 12 +#endif + +/** + * @brief UART8 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_UART8_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART8_PRIORITY 12 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_SERIAL_USE_USART1 && !STM32_HAS_USART1 +#error "USART1 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_USART2 && !STM32_HAS_USART2 +#error "USART2 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_USART3 && !STM32_HAS_USART3 +#error "USART3 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_UART4 && !STM32_HAS_UART4 +#error "UART4 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_UART5 && !STM32_HAS_UART5 +#error "UART5 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_USART6 && !STM32_HAS_USART6 +#error "USART6 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_UART7 && !STM32_HAS_UART7 +#error "UART7 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_UART8 && !STM32_HAS_UART8 +#error "UART8 not present in the selected device" +#endif + +#if !STM32_SERIAL_USE_USART1 && !STM32_SERIAL_USE_USART2 && \ + !STM32_SERIAL_USE_USART3 && !STM32_SERIAL_USE_UART4 && \ + !STM32_SERIAL_USE_UART5 && !STM32_SERIAL_USE_USART6 && \ + !STM32_SERIAL_USE_UART7 && !STM32_SERIAL_USE_UART8 +#error "SERIAL driver activated but no USART/UART peripheral assigned" +#endif + +#if STM32_SERIAL_USE_USART1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART1_PRIORITY) +#error "Invalid IRQ priority assigned to USART1" +#endif + +#if STM32_SERIAL_USE_USART2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART2_PRIORITY) +#error "Invalid IRQ priority assigned to USART2" +#endif + +#if STM32_SERIAL_USE_USART3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART3_PRIORITY) +#error "Invalid IRQ priority assigned to USART3" +#endif + +#if STM32_SERIAL_USE_UART4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART4_PRIORITY) +#error "Invalid IRQ priority assigned to UART4" +#endif + +#if STM32_SERIAL_USE_UART5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART5_PRIORITY) +#error "Invalid IRQ priority assigned to UART5" +#endif + +#if STM32_SERIAL_USE_USART6 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART6_PRIORITY) +#error "Invalid IRQ priority assigned to USART6" +#endif + +#if STM32_SERIAL_USE_UART7 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART7_PRIORITY) +#error "Invalid IRQ priority assigned to UART7" +#endif + +#if STM32_SERIAL_USE_UART8 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART8_PRIORITY) +#error "Invalid IRQ priority assigned to UART8" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief STM32 Serial Driver configuration structure. + * @details An instance of this structure must be passed to @p sdStart() + * in order to configure and start a serial driver operations. + * @note This structure content is architecture dependent, each driver + * implementation defines its own version and the custom static + * initializers. + */ +typedef struct { + /** + * @brief Bit rate. + */ + uint32_t speed; + /* End of the mandatory fields.*/ + /** + * @brief Initialization value for the CR1 register. + */ + uint16_t cr1; + /** + * @brief Initialization value for the CR2 register. + */ + uint16_t cr2; + /** + * @brief Initialization value for the CR3 register. + */ + uint16_t cr3; +} SerialConfig; + +/** + * @brief @p SerialDriver specific data. + */ +#define _serial_driver_data \ + _base_asynchronous_channel_data \ + /* Driver state.*/ \ + sdstate_t state; \ + /* Input queue.*/ \ + input_queue_t iqueue; \ + /* Output queue.*/ \ + output_queue_t oqueue; \ + /* Input circular buffer.*/ \ + uint8_t ib[SERIAL_BUFFERS_SIZE]; \ + /* Output circular buffer.*/ \ + uint8_t ob[SERIAL_BUFFERS_SIZE]; \ + /* End of the mandatory fields.*/ \ + /* Pointer to the USART registers block.*/ \ + USART_TypeDef *usart; \ + /* Mask to be applied on received frames.*/ \ + uint8_t rxmask; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/* + * Extra USARTs definitions here (missing from the ST header file). + */ +#define USART_CR2_STOP1_BITS (0 << 12) /**< @brief CR2 1 stop bit value.*/ +#define USART_CR2_STOP0P5_BITS (1 << 12) /**< @brief CR2 0.5 stop bit value.*/ +#define USART_CR2_STOP2_BITS (2 << 12) /**< @brief CR2 2 stop bit value.*/ +#define USART_CR2_STOP1P5_BITS (3 << 12) /**< @brief CR2 1.5 stop bit value.*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_SERIAL_USE_USART1 && !defined(__DOXYGEN__) +extern SerialDriver SD1; +#endif +#if STM32_SERIAL_USE_USART2 && !defined(__DOXYGEN__) +extern SerialDriver SD2; +#endif +#if STM32_SERIAL_USE_USART3 && !defined(__DOXYGEN__) +extern SerialDriver SD3; +#endif +#if STM32_SERIAL_USE_UART4 && !defined(__DOXYGEN__) +extern SerialDriver SD4; +#endif +#if STM32_SERIAL_USE_UART5 && !defined(__DOXYGEN__) +extern SerialDriver SD5; +#endif +#if STM32_SERIAL_USE_USART6 && !defined(__DOXYGEN__) +extern SerialDriver SD6; +#endif +#if STM32_SERIAL_USE_UART7 && !defined(__DOXYGEN__) +extern SerialDriver SD7; +#endif +#if STM32_SERIAL_USE_UART8 && !defined(__DOXYGEN__) +extern SerialDriver SD8; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sd_lld_init(void); + void sd_lld_start(SerialDriver *sdp, const SerialConfig *config); + void sd_lld_stop(SerialDriver *sdp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SERIAL */ + +#endif /* HAL_SERIAL_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c new file mode 100644 index 0000000..d7da046 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c @@ -0,0 +1,1008 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv1/hal_uart_lld.c + * @brief STM32 low level UART driver code. + * + * @addtogroup UART + * @{ + */ + +#include "hal.h" + +#if HAL_USE_UART || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define USART1_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART1_RX_DMA_STREAM, \ + STM32_USART1_RX_DMA_CHN) + +#define USART1_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART1_TX_DMA_STREAM, \ + STM32_USART1_TX_DMA_CHN) + +#define USART2_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART2_RX_DMA_STREAM, \ + STM32_USART2_RX_DMA_CHN) + +#define USART2_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART2_TX_DMA_STREAM, \ + STM32_USART2_TX_DMA_CHN) + +#define USART3_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART3_RX_DMA_STREAM, \ + STM32_USART3_RX_DMA_CHN) + +#define USART3_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART3_TX_DMA_STREAM, \ + STM32_USART3_TX_DMA_CHN) + +#define UART4_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART4_RX_DMA_STREAM, \ + STM32_UART4_RX_DMA_CHN) + +#define UART4_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART4_TX_DMA_STREAM, \ + STM32_UART4_TX_DMA_CHN) + +#define UART5_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART5_RX_DMA_STREAM, \ + STM32_UART5_RX_DMA_CHN) + +#define UART5_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART5_TX_DMA_STREAM, \ + STM32_UART5_TX_DMA_CHN) + +#define USART6_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART6_RX_DMA_STREAM, \ + STM32_USART6_RX_DMA_CHN) + +#define USART6_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART6_TX_DMA_STREAM, \ + STM32_USART6_TX_DMA_CHN) + +#define UART7_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART7_RX_DMA_STREAM, \ + STM32_UART7_RX_DMA_CHN) + +#define UART7_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART7_TX_DMA_STREAM, \ + STM32_UART7_TX_DMA_CHN) + +#define UART8_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART8_RX_DMA_STREAM, \ + STM32_UART8_RX_DMA_CHN) + +#define UART8_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART8_TX_DMA_STREAM, \ + STM32_UART8_TX_DMA_CHN) + +#define STM32_UART45_CR2_CHECK_MASK \ + (USART_CR2_STOP_0 | USART_CR2_CLKEN | USART_CR2_CPOL | USART_CR2_CPHA | \ + USART_CR2_LBCL) + +#define STM32_UART45_CR3_CHECK_MASK \ + (USART_CR3_CTSIE | USART_CR3_CTSE | USART_CR3_RTSE | USART_CR3_SCEN | \ + USART_CR3_NACK) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief USART1 UART driver identifier.*/ +#if STM32_UART_USE_USART1 || defined(__DOXYGEN__) +UARTDriver UARTD1; +#endif + +/** @brief USART2 UART driver identifier.*/ +#if STM32_UART_USE_USART2 || defined(__DOXYGEN__) +UARTDriver UARTD2; +#endif + +/** @brief USART3 UART driver identifier.*/ +#if STM32_UART_USE_USART3 || defined(__DOXYGEN__) +UARTDriver UARTD3; +#endif + +/** @brief UART4 UART driver identifier.*/ +#if STM32_UART_USE_UART4 || defined(__DOXYGEN__) +UARTDriver UARTD4; +#endif + +/** @brief UART5 UART driver identifier.*/ +#if STM32_UART_USE_UART5 || defined(__DOXYGEN__) +UARTDriver UARTD5; +#endif + +/** @brief USART6 UART driver identifier.*/ +#if STM32_UART_USE_USART6 || defined(__DOXYGEN__) +UARTDriver UARTD6; +#endif + +/** @brief UART7 UART driver identifier.*/ +#if STM32_UART_USE_UART7 || defined(__DOXYGEN__) +UARTDriver UARTD7; +#endif + +/** @brief UART8 UART driver identifier.*/ +#if STM32_UART_USE_UART8 || defined(__DOXYGEN__) +UARTDriver UARTD8; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Status bits translation. + * + * @param[in] sr USART SR register value + * + * @return The error flags. + */ +static uartflags_t translate_errors(uint16_t sr) { + uartflags_t sts = 0; + + if (sr & USART_SR_ORE) + sts |= UART_OVERRUN_ERROR; + if (sr & USART_SR_PE) + sts |= UART_PARITY_ERROR; + if (sr & USART_SR_FE) + sts |= UART_FRAMING_ERROR; + if (sr & USART_SR_NE) + sts |= UART_NOISE_ERROR; + if (sr & USART_SR_LBD) + sts |= UART_BREAK_DETECTED; + return sts; +} + +/** + * @brief Puts the receiver in the UART_RX_IDLE state. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +static void uart_enter_rx_idle_loop(UARTDriver *uartp) { + uint32_t mode; + + /* RX DMA channel preparation, if the char callback is defined then the + TCIE interrupt is enabled too.*/ + if (uartp->config->rxchar_cb == NULL) + mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC; + else + mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC | STM32_DMA_CR_TCIE; + dmaStreamSetMemory0(uartp->dmarx, &uartp->rxbuf); + dmaStreamSetTransactionSize(uartp->dmarx, 1); + dmaStreamSetMode(uartp->dmarx, uartp->dmarxmode | mode); + dmaStreamEnable(uartp->dmarx); +} + +/** + * @brief USART de-initialization. + * @details This function must be invoked with interrupts disabled. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +static void usart_stop(UARTDriver *uartp) { + + /* Stops RX and TX DMA channels.*/ + dmaStreamDisable(uartp->dmarx); + dmaStreamDisable(uartp->dmatx); + + /* Stops USART operations.*/ + uartp->usart->CR1 = 0; + uartp->usart->CR2 = 0; + uartp->usart->CR3 = 0; +} + +/** + * @brief USART initialization. + * @details This function must be invoked with interrupts disabled. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +static void usart_start(UARTDriver *uartp) { + uint32_t fck; + uint16_t cr1; + USART_TypeDef *u = uartp->usart; + + /* Defensive programming, starting from a clean state.*/ + usart_stop(uartp); + + /* Baud rate setting.*/ +#if STM32_HAS_USART6 + if ((uartp->usart == USART1) || (uartp->usart == USART6)) +#else + if (uartp->usart == USART1) +#endif + fck = STM32_PCLK2 / uartp->config->speed; + else + fck = STM32_PCLK1 / uartp->config->speed; + + /* Correcting USARTDIV when oversampling by 8 instead of 16. + Fraction is still 4 bits wide, but only lower 3 bits used. + Mantissa is doubled, but Fraction is left the same.*/ +#if defined(USART_CR1_OVER8) + if (uartp->config->cr1 & USART_CR1_OVER8) + fck = ((fck & ~7) * 2) | (fck & 7); +#endif + u->BRR = fck; + + /* Resetting eventual pending status flags.*/ + (void)u->SR; /* SR reset step 1.*/ + (void)u->DR; /* SR reset step 2.*/ + u->SR = 0; + + /* Note that some bits are enforced because required for correct driver + operations.*/ + u->CR2 = uartp->config->cr2 | USART_CR2_LBDIE; + u->CR3 = uartp->config->cr3 | USART_CR3_DMAT | USART_CR3_DMAR | + USART_CR3_EIE; + + /* Mustn't ever set TCIE here - if done, it causes an immediate + interrupt.*/ + cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE; + u->CR1 = uartp->config->cr1 | cr1; + + /* Starting the receiver idle loop.*/ + uart_enter_rx_idle_loop(uartp); +} + +/** + * @brief RX DMA common service routine. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_UART_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_UART_DMA_ERROR_HOOK(uartp); + } +#else + (void)flags; +#endif + + if (uartp->rxstate == UART_RX_IDLE) { + /* Receiver in idle state, a callback is generated, if enabled, for each + received character and then the driver stays in the same state.*/ + _uart_rx_idle_code(uartp); + } + else { + /* Receiver in active state, a callback is generated, if enabled, after + a completed transfer.*/ + dmaStreamDisable(uartp->dmarx); + _uart_rx_complete_isr_code(uartp); + } +} + +/** + * @brief TX DMA common service routine. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_UART_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_UART_DMA_ERROR_HOOK(uartp); + } +#else + (void)flags; +#endif + + dmaStreamDisable(uartp->dmatx); + + /* A callback is generated, if enabled, after a completed transfer.*/ + _uart_tx1_isr_code(uartp); +} + +/** + * @brief USART common service routine. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +static void serve_usart_irq(UARTDriver *uartp) { + uint16_t sr; + USART_TypeDef *u = uartp->usart; + uint32_t cr1 = u->CR1; + + sr = u->SR; /* SR reset step 1.*/ + (void)u->DR; /* SR reset step 2.*/ + + if (sr & (USART_SR_LBD | USART_SR_ORE | USART_SR_NE | + USART_SR_FE | USART_SR_PE)) { + u->SR = ~USART_SR_LBD; + _uart_rx_error_isr_code(uartp, translate_errors(sr)); + } + + if ((sr & USART_SR_TC) && (cr1 & USART_CR1_TCIE)) { + /* TC interrupt cleared and disabled.*/ + u->SR = ~USART_SR_TC; + u->CR1 = cr1 & ~USART_CR1_TCIE; + + /* End of transmission, a callback is generated.*/ + _uart_tx2_isr_code(uartp); + } + + /* Timeout interrupt sources are only checked if enabled in CR1.*/ + if ((cr1 & USART_CR1_IDLEIE) && (sr & USART_SR_IDLE)) { + _uart_timeout_isr_code(uartp); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART_USE_USART1 || defined(__DOXYGEN__) +#if !defined(STM32_USART1_HANDLER) +#error "STM32_USART1_HANDLER not defined" +#endif +/** + * @brief USART1 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_USART1 */ + +#if STM32_UART_USE_USART2 || defined(__DOXYGEN__) +#if !defined(STM32_USART2_HANDLER) +#error "STM32_USART2_HANDLER not defined" +#endif +/** + * @brief USART2 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_USART2 */ + +#if STM32_UART_USE_USART3 || defined(__DOXYGEN__) +#if !defined(STM32_USART3_HANDLER) +#error "STM32_USART3_HANDLER not defined" +#endif +/** + * @brief USART3 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD3); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_USART3 */ + +#if STM32_UART_USE_UART4 || defined(__DOXYGEN__) +#if !defined(STM32_UART4_HANDLER) +#error "STM32_UART4_HANDLER not defined" +#endif +/** + * @brief UART4 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD4); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_UART4 */ + +#if STM32_UART_USE_UART5 || defined(__DOXYGEN__) +#if !defined(STM32_UART5_HANDLER) +#error "STM32_UART5_HANDLER not defined" +#endif +/** + * @brief UART5 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD5); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_UART5 */ + +#if STM32_UART_USE_USART6 || defined(__DOXYGEN__) +#if !defined(STM32_USART6_HANDLER) +#error "STM32_USART6_HANDLER not defined" +#endif +/** + * @brief USART6 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD6); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_USART6 */ + +#if STM32_UART_USE_UART7 || defined(__DOXYGEN__) +#if !defined(STM32_UART7_HANDLER) +#error "STM32_UART7_HANDLER not defined" +#endif +/** + * @brief UART7 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD7); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_UART7 */ + +#if STM32_UART_USE_UART8 || defined(__DOXYGEN__) +#if !defined(STM32_UART8_HANDLER) +#error "STM32_UART8_HANDLER not defined" +#endif +/** + * @brief UART8 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD8); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_UART8 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level UART driver initialization. + * + * @notapi + */ +void uart_lld_init(void) { + +#if STM32_UART_USE_USART1 + uartObjectInit(&UARTD1); + UARTD1.usart = USART1; + UARTD1.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD1.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD1.dmarx = NULL; + UARTD1.dmatx = NULL; +#endif + +#if STM32_UART_USE_USART2 + uartObjectInit(&UARTD2); + UARTD2.usart = USART2; + UARTD2.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD2.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD2.dmarx = NULL; + UARTD2.dmatx = NULL; +#endif + +#if STM32_UART_USE_USART3 + uartObjectInit(&UARTD3); + UARTD3.usart = USART3; + UARTD3.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD3.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD3.dmarx = NULL; + UARTD3.dmatx = NULL; +#endif + +#if STM32_UART_USE_UART4 + uartObjectInit(&UARTD4); + UARTD4.usart = UART4; + UARTD4.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD4.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD4.dmarx = NULL; + UARTD4.dmatx = NULL; +#endif + +#if STM32_UART_USE_UART5 + uartObjectInit(&UARTD5); + UARTD5.usart = UART5; + UARTD5.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD5.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD5.dmarx = NULL; + UARTD5.dmatx = NULL; +#endif + +#if STM32_UART_USE_USART6 + uartObjectInit(&UARTD6); + UARTD6.usart = USART6; + UARTD6.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD6.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD6.dmarx = NULL; + UARTD6.dmatx = NULL; +#endif + +#if STM32_UART_USE_UART7 + uartObjectInit(&UARTD7); + UARTD7.usart = UART7; + UARTD7.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD7.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD7.dmarx = NULL; + UARTD7.dmatx = NULL; +#endif + +#if STM32_UART_USE_UART8 + uartObjectInit(&UARTD8); + UARTD8.usart = UART8; + UARTD8.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD8.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD8.dmarx = NULL; + UARTD8.dmatx = NULL; +#endif +} + +/** + * @brief Configures and activates the UART peripheral. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @notapi + */ +void uart_lld_start(UARTDriver *uartp) { + + if (uartp->state == UART_STOP) { +#if STM32_UART_USE_USART1 + if (&UARTD1 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_USART1_RX_DMA_STREAM, + STM32_UART_USART1_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_USART1_TX_DMA_STREAM, + STM32_UART_USART1_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUSART1(true); + nvicEnableVector(STM32_USART1_NUMBER, STM32_UART_USART1_IRQ_PRIORITY); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART1_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART1_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY); + } +#endif + +#if STM32_UART_USE_USART2 + if (&UARTD2 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_USART2_RX_DMA_STREAM, + STM32_UART_USART2_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_USART2_TX_DMA_STREAM, + STM32_UART_USART2_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUSART2(true); + nvicEnableVector(STM32_USART2_NUMBER, STM32_UART_USART2_IRQ_PRIORITY); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART2_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART2_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART2_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART2_DMA_PRIORITY); + } +#endif + +#if STM32_UART_USE_USART3 + if (&UARTD3 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_USART3_RX_DMA_STREAM, + STM32_UART_USART3_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_USART3_TX_DMA_STREAM, + STM32_UART_USART3_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUSART3(true); + nvicEnableVector(STM32_USART3_NUMBER, STM32_UART_USART3_IRQ_PRIORITY); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART3_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART3_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART3_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART3_DMA_PRIORITY); + } +#endif + +#if STM32_UART_USE_UART4 + if (&UARTD4 == uartp) { + + osalDbgAssert((uartp->config->cr2 & STM32_UART45_CR2_CHECK_MASK) == 0, + "specified invalid bits in UART4 CR2 register settings"); + osalDbgAssert((uartp->config->cr3 & STM32_UART45_CR3_CHECK_MASK) == 0, + "specified invalid bits in UART4 CR3 register settings"); + + uartp->dmarx = dmaStreamAllocI(STM32_UART_UART4_RX_DMA_STREAM, + STM32_UART_UART4_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_UART4_TX_DMA_STREAM, + STM32_UART_UART4_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUART4(true); + nvicEnableVector(STM32_UART4_NUMBER, STM32_UART_UART4_IRQ_PRIORITY); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART4_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART4_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART4_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART4_DMA_PRIORITY); + } +#endif + +#if STM32_UART_USE_UART5 + if (&UARTD5 == uartp) { + + osalDbgAssert((uartp->config->cr2 & STM32_UART45_CR2_CHECK_MASK) == 0, + "specified invalid bits in UART5 CR2 register settings"); + osalDbgAssert((uartp->config->cr3 & STM32_UART45_CR3_CHECK_MASK) == 0, + "specified invalid bits in UART5 CR3 register settings"); + + uartp->dmarx = dmaStreamAllocI(STM32_UART_UART5_RX_DMA_STREAM, + STM32_UART_UART5_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_UART5_TX_DMA_STREAM, + STM32_UART_UART5_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUART5(true); + nvicEnableVector(STM32_UART5_NUMBER, STM32_UART_UART5_IRQ_PRIORITY); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART5_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART5_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART5_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART5_DMA_PRIORITY); + } +#endif + +#if STM32_UART_USE_USART6 + if (&UARTD6 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_USART6_RX_DMA_STREAM, + STM32_UART_USART6_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_USART6_TX_DMA_STREAM, + STM32_UART_USART6_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUSART6(true); + nvicEnableVector(STM32_USART6_NUMBER, STM32_UART_USART6_IRQ_PRIORITY); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART6_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART6_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART6_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART6_DMA_PRIORITY); + } +#endif + +#if STM32_UART_USE_UART7 + if (&UARTD7 == uartp) { + + osalDbgAssert((uartp->config->cr2 & STM32_UART45_CR2_CHECK_MASK) == 0, + "specified invalid bits in UART7 CR2 register settings"); + osalDbgAssert((uartp->config->cr3 & STM32_UART45_CR3_CHECK_MASK) == 0, + "specified invalid bits in UART7 CR3 register settings"); + + uartp->dmarx = dmaStreamAllocI(STM32_UART_UART7_RX_DMA_STREAM, + STM32_UART_UART7_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_UART7_TX_DMA_STREAM, + STM32_UART_UART7_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUART7(true); + nvicEnableVector(STM32_UART7_NUMBER, STM32_UART_UART7_IRQ_PRIORITY); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART7_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART7_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART7_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART7_DMA_PRIORITY); + } +#endif + +#if STM32_UART_USE_UART8 + if (&UARTD8 == uartp) { + + osalDbgAssert((uartp->config->cr2 & STM32_UART45_CR2_CHECK_MASK) == 0, + "specified invalid bits in UART8 CR2 register settings"); + osalDbgAssert((uartp->config->cr3 & STM32_UART45_CR3_CHECK_MASK) == 0, + "specified invalid bits in UART8 CR3 register settings"); + + uartp->dmarx = dmaStreamAllocI(STM32_UART_UART8_RX_DMA_STREAM, + STM32_UART_UART8_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_UART8_TX_DMA_STREAM, + STM32_UART_UART8_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUART8(true); + nvicEnableVector(STM32_UART8_NUMBER, STM32_UART_UART8_IRQ_PRIORITY); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART8_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART8_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART8_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART8_DMA_PRIORITY); + } +#endif + + /* Static DMA setup, the transfer size depends on the USART settings, + it is 16 bits if M=1 and PCE=0 else it is 8 bits.*/ + if ((uartp->config->cr1 & (USART_CR1_M | USART_CR1_PCE)) == USART_CR1_M) { + uartp->dmarxmode |= STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + uartp->dmatxmode |= STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + } + dmaStreamSetPeripheral(uartp->dmarx, &uartp->usart->DR); + dmaStreamSetPeripheral(uartp->dmatx, &uartp->usart->DR); + uartp->rxbuf = 0; + } + + uartp->rxstate = UART_RX_IDLE; + uartp->txstate = UART_TX_IDLE; + usart_start(uartp); +} + +/** + * @brief Deactivates the UART peripheral. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @notapi + */ +void uart_lld_stop(UARTDriver *uartp) { + + if (uartp->state == UART_READY) { + usart_stop(uartp); + dmaStreamFreeI(uartp->dmarx); + dmaStreamFreeI(uartp->dmatx); + uartp->dmarx = NULL; + uartp->dmatx = NULL; + +#if STM32_UART_USE_USART1 + if (&UARTD1 == uartp) { + nvicDisableVector(STM32_USART1_NUMBER); + rccDisableUSART1(); + return; + } +#endif + +#if STM32_UART_USE_USART2 + if (&UARTD2 == uartp) { + nvicDisableVector(STM32_USART2_NUMBER); + rccDisableUSART2(); + return; + } +#endif + +#if STM32_UART_USE_USART3 + if (&UARTD3 == uartp) { + nvicDisableVector(STM32_USART3_NUMBER); + rccDisableUSART3(); + return; + } +#endif + +#if STM32_UART_USE_UART4 + if (&UARTD4 == uartp) { + nvicDisableVector(STM32_UART4_NUMBER); + rccDisableUART4(); + return; + } +#endif + +#if STM32_UART_USE_UART5 + if (&UARTD5 == uartp) { + nvicDisableVector(STM32_UART5_NUMBER); + rccDisableUART5(); + return; + } +#endif + +#if STM32_UART_USE_USART6 + if (&UARTD6 == uartp) { + nvicDisableVector(STM32_USART6_NUMBER); + rccDisableUSART6(); + return; + } +#endif + +#if STM32_UART_USE_UART7 + if (&UARTD7 == uartp) { + nvicDisableVector(STM32_UART7_NUMBER); + rccDisableUART7(); + return; + } +#endif + +#if STM32_UART_USE_UART8 + if (&UARTD8 == uartp) { + nvicDisableVector(STM32_UART8_NUMBER); + rccDisableUART8(); + return; + } +#endif + } +} + +/** + * @brief Starts a transmission on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) { + + /* TX DMA channel preparation.*/ + dmaStreamSetMemory0(uartp->dmatx, txbuf); + dmaStreamSetTransactionSize(uartp->dmatx, n); + dmaStreamSetMode(uartp->dmatx, uartp->dmatxmode | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE); + + /* Only enable TC interrupt if there's a callback attached to it or + if called from uartSendFullTimeout(). Also we need to clear TC flag + which could be set before.*/ +#if UART_USE_WAIT == TRUE + if ((uartp->config->txend2_cb != NULL) || (uartp->early == false)) { +#else + if (uartp->config->txend2_cb != NULL) { +#endif + uartp->usart->SR = ~USART_SR_TC; + uartp->usart->CR1 |= USART_CR1_TCIE; + } + + /* Starting transfer.*/ + dmaStreamEnable(uartp->dmatx); +} + +/** + * @brief Stops any ongoing transmission. + * @note Stopping a transmission also suppresses the transmission callbacks. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not transmitted by the + * stopped transmit operation. + * + * @notapi + */ +size_t uart_lld_stop_send(UARTDriver *uartp) { + + dmaStreamDisable(uartp->dmatx); + + return dmaStreamGetTransactionSize(uartp->dmatx); +} + +/** + * @brief Starts a receive operation on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to send + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) { + + /* Stopping previous activity (idle state).*/ + dmaStreamDisable(uartp->dmarx); + + /* RX DMA channel preparation.*/ + dmaStreamSetMemory0(uartp->dmarx, rxbuf); + dmaStreamSetTransactionSize(uartp->dmarx, n); + dmaStreamSetMode(uartp->dmarx, uartp->dmarxmode | STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE); + + /* Starting transfer.*/ + dmaStreamEnable(uartp->dmarx); +} + +/** + * @brief Stops any ongoing receive operation. + * @note Stopping a receive operation also suppresses the receive callbacks. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not received by the + * stopped receive operation. + * + * @notapi + */ +size_t uart_lld_stop_receive(UARTDriver *uartp) { + size_t n; + + dmaStreamDisable(uartp->dmarx); + n = dmaStreamGetTransactionSize(uartp->dmarx); + uart_enter_rx_idle_loop(uartp); + + return n; +} + +#endif /* HAL_USE_UART */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.h new file mode 100644 index 0000000..ae0f4d3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.h @@ -0,0 +1,758 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv1/hal_uart_lld.h + * @brief STM32 low level UART driver header. + * + * @addtogroup UART + * @{ + */ + +#ifndef HAL_UART_LLD_H +#define HAL_UART_LLD_H + +#if HAL_USE_UART || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief UART driver on USART1 enable switch. + * @details If set to @p TRUE the support for USART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_USART1) || defined(__DOXYGEN__) +#define STM32_UART_USE_USART1 FALSE +#endif + +/** + * @brief UART driver on USART2 enable switch. + * @details If set to @p TRUE the support for USART2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_USART2) || defined(__DOXYGEN__) +#define STM32_UART_USE_USART2 FALSE +#endif + +/** + * @brief UART driver on USART3 enable switch. + * @details If set to @p TRUE the support for USART3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_USART3) || defined(__DOXYGEN__) +#define STM32_UART_USE_USART3 FALSE +#endif + +/** + * @brief UART driver on UART4 enable switch. + * @details If set to @p TRUE the support for UART4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART4) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART4 FALSE +#endif + +/** + * @brief UART driver on UART5 enable switch. + * @details If set to @p TRUE the support for UART5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART5) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART5 FALSE +#endif + +/** + * @brief UART driver on USART6 enable switch. + * @details If set to @p TRUE the support for USART6 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_USART6) || defined(__DOXYGEN__) +#define STM32_UART_USE_USART6 FALSE +#endif + +/** + * @brief UART driver on UART7 enable switch. + * @details If set to @p TRUE the support for UART7 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART7) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART7 FALSE +#endif + +/** + * @brief UART driver on UART8 enable switch. + * @details If set to @p TRUE the support for UART8 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART8) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART8 FALSE +#endif + +/** + * @brief USART1 interrupt priority level setting. + */ +#if !defined(STM32_UART_USART1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART1_IRQ_PRIORITY 12 +#endif + +/** + * @brief USART2 interrupt priority level setting. + */ +#if !defined(STM32_UART_USART2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART2_IRQ_PRIORITY 12 +#endif + +/** + * @brief USART3 interrupt priority level setting. + */ +#if !defined(STM32_UART_USART3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART3_IRQ_PRIORITY 12 +#endif + +/** + * @brief UART4 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART4_IRQ_PRIORITY 12 +#endif + +/** + * @brief UART5 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART5_IRQ_PRIORITY 12 +#endif + +/** + * @brief USART6 interrupt priority level setting. + */ +#if !defined(STM32_UART_USART6_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART6_IRQ_PRIORITY 12 +#endif + +/** + * @brief UART7 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART7_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART7_IRQ_PRIORITY 12 +#endif + +/** + * @brief UART8 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART8_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART8_IRQ_PRIORITY 12 +#endif + +/** + * @brief USART1 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_USART1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART1_DMA_PRIORITY 0 +#endif + +/** + * @brief USART2 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_USART2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART2_DMA_PRIORITY 0 +#endif + +/** + * @brief USART3 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_USART3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART3_DMA_PRIORITY 0 +#endif + +/** + * @brief UART4 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_UART4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART4_DMA_PRIORITY 0 +#endif + +/** + * @brief UART5 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_UART5_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART5_DMA_PRIORITY 0 +#endif + +/** + * @brief USART6 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_USART6_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART6_DMA_PRIORITY 0 +#endif + +/** + * @brief UART7 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_UART7_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART7_DMA_PRIORITY 0 +#endif + +/** + * @brief UART8 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_UART8_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART8_DMA_PRIORITY 0 +#endif + +/** + * @brief USART DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(STM32_UART_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_UART_USE_USART1 && !STM32_HAS_USART1 +#error "USART1 not present in the selected device" +#endif + +#if STM32_UART_USE_USART2 && !STM32_HAS_USART2 +#error "USART2 not present in the selected device" +#endif + +#if STM32_UART_USE_USART3 && !STM32_HAS_USART3 +#error "USART3 not present in the selected device" +#endif + +#if STM32_UART_USE_UART4 +#if !STM32_HAS_UART4 +#error "UART4 not present in the selected device" +#endif + +#if !defined(STM32F2XX) && !defined(STM32F4XX) && !defined(STM32L151xE) && \ + !defined(STM32L152xE) && !defined(STM32L162xE) +#error "UART4 DMA access not supported in this platform" +#endif +#endif /* STM32_UART_USE_UART4 */ + +#if STM32_UART_USE_UART5 +#if !STM32_HAS_UART5 +#error "UART5 not present in the selected device" +#endif + +#if !defined(STM32F2XX) && !defined(STM32F4XX) && !defined(STM32L151xE) && \ + !defined(STM32L152xE) && !defined(STM32L162xE) +#error "UART5 DMA access not supported in this platform" +#endif +#endif /* STM32_UART_USE_UART5 */ + +#if STM32_UART_USE_USART6 && !STM32_HAS_USART6 +#error "USART6 not present in the selected device" +#endif + +#if STM32_UART_USE_UART7 && !STM32_HAS_UART7 +#error "UART7 not present in the selected device" +#endif + +#if STM32_UART_USE_UART8 && !STM32_HAS_UART8 +#error "UART8 not present in the selected device" +#endif + +#if !STM32_UART_USE_USART1 && !STM32_UART_USE_USART2 && \ + !STM32_UART_USE_USART3 && !STM32_UART_USE_UART4 && \ + !STM32_UART_USE_UART5 && !STM32_UART_USE_USART6 && \ + !STM32_UART_USE_UART7 && !STM32_UART_USE_UART8 +#error "UART driver activated but no USART/UART peripheral assigned" +#endif + +#if STM32_UART_USE_USART1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USART1" +#endif + +#if STM32_UART_USE_USART2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USART2" +#endif + +#if STM32_UART_USE_USART3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USART3" +#endif + +#if STM32_UART_USE_UART4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART4" +#endif + +#if STM32_UART_USE_UART5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART5" +#endif + +#if STM32_UART_USE_USART6 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART6_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USART6" +#endif + +#if STM32_UART_USE_UART7 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART7_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART7" +#endif + +#if STM32_UART_USE_UART8 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART8_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART8" +#endif + +#if STM32_UART_USE_USART1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to USART1" +#endif + +#if STM32_UART_USE_USART2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to USART2" +#endif + +#if STM32_UART_USE_USART3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to USART3" +#endif + +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART4" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART5_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART5" +#endif + +#if STM32_UART_USE_USART6 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART6_DMA_PRIORITY) +#error "Invalid DMA priority assigned to USART6" +#endif + +#if STM32_UART_USE_UART7 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART7_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART7" +#endif + +#if STM32_UART_USE_UART8 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART8_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART8" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_UART_USE_USART1 && (!defined(STM32_UART_USART1_RX_DMA_STREAM) || \ + !defined(STM32_UART_USART1_TX_DMA_STREAM)) +#error "USART1 DMA streams not defined" +#endif + +#if STM32_UART_USE_USART2 && (!defined(STM32_UART_USART2_RX_DMA_STREAM) || \ + !defined(STM32_UART_USART2_TX_DMA_STREAM)) +#error "USART2 DMA streams not defined" +#endif + +#if STM32_UART_USE_USART3 && (!defined(STM32_UART_USART3_RX_DMA_STREAM) || \ + !defined(STM32_UART_USART3_TX_DMA_STREAM)) +#error "USART3 DMA streams not defined" +#endif + +#if STM32_UART_USE_UART4 && (!defined(STM32_UART_UART4_RX_DMA_STREAM) || \ + !defined(STM32_UART_UART4_TX_DMA_STREAM)) +#error "UART4 DMA streams not defined" +#endif + +#if STM32_UART_USE_UART5 && (!defined(STM32_UART_UART5_RX_DMA_STREAM) || \ + !defined(STM32_UART_UART5_TX_DMA_STREAM)) +#error "UART5 DMA streams not defined" +#endif + +#if STM32_UART_USE_USART6 && (!defined(STM32_UART_USART6_RX_DMA_STREAM) || \ + !defined(STM32_UART_USART6_TX_DMA_STREAM)) +#error "USART6 DMA streams not defined" +#endif + +#if STM32_UART_USE_UART7 && (!defined(STM32_UART_UART7_RX_DMA_STREAM) || \ + !defined(STM32_UART_UART7_TX_DMA_STREAM)) +#error "UART7 DMA streams not defined" +#endif + +#if STM32_UART_USE_UART8 && (!defined(STM32_UART_UART8_RX_DMA_STREAM) || \ + !defined(STM32_UART_UART8_TX_DMA_STREAM)) +#error "UART8 DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_UART_USE_USART1 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_RX_DMA_STREAM, \ + STM32_USART1_RX_DMA_MSK) +#error "invalid DMA stream associated to USART1 RX" +#endif + +#if STM32_UART_USE_USART1 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_TX_DMA_STREAM, \ + STM32_USART1_TX_DMA_MSK) +#error "invalid DMA stream associated to USART1 TX" +#endif + +#if STM32_UART_USE_USART2 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_RX_DMA_STREAM, \ + STM32_USART2_RX_DMA_MSK) +#error "invalid DMA stream associated to USART2 RX" +#endif + +#if STM32_UART_USE_USART2 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_TX_DMA_STREAM, \ + STM32_USART2_TX_DMA_MSK) +#error "invalid DMA stream associated to USART2 TX" +#endif + +#if STM32_UART_USE_USART3 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_RX_DMA_STREAM, \ + STM32_USART3_RX_DMA_MSK) +#error "invalid DMA stream associated to USART3 RX" +#endif + +#if STM32_UART_USE_USART3 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_TX_DMA_STREAM, \ + STM32_USART3_TX_DMA_MSK) +#error "invalid DMA stream associated to USART3 TX" +#endif + +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_RX_DMA_STREAM, \ + STM32_UART4_RX_DMA_MSK) +#error "invalid DMA stream associated to UART4 RX" +#endif + +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_TX_DMA_STREAM, \ + STM32_UART4_TX_DMA_MSK) +#error "invalid DMA stream associated to UART4 TX" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_RX_DMA_STREAM, \ + STM32_UART5_RX_DMA_MSK) +#error "invalid DMA stream associated to UART5 RX" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_TX_DMA_STREAM, \ + STM32_UART5_TX_DMA_MSK) +#error "invalid DMA stream associated to UART5 TX" +#endif + +#if STM32_UART_USE_USART6 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART6_RX_DMA_STREAM, \ + STM32_USART6_RX_DMA_MSK) +#error "invalid DMA stream associated to USART6 RX" +#endif + +#if STM32_UART_USE_USART6 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART6_TX_DMA_STREAM, \ + STM32_USART6_TX_DMA_MSK) +#error "invalid DMA stream associated to USART6 TX" +#endif +#endif /* STM32_ADVANCED_DMA */ + +#if STM32_UART_USE_UART7 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART7_RX_DMA_STREAM, \ + STM32_UART7_RX_DMA_MSK) +#error "invalid DMA stream associated to UART7 RX" +#endif + +#if STM32_UART_USE_UART7 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART7_TX_DMA_STREAM, \ + STM32_UART7_TX_DMA_MSK) +#error "invalid DMA stream associated to UART7 TX" +#endif + +#if STM32_UART_USE_UART8 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART8_RX_DMA_STREAM, \ + STM32_UART8_RX_DMA_MSK) +#error "invalid DMA stream associated to UART8 RX" +#endif + +#if STM32_UART_USE_UART8 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART8_TX_DMA_STREAM, \ + STM32_UART8_TX_DMA_MSK) +#error "invalid DMA stream associated to UART8 TX" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief UART driver condition flags type. + */ +typedef uint32_t uartflags_t; + +/** + * @brief Structure representing an UART driver. + */ +typedef struct UARTDriver UARTDriver; + +/** + * @brief Generic UART notification callback type. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +typedef void (*uartcb_t)(UARTDriver *uartp); + +/** + * @brief Character received UART notification callback type. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] c received character + */ +typedef void (*uartccb_t)(UARTDriver *uartp, uint16_t c); + +/** + * @brief Receive error UART notification callback type. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] e receive error mask + */ +typedef void (*uartecb_t)(UARTDriver *uartp, uartflags_t e); + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief End of transmission buffer callback. + */ + uartcb_t txend1_cb; + /** + * @brief Physical end of transmission callback. + */ + uartcb_t txend2_cb; + /** + * @brief Receive buffer filled callback. + */ + uartcb_t rxend_cb; + /** + * @brief Character received while out if the @p UART_RECEIVE state. + */ + uartccb_t rxchar_cb; + /** + * @brief Receive error callback. + */ + uartecb_t rxerr_cb; + /* End of the mandatory fields.*/ + /** + * @brief Receiver timeout callback. + * @details Handles idle interrupts depending on configured + * flags in CR registers and supported hardware features. + */ + uartcb_t timeout_cb; + /** + * @brief Bit rate. + */ + uint32_t speed; + /** + * @brief Initialization value for the CR1 register. + */ + uint16_t cr1; + /** + * @brief Initialization value for the CR2 register. + */ + uint16_t cr2; + /** + * @brief Initialization value for the CR3 register. + */ + uint16_t cr3; +} UARTConfig; + +/** + * @brief Structure representing an UART driver. + */ +struct UARTDriver { + /** + * @brief Driver state. + */ + uartstate_t state; + /** + * @brief Transmitter state. + */ + uarttxstate_t txstate; + /** + * @brief Receiver state. + */ + uartrxstate_t rxstate; + /** + * @brief Current configuration data. + */ + const UARTConfig *config; +#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Synchronization flag for transmit operations. + */ + bool early; + /** + * @brief Waiting thread on RX. + */ + thread_reference_t threadrx; + /** + * @brief Waiting thread on TX. + */ + thread_reference_t threadtx; +#endif /* UART_USE_WAIT */ +#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the peripheral. + */ + mutex_t mutex; +#endif /* UART_USE_MUTUAL_EXCLUSION */ +#if defined(UART_DRIVER_EXT_FIELDS) + UART_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the USART registers block. + */ + USART_TypeDef *usart; + /** + * @brief Receive DMA mode bit mask. + */ + uint32_t dmarxmode; + /** + * @brief Send DMA mode bit mask. + */ + uint32_t dmatxmode; + /** + * @brief Receive DMA channel. + */ + const stm32_dma_stream_t *dmarx; + /** + * @brief Transmit DMA channel. + */ + const stm32_dma_stream_t *dmatx; + /** + * @brief Default receive buffer while into @p UART_RX_IDLE state. + */ + volatile uint16_t rxbuf; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_UART_USE_USART1 && !defined(__DOXYGEN__) +extern UARTDriver UARTD1; +#endif + +#if STM32_UART_USE_USART2 && !defined(__DOXYGEN__) +extern UARTDriver UARTD2; +#endif + +#if STM32_UART_USE_USART3 && !defined(__DOXYGEN__) +extern UARTDriver UARTD3; +#endif + +#if STM32_UART_USE_UART4 && !defined(__DOXYGEN__) +extern UARTDriver UARTD4; +#endif + +#if STM32_UART_USE_UART5 && !defined(__DOXYGEN__) +extern UARTDriver UARTD5; +#endif + +#if STM32_UART_USE_USART6 && !defined(__DOXYGEN__) +extern UARTDriver UARTD6; +#endif + +#if STM32_UART_USE_UART7 && !defined(__DOXYGEN__) +extern UARTDriver UARTD7; +#endif + +#if STM32_UART_USE_UART8 && !defined(__DOXYGEN__) +extern UARTDriver UARTD8; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void uart_lld_init(void); + void uart_lld_start(UARTDriver *uartp); + void uart_lld_stop(UARTDriver *uartp); + void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf); + size_t uart_lld_stop_send(UARTDriver *uartp); + void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf); + size_t uart_lld_stop_receive(UARTDriver *uartp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_UART */ + +#endif /* HAL_UART_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/driver.mk new file mode 100644 index 0000000..2de63f8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/driver.mk @@ -0,0 +1,13 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_SERIAL TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c +endif +ifneq ($(findstring HAL_USE_UART TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c new file mode 100644 index 0000000..7c89ecf --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c @@ -0,0 +1,913 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/hal_serial_lld.c + * @brief STM32 low level serial driver code. + * + * @addtogroup SERIAL + * @{ + */ + +#include "hal.h" + +#if HAL_USE_SERIAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* For compatibility for those devices without LIN support in the USARTs.*/ +#if !defined(USART_ISR_LBDF) +#define USART_ISR_LBDF 0 +#endif + +#if !defined(USART_CR2_LBDIE) +#define USART_CR2_LBDIE 0 +#endif + +/* Differences in L4+ headers.*/ +#if !defined(USART_CR1_TXEIE) +#define USART_CR1_TXEIE USART_CR1_TXEIE_TXFNFIE +#endif + +#if !defined(USART_CR1_RXNEIE) +#define USART_CR1_RXNEIE USART_CR1_RXNEIE_RXFNEIE +#endif + +#if !defined(USART_ISR_TXE) +#define USART_ISR_TXE USART_ISR_TXE_TXFNF +#endif + +#if !defined(USART_ISR_RXNE) +#define USART_ISR_RXNE USART_ISR_RXNE_RXFNE +#endif + +/* STM32L0xx/STM32F7xx ST headers difference.*/ +#if !defined(USART_ISR_LBDF) +#define USART_ISR_LBDF USART_ISR_LBD +#endif + +/* Handling differences in frame size bits.*/ +#if !defined(USART_CR1_M_0) +#define USART_CR1_M_0 (1 << 12) +#endif + +#if !defined(USART_CR1_M_1) +#define USART_CR1_M_1 (1 << 28) +#endif + +/* Workarounds for those devices where UARTs are USARTs.*/ +#if defined(USART4) +#define UART4 USART4 +#endif +#if defined(USART5) +#define UART5 USART5 +#endif +#if defined(USART7) +#define UART7 USART7 +#endif +#if defined(USART8) +#define UART8 USART8 +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief USART1 serial driver identifier.*/ +#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__) +SerialDriver SD1; +#endif + +/** @brief USART2 serial driver identifier.*/ +#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__) +SerialDriver SD2; +#endif + +/** @brief USART3 serial driver identifier.*/ +#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__) +SerialDriver SD3; +#endif + +/** @brief UART4 serial driver identifier.*/ +#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__) +SerialDriver SD4; +#endif + +/** @brief UART5 serial driver identifier.*/ +#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__) +SerialDriver SD5; +#endif + +/** @brief USART6 serial driver identifier.*/ +#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__) +SerialDriver SD6; +#endif + +/** @brief UART7 serial driver identifier.*/ +#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__) +SerialDriver SD7; +#endif + +/** @brief UART8 serial driver identifier.*/ +#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__) +SerialDriver SD8; +#endif + +/** @brief LPUART1 serial driver identifier.*/ +#if STM32_SERIAL_USE_LPUART1 || defined(__DOXYGEN__) +SerialDriver LPSD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** @brief Driver default configuration.*/ +static const SerialConfig default_config = +{ + SERIAL_DEFAULT_BITRATE, + 0, + USART_CR2_STOP1_BITS, + 0 +}; + +#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__) +/** @brief Input buffer for SD1.*/ +static uint8_t sd_in_buf1[STM32_SERIAL_USART1_IN_BUF_SIZE]; + +/** @brief Output buffer for SD1.*/ +static uint8_t sd_out_buf1[STM32_SERIAL_USART1_OUT_BUF_SIZE]; +#endif + +#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__) +/** @brief Input buffer for SD2.*/ +static uint8_t sd_in_buf2[STM32_SERIAL_USART2_IN_BUF_SIZE]; + +/** @brief Output buffer for SD2.*/ +static uint8_t sd_out_buf2[STM32_SERIAL_USART2_OUT_BUF_SIZE]; +#endif + +#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__) +/** @brief Input buffer for SD3.*/ +static uint8_t sd_in_buf3[STM32_SERIAL_USART3_IN_BUF_SIZE]; + +/** @brief Output buffer for SD3.*/ +static uint8_t sd_out_buf3[STM32_SERIAL_USART3_OUT_BUF_SIZE]; +#endif + +#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__) +/** @brief Input buffer for SD4.*/ +static uint8_t sd_in_buf4[STM32_SERIAL_UART4_IN_BUF_SIZE]; + +/** @brief Output buffer for SD4.*/ +static uint8_t sd_out_buf4[STM32_SERIAL_UART4_OUT_BUF_SIZE]; +#endif + +#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__) +/** @brief Input buffer for SD5.*/ +static uint8_t sd_in_buf5[STM32_SERIAL_UART5_IN_BUF_SIZE]; + +/** @brief Output buffer for SD5.*/ +static uint8_t sd_out_buf5[STM32_SERIAL_UART5_OUT_BUF_SIZE]; +#endif + +#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__) +/** @brief Input buffer for SD6.*/ +static uint8_t sd_in_buf6[STM32_SERIAL_USART6_IN_BUF_SIZE]; + +/** @brief Output buffer for SD6.*/ +static uint8_t sd_out_buf6[STM32_SERIAL_USART6_OUT_BUF_SIZE]; +#endif + +#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__) +/** @brief Input buffer for SD7.*/ +static uint8_t sd_in_buf7[STM32_SERIAL_UART7_IN_BUF_SIZE]; + +/** @brief Output buffer for SD7.*/ +static uint8_t sd_out_buf7[STM32_SERIAL_UART7_OUT_BUF_SIZE]; +#endif + +#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__) +/** @brief Input buffer for SD8.*/ +static uint8_t sd_in_buf8[STM32_SERIAL_UART8_IN_BUF_SIZE]; + +/** @brief Output buffer for SD8.*/ +static uint8_t sd_out_buf8[STM32_SERIAL_UART8_OUT_BUF_SIZE]; +#endif + +#if STM32_SERIAL_USE_LPUART1 || defined(__DOXYGEN__) +/** @brief Input buffer for LPSD1.*/ +static uint8_t sd_in_buflp1[STM32_SERIAL_LPUART1_IN_BUF_SIZE]; + +/** @brief Output buffer for LPSD1.*/ +static uint8_t sd_out_buflp1[STM32_SERIAL_LPUART1_OUT_BUF_SIZE]; +#endif + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief USART initialization. + * @details This function must be invoked with interrupts disabled. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] config the architecture-dependent serial driver configuration + */ +static void usart_init(SerialDriver *sdp, const SerialConfig *config) { + uint32_t brr; + USART_TypeDef *u = sdp->usart; + + /* Baud rate setting.*/ +#if STM32_SERIAL_USE_LPUART1 + if (sdp == &LPSD1) { + osalDbgAssert((sdp->clock >= config->speed * 3U) && + (sdp->clock <= config->speed * 4096U), + "invalid baud rate vs input clock"); + + brr = (uint32_t)(((uint64_t)sdp->clock * 256) / config->speed); + + osalDbgAssert((brr >= 0x300) && (brr < 0x100000), "invalid BRR value"); + } + else +#endif + { + brr = (uint32_t)(sdp->clock / config->speed); + + /* Correcting BRR value when oversampling by 8 instead of 16. + Fraction is still 4 bits wide, but only lower 3 bits used. + Mantissa is doubled, but Fraction is left the same.*/ + if (config->cr1 & USART_CR1_OVER8) + brr = ((brr & ~7) * 2) | (brr & 7); + + osalDbgAssert(brr < 0x10000, "invalid BRR value"); + } + u->BRR = brr; + + /* Note that some bits are enforced.*/ + u->CR2 = config->cr2 | USART_CR2_LBDIE; + u->CR3 = config->cr3 | USART_CR3_EIE; + u->CR1 = config->cr1 | USART_CR1_UE | USART_CR1_PEIE | + USART_CR1_RXNEIE | USART_CR1_TE | + USART_CR1_RE; + u->ICR = 0xFFFFFFFFU; + + /* Deciding mask to be applied on the data register on receive, this is + required in order to mask out the parity bit.*/ + if ((config->cr1 & USART_CR1_PCE) != 0U) { + switch (config->cr1 & (USART_CR1_M_1 | USART_CR1_M_0)) { + case 0: + sdp->rxmask = 0x7F; + break; + case USART_CR1_M_1: + sdp->rxmask = 0x3F; + break; + default: + sdp->rxmask = 0xFF; + } + } + else { + sdp->rxmask = 0xFF; + } +} + +/** + * @brief USART de-initialization. + * @details This function must be invoked with interrupts disabled. + * + * @param[in] u pointer to an USART I/O block + */ +static void usart_deinit(USART_TypeDef *u) { + + u->CR1 = 0; + u->CR2 = 0; + u->CR3 = 0; +} + +/** + * @brief Error handling routine. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] isr USART ISR register value + */ +static void set_error(SerialDriver *sdp, uint32_t isr) { + eventflags_t sts = 0; + + if (isr & USART_ISR_ORE) + sts |= SD_OVERRUN_ERROR; + if (isr & USART_ISR_PE) + sts |= SD_PARITY_ERROR; + if (isr & USART_ISR_FE) + sts |= SD_FRAMING_ERROR; + if (isr & USART_ISR_NE) + sts |= SD_NOISE_ERROR; + osalSysLockFromISR(); + chnAddFlagsI(sdp, sts); + osalSysUnlockFromISR(); +} + +#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__) +static void notify1(io_queue_t *qp) { + + (void)qp; + USART1->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__) +static void notify2(io_queue_t *qp) { + + (void)qp; + USART2->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__) +static void notify3(io_queue_t *qp) { + + (void)qp; + USART3->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__) +static void notify4(io_queue_t *qp) { + + (void)qp; + UART4->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__) +static void notify5(io_queue_t *qp) { + + (void)qp; + UART5->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__) +static void notify6(io_queue_t *qp) { + + (void)qp; + USART6->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__) +static void notify7(io_queue_t *qp) { + + (void)qp; + UART7->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__) +static void notify8(io_queue_t *qp) { + + (void)qp; + UART8->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +#if STM32_SERIAL_USE_LPUART1 || defined(__DOXYGEN__) +static void notifylp1(io_queue_t *qp) { + + (void)qp; + LPUART1->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE; +} +#endif + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__) +#if !defined(STM32_USART1_SUPPRESS_ISR) +#if !defined(STM32_USART1_HANDLER) +#error "STM32_USART1_HANDLER not defined" +#endif +/** + * @brief USART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + sd_lld_serve_interrupt(&SD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__) +#if !defined(STM32_USART2_SUPPRESS_ISR) +#if !defined(STM32_USART2_HANDLER) +#error "STM32_USART2_HANDLER not defined" +#endif +/** + * @brief USART2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + sd_lld_serve_interrupt(&SD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__) +#if !defined(STM32_USART3_SUPPRESS_ISR) +#if !defined(STM32_USART3_HANDLER) +#error "STM32_USART3_HANDLER not defined" +#endif +/** + * @brief USART3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + sd_lld_serve_interrupt(&SD3); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__) +#if !defined(STM32_UART4_SUPPRESS_ISR) +#if !defined(STM32_UART4_HANDLER) +#error "STM32_UART4_HANDLER not defined" +#endif +/** + * @brief UART4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + sd_lld_serve_interrupt(&SD4); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__) +#if !defined(STM32_UART5_SUPPRESS_ISR) +#if !defined(STM32_UART5_HANDLER) +#error "STM32_UART5_HANDLER not defined" +#endif +/** + * @brief UART5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + sd_lld_serve_interrupt(&SD5); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__) +#if !defined(STM32_USART6_SUPPRESS_ISR) +#if !defined(STM32_USART6_HANDLER) +#error "STM32_USART6_HANDLER not defined" +#endif +/** + * @brief USART6 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + sd_lld_serve_interrupt(&SD6); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__) +#if !defined(STM32_UART7_SUPPRESS_ISR) +#if !defined(STM32_UART7_HANDLER) +#error "STM32_UART7_HANDLER not defined" +#endif +/** + * @brief UART7 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + sd_lld_serve_interrupt(&SD7); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__) +#if !defined(STM32_UART8_SUPPRESS_ISR) +#if !defined(STM32_UART8_HANDLER) +#error "STM32_UART8_HANDLER not defined" +#endif +/** + * @brief UART8 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + sd_lld_serve_interrupt(&SD8); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_SERIAL_USE_LPUART1 || defined(__DOXYGEN__) +#if !defined(STM32_LPUART1_SUPPRESS_ISR) +#if !defined(STM32_LPUART1_HANDLER) +#error "STM32_LPUART1_HANDLER not defined" +#endif +/** + * @brief LPUART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_LPUART1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + sd_lld_serve_interrupt(&LPSD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level serial driver initialization. + * + * @notapi + */ +void sd_lld_init(void) { + +#if STM32_SERIAL_USE_USART1 + sdObjectInit(&SD1); + iqObjectInit(&SD1.iqueue, sd_in_buf1, sizeof sd_in_buf1, NULL, &SD1); + oqObjectInit(&SD1.oqueue, sd_out_buf1, sizeof sd_out_buf1, notify1, &SD1); + SD1.usart = USART1; + SD1.clock = STM32_USART1CLK; +#if !defined(STM32_USART1_SUPPRESS_ISR) && defined(STM32_USART1_NUMBER) + nvicEnableVector(STM32_USART1_NUMBER, STM32_SERIAL_USART1_PRIORITY); +#endif +#endif + +#if STM32_SERIAL_USE_USART2 + sdObjectInit(&SD2); + iqObjectInit(&SD2.iqueue, sd_in_buf2, sizeof sd_in_buf2, NULL, &SD2); + oqObjectInit(&SD2.oqueue, sd_out_buf2, sizeof sd_out_buf2, notify2, &SD2); + SD2.usart = USART2; + SD2.clock = STM32_USART2CLK; +#if !defined(STM32_USART2_SUPPRESS_ISR) && defined(STM32_USART2_NUMBER) + nvicEnableVector(STM32_USART2_NUMBER, STM32_SERIAL_USART2_PRIORITY); +#endif +#endif + +#if STM32_SERIAL_USE_USART3 + sdObjectInit(&SD3); + iqObjectInit(&SD3.iqueue, sd_in_buf3, sizeof sd_in_buf3, NULL, &SD3); + oqObjectInit(&SD3.oqueue, sd_out_buf3, sizeof sd_out_buf3, notify3, &SD3); + SD3.usart = USART3; + SD3.clock = STM32_USART3CLK; +#if !defined(STM32_USART3_SUPPRESS_ISR) && defined(STM32_USART3_NUMBER) + nvicEnableVector(STM32_USART3_NUMBER, STM32_SERIAL_USART3_PRIORITY); +#endif +#endif + +#if STM32_SERIAL_USE_UART4 + sdObjectInit(&SD4); + iqObjectInit(&SD4.iqueue, sd_in_buf4, sizeof sd_in_buf4, NULL, &SD4); + oqObjectInit(&SD4.oqueue, sd_out_buf4, sizeof sd_out_buf4, notify4, &SD4); + SD4.usart = UART4; + SD4.clock = STM32_UART4CLK; +#if !defined(STM32_UART4_SUPPRESS_ISR) && defined(STM32_UART4_NUMBER) + nvicEnableVector(STM32_UART4_NUMBER, STM32_SERIAL_UART4_PRIORITY); +#endif +#endif + +#if STM32_SERIAL_USE_UART5 + sdObjectInit(&SD5); + iqObjectInit(&SD5.iqueue, sd_in_buf5, sizeof sd_in_buf5, NULL, &SD5); + oqObjectInit(&SD5.oqueue, sd_out_buf5, sizeof sd_out_buf5, notify5, &SD5); + SD5.usart = UART5; + SD5.clock = STM32_UART5CLK; +#if !defined(STM32_UART5_SUPPRESS_ISR) && defined(STM32_UART5_NUMBER) + nvicEnableVector(STM32_UART5_NUMBER, STM32_SERIAL_UART5_PRIORITY); +#endif +#endif + +#if STM32_SERIAL_USE_USART6 + sdObjectInit(&SD6); + iqObjectInit(&SD6.iqueue, sd_in_buf6, sizeof sd_in_buf6, NULL, &SD6); + oqObjectInit(&SD6.oqueue, sd_out_buf6, sizeof sd_out_buf6, notify6, &SD6); + SD6.usart = USART6; + SD6.clock = STM32_USART6CLK; +#if !defined(STM32_USART6_SUPPRESS_ISR) && defined(STM32_USART6_NUMBER) + nvicEnableVector(STM32_USART6_NUMBER, STM32_SERIAL_USART6_PRIORITY); +#endif +#endif + +#if STM32_SERIAL_USE_UART7 + sdObjectInit(&SD7); + iqObjectInit(&SD7.iqueue, sd_in_buf7, sizeof sd_in_buf7, NULL, &SD7); + oqObjectInit(&SD7.oqueue, sd_out_buf7, sizeof sd_out_buf7, notify7, &SD7); + SD7.usart = UART7; + SD7.clock = STM32_UART7CLK; +#if !defined(STM32_UART7_SUPPRESS_ISR) && defined(STM32_UART7_NUMBER) + nvicEnableVector(STM32_UART7_NUMBER, STM32_SERIAL_UART7_PRIORITY); +#endif +#endif + +#if STM32_SERIAL_USE_UART8 + sdObjectInit(&SD8); + iqObjectInit(&SD8.iqueue, sd_in_buf8, sizeof sd_in_buf8, NULL, &SD8); + oqObjectInit(&SD8.oqueue, sd_out_buf8, sizeof sd_out_buf8, notify8, &SD8); + SD8.usart = UART8; + SD8.clock = STM32_UART8CLK; +#if !defined(STM32_UART8_SUPPRESS_ISR) && defined(STM32_UART8_NUMBER) + nvicEnableVector(STM32_UART8_NUMBER, STM32_SERIAL_UART8_PRIORITY); +#endif +#endif + +#if STM32_SERIAL_USE_LPUART1 + sdObjectInit(&LPSD1); + iqObjectInit(&LPSD1.iqueue, sd_in_buflp1, sizeof sd_in_buflp1, NULL, &LPSD1); + oqObjectInit(&LPSD1.oqueue, sd_out_buflp1, sizeof sd_out_buflp1, notifylp1, &LPSD1); + LPSD1.usart = LPUART1; + LPSD1.clock = STM32_LPUART1CLK; +#if !defined(STM32_LPUART1_SUPPRESS_ISR) && defined(STM32_LPUART1_NUMBER) + nvicEnableVector(STM32_LPUART1_NUMBER, STM32_SERIAL_LPUART1_PRIORITY); +#endif +#endif +} + +/** + * @brief Low level serial driver configuration and (re)start. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] config the architecture-dependent serial driver configuration. + * If this parameter is set to @p NULL then a default + * configuration is used. + * + * @notapi + */ +void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { + + if (config == NULL) + config = &default_config; + + if (sdp->state == SD_STOP) { +#if STM32_SERIAL_USE_USART1 + if (&SD1 == sdp) { + rccEnableUSART1(true); + } +#endif +#if STM32_SERIAL_USE_USART2 + if (&SD2 == sdp) { + rccEnableUSART2(true); + } +#endif +#if STM32_SERIAL_USE_USART3 + if (&SD3 == sdp) { + rccEnableUSART3(true); + } +#endif +#if STM32_SERIAL_USE_UART4 + if (&SD4 == sdp) { + rccEnableUART4(true); + } +#endif +#if STM32_SERIAL_USE_UART5 + if (&SD5 == sdp) { + rccEnableUART5(true); + } +#endif +#if STM32_SERIAL_USE_USART6 + if (&SD6 == sdp) { + rccEnableUSART6(true); + } +#endif +#if STM32_SERIAL_USE_UART7 + if (&SD7 == sdp) { + rccEnableUART7(true); + } +#endif +#if STM32_SERIAL_USE_UART8 + if (&SD8 == sdp) { + rccEnableUART8(true); + } +#endif +#if STM32_SERIAL_USE_LPUART1 + if (&LPSD1 == sdp) { + rccEnableLPUART1(true); + } +#endif + } + usart_init(sdp, config); +} + +/** + * @brief Low level serial driver stop. + * @details De-initializes the USART, stops the associated clock, resets the + * interrupt vector. + * + * @param[in] sdp pointer to a @p SerialDriver object + * + * @notapi + */ +void sd_lld_stop(SerialDriver *sdp) { + + if (sdp->state == SD_READY) { + /* UART is de-initialized then clocks are disabled.*/ + usart_deinit(sdp->usart); + +#if STM32_SERIAL_USE_USART1 + if (&SD1 == sdp) { + rccDisableUSART1(); + return; + } +#endif +#if STM32_SERIAL_USE_USART2 + if (&SD2 == sdp) { + rccDisableUSART2(); + return; + } +#endif +#if STM32_SERIAL_USE_USART3 + if (&SD3 == sdp) { + rccDisableUSART3(); + return; + } +#endif +#if STM32_SERIAL_USE_UART4 + if (&SD4 == sdp) { + rccDisableUART4(); + return; + } +#endif +#if STM32_SERIAL_USE_UART5 + if (&SD5 == sdp) { + rccDisableUART5(); + return; + } +#endif +#if STM32_SERIAL_USE_USART6 + if (&SD6 == sdp) { + rccDisableUSART6(); + return; + } +#endif +#if STM32_SERIAL_USE_UART7 + if (&SD7 == sdp) { + rccDisableUART7(); + return; + } +#endif +#if STM32_SERIAL_USE_UART8 + if (&SD8 == sdp) { + rccDisableUART8(); + return; + } +#endif +#if STM32_SERIAL_USE_LPUART1 + if (&LPSD1 == sdp) { + rccDisableLPUART1(); + return; + } +#endif + } +} + +/** + * @brief Common IRQ handler. + * + * @param[in] sdp communication channel associated to the USART + */ +void sd_lld_serve_interrupt(SerialDriver *sdp) { + USART_TypeDef *u = sdp->usart; + uint32_t cr1 = u->CR1; + uint32_t isr; + + /* Reading and clearing status.*/ + isr = u->ISR; + u->ICR = isr; + + /* Error condition detection.*/ + if (isr & (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE | USART_ISR_PE)) + set_error(sdp, isr); + + /* Special case, LIN break detection.*/ + if (isr & USART_ISR_LBDF) { + osalSysLockFromISR(); + chnAddFlagsI(sdp, SD_BREAK_DETECTED); + osalSysUnlockFromISR(); + } + + /* Data available, note it is a while in order to handle two situations: + 1) Another byte arrived after removing the previous one, this would cause + an extra interrupt to serve. + 2) FIFO mode is enabled on devices that support it, we need to empty + the FIFO.*/ + while (isr & USART_ISR_RXNE) { + osalSysLockFromISR(); + sdIncomingDataI(sdp, (uint8_t)u->RDR & sdp->rxmask); + osalSysUnlockFromISR(); + + isr = u->ISR; + } + + /* Transmission buffer empty, note it is a while in order to handle two + situations: + 1) The data registers has been emptied immediately after writing it, this + would cause an extra interrupt to serve. + 2) FIFO mode is enabled on devices that support it, we need to fill + the FIFO.*/ + if (cr1 & USART_CR1_TXEIE) { + while (isr & USART_ISR_TXE) { + msg_t b; + + osalSysLockFromISR(); + b = oqGetI(&sdp->oqueue); + if (b < MSG_OK) { + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + u->CR1 = cr1 & ~USART_CR1_TXEIE; + osalSysUnlockFromISR(); + break; + } + u->TDR = b; + osalSysUnlockFromISR(); + + isr = u->ISR; + } + } + + /* Physical transmission end.*/ + if ((cr1 & USART_CR1_TCIE) && (isr & USART_ISR_TC)) { + osalSysLockFromISR(); + if (oqIsEmptyI(&sdp->oqueue)) { + chnAddFlagsI(sdp, CHN_TRANSMISSION_END); + u->CR1 = cr1 & ~USART_CR1_TCIE; + } + osalSysUnlockFromISR(); + } +} + +#endif /* HAL_USE_SERIAL */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.h new file mode 100644 index 0000000..19ee329 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.h @@ -0,0 +1,534 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/hal_serial_lld.h + * @brief STM32 low level serial driver header. + * + * @addtogroup SERIAL + * @{ + */ + +#ifndef HAL_SERIAL_LLD_H +#define HAL_SERIAL_LLD_H + +#if HAL_USE_SERIAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Advanced buffering support switch. + * @details This constants enables the advanced buffering support in the + * low level driver, the queue buffer is no more part of the + * @p SerialDriver structure, each driver can have a different + * queue size. + */ +#define SERIAL_ADVANCED_BUFFERING_SUPPORT TRUE + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief USART1 driver enable switch. + * @details If set to @p TRUE the support for USART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_USART1) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_USART1 FALSE +#endif + +/** + * @brief USART2 driver enable switch. + * @details If set to @p TRUE the support for USART2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_USART2) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_USART2 FALSE +#endif + +/** + * @brief USART3 driver enable switch. + * @details If set to @p TRUE the support for USART3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_USART3) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_USART3 FALSE +#endif + +/** + * @brief UART4 driver enable switch. + * @details If set to @p TRUE the support for UART4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_UART4) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_UART4 FALSE +#endif + +/** + * @brief UART5 driver enable switch. + * @details If set to @p TRUE the support for UART5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_UART5) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_UART5 FALSE +#endif + +/** + * @brief USART6 driver enable switch. + * @details If set to @p TRUE the support for USART6 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_USART6) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_USART6 FALSE +#endif + +/** + * @brief UART7 driver enable switch. + * @details If set to @p TRUE the support for UART7 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_UART7) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_UART7 FALSE +#endif + +/** + * @brief UART8 driver enable switch. + * @details If set to @p TRUE the support for UART8 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_UART8) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_UART8 FALSE +#endif + +/** + * @brief LPUART1 driver enable switch. + * @details If set to @p TRUE the support for LPUART is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SERIAL_USE_LPUART1) || defined(__DOXYGEN__) +#define STM32_SERIAL_USE_LPUART1 FALSE +#endif + +/** + * @brief USART1 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_USART1_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART1_PRIORITY 12 +#endif + +/** + * @brief USART2 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_USART2_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART2_PRIORITY 12 +#endif + +/** + * @brief USART3 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_USART3_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART3_PRIORITY 12 +#endif + +/** + * @brief UART4 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_UART4_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART4_PRIORITY 12 +#endif + +/** + * @brief UART5 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_UART5_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART5_PRIORITY 12 +#endif + +/** + * @brief USART6 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_USART6_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART6_PRIORITY 12 +#endif + +/** + * @brief UART7 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_UART7_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART7_PRIORITY 12 +#endif + +/** + * @brief UART8 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_UART8_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART8_PRIORITY 12 +#endif + +/** + * @brief LPUART1 interrupt priority level setting. + */ +#if !defined(STM32_SERIAL_LPUART1_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SERIAL_LPUART1_PRIORITY 12 +#endif + +/** + * @brief Input buffer size for USART1. + */ +#if !defined(STM32_SERIAL_USART1_IN_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART1_IN_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Output buffer size for USART1. + */ +#if !defined(STM32_SERIAL_USART1_OUT_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART1_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Input buffer size for USART2. + */ +#if !defined(STM32_SERIAL_USART2_IN_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART2_IN_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Output buffer size for USART2. + */ +#if !defined(STM32_SERIAL_USART2_OUT_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART2_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Input buffer size for USART3. + */ +#if !defined(STM32_SERIAL_USART3_IN_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART3_IN_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Output buffer size for USART3. + */ +#if !defined(STM32_SERIAL_USART3_OUT_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART3_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Input buffer size for UART4. + */ +#if !defined(STM32_SERIAL_UART4_IN_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART4_IN_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Output buffer size for UART4. + */ +#if !defined(STM32_SERIAL_UART4_OUT_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART4_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Input buffer size for UART5. + */ +#if !defined(STM32_SERIAL_UART5_IN_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART5_IN_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Output buffer size for UART5. + */ +#if !defined(STM32_SERIAL_UART5_OUT_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART5_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Input buffer size for USART6. + */ +#if !defined(STM32_SERIAL_USART6_IN_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART6_IN_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Output buffer size for USART6. + */ +#if !defined(STM32_SERIAL_USART6_OUT_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_USART6_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Input buffer size for UART7. + */ +#if !defined(STM32_SERIAL_UART7_IN_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART7_IN_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Output buffer size for UART7. + */ +#if !defined(STM32_SERIAL_UART7_OUT_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART7_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Input buffer size for UART8. + */ +#if !defined(STM32_SERIAL_UART8_IN_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART8_IN_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Output buffer size for UART8. + */ +#if !defined(STM32_SERIAL_UART8_OUT_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_UART8_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Input buffer size for LPUART1. + */ +#if !defined(STM32_SERIAL_LPUART1_IN_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_LPUART1_IN_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif + +/** + * @brief Output buffer size for LPUART1. + */ +#if !defined(STM32_SERIAL_LPUART1_OUT_BUF_SIZE) || defined(__DOXYGEN__) +#define STM32_SERIAL_LPUART1_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_SERIAL_USE_USART1 && !STM32_HAS_USART1 +#error "USART1 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_USART2 && !STM32_HAS_USART2 +#error "USART2 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_USART3 && !STM32_HAS_USART3 +#error "USART3 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_UART4 && !STM32_HAS_UART4 +#error "UART4 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_UART5 && !STM32_HAS_UART5 +#error "UART5 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_USART6 && !STM32_HAS_USART6 +#error "USART6 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_UART7 && !STM32_HAS_UART7 +#error "UART7 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_UART8 && !STM32_HAS_UART8 +#error "UART8 not present in the selected device" +#endif + +#if STM32_SERIAL_USE_LPUART1 && !STM32_HAS_LPUART1 +#error "LPUART1 not present in the selected device" +#endif + +#if !STM32_SERIAL_USE_USART1 && !STM32_SERIAL_USE_USART2 && \ + !STM32_SERIAL_USE_USART3 && !STM32_SERIAL_USE_UART4 && \ + !STM32_SERIAL_USE_UART5 && !STM32_SERIAL_USE_USART6 && \ + !STM32_SERIAL_USE_UART7 && !STM32_SERIAL_USE_UART8 && \ + !STM32_SERIAL_USE_LPUART1 +#error "SERIAL driver activated but no USART/UART peripheral assigned" +#endif + +#if !defined(STM32_USART1_SUPPRESS_ISR) && \ + STM32_SERIAL_USE_USART1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART1_PRIORITY) +#error "Invalid IRQ priority assigned to USART1" +#endif + +#if !defined(STM32_USART2_SUPPRESS_ISR) && \ + STM32_SERIAL_USE_USART2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART2_PRIORITY) +#error "Invalid IRQ priority assigned to USART2" +#endif + +#if !defined(STM32_USART3_SUPPRESS_ISR) && \ + STM32_SERIAL_USE_USART3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART3_PRIORITY) +#error "Invalid IRQ priority assigned to USART3" +#endif + +#if !defined(STM32_UART4_SUPPRESS_ISR) && \ + STM32_SERIAL_USE_UART4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART4_PRIORITY) +#error "Invalid IRQ priority assigned to UART4" +#endif + +#if !defined(STM32_UART5_SUPPRESS_ISR) && \ + STM32_SERIAL_USE_UART5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART5_PRIORITY) +#error "Invalid IRQ priority assigned to UART5" +#endif + +#if !defined(STM32_USART6_SUPPRESS_ISR) && \ + STM32_SERIAL_USE_USART6 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART6_PRIORITY) +#error "Invalid IRQ priority assigned to USART6" +#endif + +#if !defined(STM32_UART7_SUPPRESS_ISR) && \ + STM32_SERIAL_USE_UART7 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART7_PRIORITY) +#error "Invalid IRQ priority assigned to UART7" +#endif + +#if !defined(STM32_UART8_SUPPRESS_ISR) && \ + STM32_SERIAL_USE_UART8 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART8_PRIORITY) +#error "Invalid IRQ priority assigned to UART8" +#endif + +#if !defined(STM32_LPUART1_SUPPRESS_ISR) && \ + STM32_SERIAL_USE_LPUART1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_LPUART1_PRIORITY) +#error "Invalid IRQ priority assigned to LPUART1" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief STM32 Serial Driver configuration structure. + * @details An instance of this structure must be passed to @p sdStart() + * in order to configure and start a serial driver operations. + * @note This structure content is architecture dependent, each driver + * implementation defines its own version and the custom static + * initializers. + */ +typedef struct { + /** + * @brief Bit rate. + */ + uint32_t speed; + /* End of the mandatory fields.*/ + /** + * @brief Initialization value for the CR1 register. + */ + uint32_t cr1; + /** + * @brief Initialization value for the CR2 register. + */ + uint32_t cr2; + /** + * @brief Initialization value for the CR3 register. + */ + uint32_t cr3; +} SerialConfig; + +/** + * @brief @p SerialDriver specific data. + */ +#define _serial_driver_data \ + _base_asynchronous_channel_data \ + /* Driver state.*/ \ + sdstate_t state; \ + /* Input queue.*/ \ + input_queue_t iqueue; \ + /* Output queue.*/ \ + output_queue_t oqueue; \ + /* End of the mandatory fields.*/ \ + /* Pointer to the USART registers block.*/ \ + USART_TypeDef *usart; \ + /* Clock frequency for the associated USART/UART.*/ \ + uint32_t clock; \ + /* Mask to be applied on received frames.*/ \ + uint8_t rxmask; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/* + * Extra USARTs definitions here (missing from the ST header file). + */ +#define USART_CR2_STOP1_BITS (0 << 12) /**< @brief CR2 1 stop bit value.*/ +#define USART_CR2_STOP0P5_BITS (1 << 12) /**< @brief CR2 0.5 stop bit value.*/ +#define USART_CR2_STOP2_BITS (2 << 12) /**< @brief CR2 2 stop bit value.*/ +#define USART_CR2_STOP1P5_BITS (3 << 12) /**< @brief CR2 1.5 stop bit value.*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_SERIAL_USE_USART1 && !defined(__DOXYGEN__) +extern SerialDriver SD1; +#endif +#if STM32_SERIAL_USE_USART2 && !defined(__DOXYGEN__) +extern SerialDriver SD2; +#endif +#if STM32_SERIAL_USE_USART3 && !defined(__DOXYGEN__) +extern SerialDriver SD3; +#endif +#if STM32_SERIAL_USE_UART4 && !defined(__DOXYGEN__) +extern SerialDriver SD4; +#endif +#if STM32_SERIAL_USE_UART5 && !defined(__DOXYGEN__) +extern SerialDriver SD5; +#endif +#if STM32_SERIAL_USE_USART6 && !defined(__DOXYGEN__) +extern SerialDriver SD6; +#endif +#if STM32_SERIAL_USE_UART7 && !defined(__DOXYGEN__) +extern SerialDriver SD7; +#endif +#if STM32_SERIAL_USE_UART8 && !defined(__DOXYGEN__) +extern SerialDriver SD8; +#endif +#if STM32_SERIAL_USE_LPUART1 && !defined(__DOXYGEN__) +extern SerialDriver LPSD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sd_lld_init(void); + void sd_lld_start(SerialDriver *sdp, const SerialConfig *config); + void sd_lld_stop(SerialDriver *sdp); + void sd_lld_serve_interrupt(SerialDriver *sdp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SERIAL */ + +#endif /* HAL_SERIAL_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c new file mode 100644 index 0000000..3787716 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c @@ -0,0 +1,1075 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/hal_uart_lld.c + * @brief STM32 low level UART driver code. + * + * @addtogroup UART + * @{ + */ + +#include "hal.h" + +#if HAL_USE_UART || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* For compatibility for those devices without LIN support in the USARTs.*/ +#if !defined(USART_ISR_LBDF) +#define USART_ISR_LBDF 0 +#endif + +#if !defined(USART_CR2_LBDIE) +#define USART_CR2_LBDIE 0 +#endif + +/* STM32L0xx/STM32F7xx ST headers difference.*/ +#if !defined(USART_ISR_LBDF) +#define USART_ISR_LBDF USART_ISR_LBD +#endif + +/* STM32L0xx/STM32F7xx ST headers difference.*/ +#if !defined(USART_ISR_LBDF) +#define USART_ISR_LBDF USART_ISR_LBD +#endif + +#define USART1_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART1_RX_DMA_STREAM, \ + STM32_USART1_RX_DMA_CHN) + +#define USART1_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART1_TX_DMA_STREAM, \ + STM32_USART1_TX_DMA_CHN) + +#define USART2_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART2_RX_DMA_STREAM, \ + STM32_USART2_RX_DMA_CHN) + +#define USART2_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART2_TX_DMA_STREAM, \ + STM32_USART2_TX_DMA_CHN) + +#define USART3_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART3_RX_DMA_STREAM, \ + STM32_USART3_RX_DMA_CHN) + +#define USART3_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART3_TX_DMA_STREAM, \ + STM32_USART3_TX_DMA_CHN) + +#define UART4_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART4_RX_DMA_STREAM, \ + STM32_UART4_RX_DMA_CHN) + +#define UART4_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART4_TX_DMA_STREAM, \ + STM32_UART4_TX_DMA_CHN) + +#define UART5_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART5_RX_DMA_STREAM, \ + STM32_UART5_RX_DMA_CHN) + +#define UART5_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART5_TX_DMA_STREAM, \ + STM32_UART5_TX_DMA_CHN) + +#define USART6_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART6_RX_DMA_STREAM, \ + STM32_USART6_RX_DMA_CHN) + +#define USART6_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART6_TX_DMA_STREAM, \ + STM32_USART6_TX_DMA_CHN) + +#define UART7_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART7_RX_DMA_STREAM, \ + STM32_UART7_RX_DMA_CHN) + +#define UART7_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART7_TX_DMA_STREAM, \ + STM32_UART7_TX_DMA_CHN) + +#define UART8_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART8_RX_DMA_STREAM, \ + STM32_UART8_RX_DMA_CHN) + +#define UART8_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART8_TX_DMA_STREAM, \ + STM32_UART8_TX_DMA_CHN) + +/* Workarounds for those devices where UARTs are USARTs.*/ +#if defined(USART4) +#define UART4 USART4 +#endif +#if defined(USART5) +#define UART5 USART5 +#endif +#if defined(USART7) +#define UART7 USART7 +#endif +#if defined(USART8) +#define UART8 USART8 +#endif + +/* Workaround for more differences in headers.*/ +#if !defined(USART_CR1_M0) +#define USART_CR1_M0 USART_CR1_M +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief USART1 UART driver identifier.*/ +#if STM32_UART_USE_USART1 || defined(__DOXYGEN__) +UARTDriver UARTD1; +#endif + +/** @brief USART2 UART driver identifier.*/ +#if STM32_UART_USE_USART2 || defined(__DOXYGEN__) +UARTDriver UARTD2; +#endif + +/** @brief USART3 UART driver identifier.*/ +#if STM32_UART_USE_USART3 || defined(__DOXYGEN__) +UARTDriver UARTD3; +#endif + +/** @brief UART4 UART driver identifier.*/ +#if STM32_UART_USE_UART4 || defined(__DOXYGEN__) +UARTDriver UARTD4; +#endif + +/** @brief UART5 UART driver identifier.*/ +#if STM32_UART_USE_UART5 || defined(__DOXYGEN__) +UARTDriver UARTD5; +#endif + +/** @brief USART6 UART driver identifier.*/ +#if STM32_UART_USE_USART6 || defined(__DOXYGEN__) +UARTDriver UARTD6; +#endif + +/** @brief UART7 UART driver identifier.*/ +#if STM32_UART_USE_UART7 || defined(__DOXYGEN__) +UARTDriver UARTD7; +#endif + +/** @brief UART8 UART driver identifier.*/ +#if STM32_UART_USE_UART8 || defined(__DOXYGEN__) +UARTDriver UARTD8; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Status bits translation. + * + * @param[in] isr USART SR register value + * + * @return The error flags. + */ +static uartflags_t translate_errors(uint32_t isr) { + uartflags_t sts = 0; + + if (isr & USART_ISR_ORE) + sts |= UART_OVERRUN_ERROR; + if (isr & USART_ISR_PE) + sts |= UART_PARITY_ERROR; + if (isr & USART_ISR_FE) + sts |= UART_FRAMING_ERROR; + if (isr & USART_ISR_NE) + sts |= UART_NOISE_ERROR; + if (isr & USART_ISR_LBDF) + sts |= UART_BREAK_DETECTED; + return sts; +} + +/** + * @brief Puts the receiver in the UART_RX_IDLE state. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +static void uart_enter_rx_idle_loop(UARTDriver *uartp) { + uint32_t mode; + + /* RX DMA channel preparation, if the char callback is defined then the + TCIE interrupt is enabled too.*/ + if (uartp->config->rxchar_cb == NULL) + mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC; + else + mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC | STM32_DMA_CR_TCIE; + dmaStreamSetMemory0(uartp->dmarx, &uartp->rxbuf); + dmaStreamSetTransactionSize(uartp->dmarx, 1); + dmaStreamSetMode(uartp->dmarx, uartp->dmarxmode | mode); + dmaStreamEnable(uartp->dmarx); +} + +/** + * @brief USART de-initialization. + * @details This function must be invoked with interrupts disabled. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +static void usart_stop(UARTDriver *uartp) { + + /* Stops RX and TX DMA channels.*/ + dmaStreamDisable(uartp->dmarx); + dmaStreamDisable(uartp->dmatx); + + /* Stops USART operations.*/ + uartp->usart->CR1 = 0; + uartp->usart->CR2 = 0; + uartp->usart->CR3 = 0; +} + +/** + * @brief USART initialization. + * @details This function must be invoked with interrupts disabled. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +static void usart_start(UARTDriver *uartp) { + uint32_t fck; + uint32_t cr1; + const uint32_t tmo = uartp->config->timeout; + USART_TypeDef *u = uartp->usart; + + /* Defensive programming, starting from a clean state.*/ + usart_stop(uartp); + + /* Baud rate setting.*/ + fck = (uint32_t)(uartp->clock / uartp->config->speed); + + /* Correcting USARTDIV when oversampling by 8 instead of 16. + Fraction is still 4 bits wide, but only lower 3 bits used. + Mantissa is doubled, but Fraction is left the same.*/ + if (uartp->config->cr1 & USART_CR1_OVER8) + fck = ((fck & ~7) * 2) | (fck & 7); + u->BRR = fck; + + /* Resetting eventual pending status flags.*/ + u->ICR = 0xFFFFFFFFU; + + /* Note that some bits are enforced because required for correct driver + operations.*/ + u->CR2 = uartp->config->cr2 | USART_CR2_LBDIE; + u->CR3 = uartp->config->cr3 | USART_CR3_DMAT | USART_CR3_DMAR | + USART_CR3_EIE; + + /* Mustn't ever set TCIE here - if done, it causes an immediate + interrupt.*/ + cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE; + u->CR1 = uartp->config->cr1 | cr1; + + /* Set receive timeout and checks if it is really applied.*/ + if (tmo > 0) { + osalDbgAssert(tmo <= USART_RTOR_RTO, "Timeout overflow"); + u->RTOR = tmo; + osalDbgAssert(tmo == u->RTOR, "Timeout feature unsupported in this UART"); + } + + /* Starting the receiver idle loop.*/ + uart_enter_rx_idle_loop(uartp); +} + +/** + * @brief RX DMA common service routine. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_UART_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_UART_DMA_ERROR_HOOK(uartp); + } +#else + (void)flags; +#endif + + if (uartp->rxstate == UART_RX_IDLE) { + /* Receiver in idle state, a callback is generated, if enabled, for each + received character and then the driver stays in the same state.*/ + _uart_rx_idle_code(uartp); + } + else { + /* Receiver in active state, a callback is generated, if enabled, after + a completed transfer.*/ + dmaStreamDisable(uartp->dmarx); + _uart_rx_complete_isr_code(uartp); + } +} + +/** + * @brief TX DMA common service routine. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_UART_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_UART_DMA_ERROR_HOOK(uartp); + } +#else + (void)flags; +#endif + + dmaStreamDisable(uartp->dmatx); + + /* A callback is generated, if enabled, after a completed transfer.*/ + _uart_tx1_isr_code(uartp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART_USE_USART1 || defined(__DOXYGEN__) +#if !defined(STM32_USART1_SUPPRESS_ISR) +#if !defined(STM32_USART1_HANDLER) +#error "STM32_USART1_HANDLER not defined" +#endif +/** + * @brief USART1 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uart_lld_serve_interrupt(&UARTD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_UART_USE_USART2 || defined(__DOXYGEN__) +#if !defined(STM32_USART2_SUPPRESS_ISR) +#if !defined(STM32_USART2_HANDLER) +#error "STM32_USART2_HANDLER not defined" +#endif +/** + * @brief USART2 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uart_lld_serve_interrupt(&UARTD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_UART_USE_USART3 || defined(__DOXYGEN__) +#if !defined(STM32_USART3_SUPPRESS_ISR) +#if !defined(STM32_USART3_HANDLER) +#error "STM32_USART3_HANDLER not defined" +#endif +/** + * @brief USART3 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uart_lld_serve_interrupt(&UARTD3); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_UART_USE_UART4 || defined(__DOXYGEN__) +#if !defined(STM32_UART4_SUPPRESS_ISR) +#if !defined(STM32_UART4_HANDLER) +#error "STM32_UART4_HANDLER not defined" +#endif +/** + * @brief UART4 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uart_lld_serve_interrupt(&UARTD4); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_UART_USE_UART5 || defined(__DOXYGEN__) +#if !defined(STM32_UART5_SUPPRESS_ISR) +#if !defined(STM32_UART5_HANDLER) +#error "STM32_UART5_HANDLER not defined" +#endif +/** + * @brief UART5 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uart_lld_serve_interrupt(&UARTD5); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_UART_USE_USART6 || defined(__DOXYGEN__) +#if !defined(STM32_USART6_SUPPRESS_ISR) +#if !defined(STM32_USART6_HANDLER) +#error "STM32_USART6_HANDLER not defined" +#endif +/** + * @brief USART6 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uart_lld_serve_interrupt(&UARTD6); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_UART_USE_UART7 || defined(__DOXYGEN__) +#if !defined(STM32_UART7_SUPPRESS_ISR) +#if !defined(STM32_UART7_HANDLER) +#error "STM32_UART7_HANDLER not defined" +#endif +/** + * @brief UART7 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uart_lld_serve_interrupt(&UARTD7); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +#if STM32_UART_USE_UART8 || defined(__DOXYGEN__) +#if !defined(STM32_UART8_SUPPRESS_ISR) +#if !defined(STM32_UART8_HANDLER) +#error "STM32_UART8_HANDLER not defined" +#endif +/** + * @brief UART8 IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uart_lld_serve_interrupt(&UARTD8); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level UART driver initialization. + * + * @notapi + */ +void uart_lld_init(void) { + +#if STM32_UART_USE_USART1 + uartObjectInit(&UARTD1); + UARTD1.usart = USART1; + UARTD1.clock = STM32_USART1CLK; + UARTD1.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD1.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD1.dmarx = NULL; + UARTD1.dmatx = NULL; +#if !defined(STM32_USART1_SUPPRESS_ISR) && defined(STM32_USART1_NUMBER) + nvicEnableVector(STM32_USART1_NUMBER, STM32_UART_USART1_IRQ_PRIORITY); +#endif +#endif + +#if STM32_UART_USE_USART2 + uartObjectInit(&UARTD2); + UARTD2.usart = USART2; + UARTD2.clock = STM32_USART2CLK; + UARTD2.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD2.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD2.dmarx = NULL; + UARTD2.dmatx = NULL; +#if !defined(STM32_USART2_SUPPRESS_ISR) && defined(STM32_USART2_NUMBER) + nvicEnableVector(STM32_USART2_NUMBER, STM32_UART_USART2_IRQ_PRIORITY); +#endif +#endif + +#if STM32_UART_USE_USART3 + uartObjectInit(&UARTD3); + UARTD3.usart = USART3; + UARTD3.clock = STM32_USART3CLK; + UARTD3.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD3.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD3.dmarx = NULL; + UARTD3.dmatx = NULL; +#if !defined(STM32_USART3_SUPPRESS_ISR) && defined(STM32_USART3_NUMBER) + nvicEnableVector(STM32_USART3_NUMBER, STM32_UART_USART3_IRQ_PRIORITY); +#endif +#endif + +#if STM32_UART_USE_UART4 + uartObjectInit(&UARTD4); + UARTD4.usart = UART4; + UARTD4.clock = STM32_UART4CLK; + UARTD4.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD4.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD4.dmarx = NULL; + UARTD4.dmatx = NULL; +#if !defined(STM32_UART4_SUPPRESS_ISR) && defined(STM32_UART4_NUMBER) + nvicEnableVector(STM32_UART4_NUMBER, STM32_UART_UART4_IRQ_PRIORITY); +#endif +#endif + +#if STM32_UART_USE_UART5 + uartObjectInit(&UARTD5); + UARTD5.usart = UART5; + UARTD5.clock = STM32_UART5CLK; + UARTD5.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD5.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD5.dmarx = NULL; + UARTD5.dmatx = NULL; +#if !defined(STM32_UART5_SUPPRESS_ISR) && defined(STM32_UART5_NUMBER) + nvicEnableVector(STM32_UART5_NUMBER, STM32_UART_UART5_IRQ_PRIORITY); +#endif +#endif + +#if STM32_UART_USE_USART6 + uartObjectInit(&UARTD6); + UARTD6.usart = USART6; + UARTD6.clock = STM32_USART6CLK; + UARTD6.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD6.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD6.dmarx = NULL; + UARTD6.dmatx = NULL; +#if !defined(STM32_USART6_SUPPRESS_ISR) && defined(STM32_USART6_NUMBER) + nvicEnableVector(STM32_USART6_NUMBER, STM32_UART_USART6_IRQ_PRIORITY); +#endif +#endif + +#if STM32_UART_USE_UART7 + uartObjectInit(&UARTD7); + UARTD7.usart = UART7; + UARTD7.clock = STM32_UART7CLK; + UARTD7.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD7.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD7.dmarx = NULL; + UARTD7.dmatx = NULL; +#if !defined(STM32_UART7_SUPPRESS_ISR) && defined(STM32_UART7_NUMBER) + nvicEnableVector(STM32_UART7_NUMBER, STM32_UART_UART7_IRQ_PRIORITY); +#endif +#endif + +#if STM32_UART_USE_UART8 + uartObjectInit(&UARTD8); + UARTD8.usart = UART8; + UARTD8.clock = STM32_UART8CLK; + UARTD8.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD8.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD8.dmarx = NULL; + UARTD8.dmatx = NULL; +#if !defined(STM32_UART8_SUPPRESS_ISR) && defined(STM32_UART8_NUMBER) + nvicEnableVector(STM32_UART8_NUMBER, STM32_UART_UART8_IRQ_PRIORITY); +#endif +#endif +} + +/** + * @brief Configures and activates the UART peripheral. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @notapi + */ +void uart_lld_start(UARTDriver *uartp) { + + if (uartp->state == UART_STOP) { +#if STM32_UART_USE_USART1 + if (&UARTD1 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_USART1_RX_DMA_STREAM, + STM32_UART_USART1_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_USART1_TX_DMA_STREAM, + STM32_UART_USART1_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUSART1(true); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART1_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART1_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_USART1_RX); + dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_USART1_TX); +#endif + } +#endif + +#if STM32_UART_USE_USART2 + if (&UARTD2 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_USART2_RX_DMA_STREAM, + STM32_UART_USART2_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_USART2_TX_DMA_STREAM, + STM32_UART_USART2_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUSART2(true); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART2_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART2_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART2_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART2_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_USART2_RX); + dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_USART2_TX); +#endif + } +#endif + +#if STM32_UART_USE_USART3 + if (&UARTD3 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_USART3_RX_DMA_STREAM, + STM32_UART_USART3_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_USART3_TX_DMA_STREAM, + STM32_UART_USART3_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUSART3(true); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART3_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART3_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART3_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART3_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_USART3_RX); + dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_USART3_TX); +#endif + } +#endif + +#if STM32_UART_USE_UART4 + if (&UARTD4 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_UART4_RX_DMA_STREAM, + STM32_UART_UART4_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_UART4_TX_DMA_STREAM, + STM32_UART_UART4_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUART4(true); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART4_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART4_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART4_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART4_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_UART4_RX); + dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_UART4_TX); +#endif + } +#endif + +#if STM32_UART_USE_UART5 + if (&UARTD5 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_UART5_RX_DMA_STREAM, + STM32_UART_UART5_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_UART5_TX_DMA_STREAM, + STM32_UART_UART5_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUART5(true); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART5_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART5_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART5_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART5_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_UART5_RX); + dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_UART5_TX); +#endif + } +#endif + +#if STM32_UART_USE_USART6 + if (&UARTD6 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_USART6_RX_DMA_STREAM, + STM32_UART_USART6_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_USART6_TX_DMA_STREAM, + STM32_UART_USART6_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUSART6(true); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART6_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART6_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART6_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_USART6_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_USART6_RX); + dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_USART6_TX); +#endif + } +#endif + +#if STM32_UART_USE_UART7 + if (&UARTD7 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_UART7_RX_DMA_STREAM, + STM32_UART_UART7_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_UART7_TX_DMA_STREAM, + STM32_UART_UART7_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUART7(true); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART7_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART7_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART7_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART7_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_UART7_RX); + dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_UART7_TX); +#endif + } +#endif + +#if STM32_UART_USE_UART8 + if (&UARTD8 == uartp) { + uartp->dmarx = dmaStreamAllocI(STM32_UART_UART8_RX_DMA_STREAM, + STM32_UART_UART8_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream"); + uartp->dmatx = dmaStreamAllocI(STM32_UART_UART8_TX_DMA_STREAM, + STM32_UART_UART8_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream"); + + rccEnableUART8(true); + uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART8_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART8_DMA_PRIORITY); + uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART8_TX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART8_DMA_PRIORITY); +#if STM32_DMA_SUPPORTS_DMAMUX + dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_UART8_RX); + dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_UART8_TX); +#endif + } +#endif + + /* Static DMA setup, the transfer size depends on the USART settings, + it is 16 bits if M=1 and PCE=0 else it is 8 bits.*/ + if ((uartp->config->cr1 & (USART_CR1_M | USART_CR1_PCE)) == USART_CR1_M0) { + uartp->dmarxmode |= STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + uartp->dmatxmode |= STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + } + dmaStreamSetPeripheral(uartp->dmarx, &uartp->usart->RDR); + dmaStreamSetPeripheral(uartp->dmatx, &uartp->usart->TDR); + uartp->rxbuf = 0; + } + + uartp->rxstate = UART_RX_IDLE; + uartp->txstate = UART_TX_IDLE; + usart_start(uartp); +} + +/** + * @brief Deactivates the UART peripheral. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @notapi + */ +void uart_lld_stop(UARTDriver *uartp) { + + if (uartp->state == UART_READY) { + usart_stop(uartp); + dmaStreamFreeI(uartp->dmarx); + dmaStreamFreeI(uartp->dmatx); + uartp->dmarx = NULL; + uartp->dmatx = NULL; + +#if STM32_UART_USE_USART1 + if (&UARTD1 == uartp) { + rccDisableUSART1(); + return; + } +#endif + +#if STM32_UART_USE_USART2 + if (&UARTD2 == uartp) { + rccDisableUSART2(); + return; + } +#endif + +#if STM32_UART_USE_USART3 + if (&UARTD3 == uartp) { + rccDisableUSART3(); + return; + } +#endif + +#if STM32_UART_USE_UART4 + if (&UARTD4 == uartp) { + rccDisableUART4(); + return; + } +#endif + +#if STM32_UART_USE_UART5 + if (&UARTD5 == uartp) { + rccDisableUART5(); + return; + } +#endif + +#if STM32_UART_USE_USART6 + if (&UARTD6 == uartp) { + rccDisableUSART6(); + return; + } +#endif + +#if STM32_UART_USE_UART7 + if (&UARTD7 == uartp) { + rccDisableUART7(); + return; + } +#endif + +#if STM32_UART_USE_UART8 + if (&UARTD8 == uartp) { + rccDisableUART8(); + return; + } +#endif + } +} + +/** + * @brief Starts a transmission on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) { + + /* TX DMA channel preparation.*/ + dmaStreamSetMemory0(uartp->dmatx, txbuf); + dmaStreamSetTransactionSize(uartp->dmatx, n); + dmaStreamSetMode(uartp->dmatx, uartp->dmatxmode | STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE); + + /* Only enable TC interrupt if there's a callback attached to it or + if called from uartSendFullTimeout(). Also we need to clear TC flag + which could be set before.*/ +#if UART_USE_WAIT == TRUE + if ((uartp->config->txend2_cb != NULL) || (uartp->early == false)) { +#else + if (uartp->config->txend2_cb != NULL) { +#endif + uartp->usart->ICR = USART_ICR_TCCF; + uartp->usart->CR1 |= USART_CR1_TCIE; + } + + /* Starting transfer.*/ + dmaStreamEnable(uartp->dmatx); +} + +/** + * @brief Stops any ongoing transmission. + * @note Stopping a transmission also suppresses the transmission callbacks. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not transmitted by the + * stopped transmit operation. + * + * @notapi + */ +size_t uart_lld_stop_send(UARTDriver *uartp) { + + dmaStreamDisable(uartp->dmatx); + + return dmaStreamGetTransactionSize(uartp->dmatx); +} + +/** + * @brief Starts a receive operation on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to send + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) { + + /* Stopping previous activity (idle state).*/ + dmaStreamDisable(uartp->dmarx); + + /* RX DMA channel preparation.*/ + dmaStreamSetMemory0(uartp->dmarx, rxbuf); + dmaStreamSetTransactionSize(uartp->dmarx, n); + dmaStreamSetMode(uartp->dmarx, uartp->dmarxmode | STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE); + + /* Starting transfer.*/ + dmaStreamEnable(uartp->dmarx); +} + +/** + * @brief Stops any ongoing receive operation. + * @note Stopping a receive operation also suppresses the receive callbacks. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not received by the + * stopped receive operation. + * + * @notapi + */ +size_t uart_lld_stop_receive(UARTDriver *uartp) { + size_t n; + + dmaStreamDisable(uartp->dmarx); + n = dmaStreamGetTransactionSize(uartp->dmarx); + uart_enter_rx_idle_loop(uartp); + + return n; +} + +/** + * @brief USART common service routine. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +void uart_lld_serve_interrupt(UARTDriver *uartp) { + uint32_t isr; + USART_TypeDef *u = uartp->usart; + uint32_t cr1 = u->CR1; + + /* Reading and clearing status.*/ + isr = u->ISR; + u->ICR = isr; + + if (isr & (USART_ISR_LBDF | USART_ISR_ORE | USART_ISR_NE | + USART_ISR_FE | USART_ISR_PE)) { + _uart_rx_error_isr_code(uartp, translate_errors(isr)); + } + + if ((isr & USART_ISR_TC) && (cr1 & USART_CR1_TCIE)) { + /* TC interrupt disabled.*/ + u->CR1 = cr1 & ~USART_CR1_TCIE; + + /* End of transmission, a callback is generated.*/ + _uart_tx2_isr_code(uartp); + } + + /* Timeout interrupt sources are only checked if enabled in CR1.*/ + if (((cr1 & USART_CR1_IDLEIE) && (isr & USART_ISR_IDLE)) || + ((cr1 & USART_CR1_RTOIE) && (isr & USART_ISR_RTOF))) { + _uart_timeout_isr_code(uartp); + } +} + +#endif /* HAL_USE_UART */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h new file mode 100644 index 0000000..ec5a694 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h @@ -0,0 +1,842 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/hal_uart_lld.h + * @brief STM32 low level UART driver header. + * + * @addtogroup UART + * @{ + */ + +#ifndef HAL_UART_LLD_H +#define HAL_UART_LLD_H + +#if HAL_USE_UART || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief UART driver on USART1 enable switch. + * @details If set to @p TRUE the support for USART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_USART1) || defined(__DOXYGEN__) +#define STM32_UART_USE_USART1 FALSE +#endif + +/** + * @brief UART driver on USART2 enable switch. + * @details If set to @p TRUE the support for USART2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_USART2) || defined(__DOXYGEN__) +#define STM32_UART_USE_USART2 FALSE +#endif + +/** + * @brief UART driver on USART3 enable switch. + * @details If set to @p TRUE the support for USART3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_USART3) || defined(__DOXYGEN__) +#define STM32_UART_USE_USART3 FALSE +#endif + +/** + * @brief UART driver on UART4 enable switch. + * @details If set to @p TRUE the support for UART4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART4) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART4 FALSE +#endif + +/** + * @brief UART driver on UART5 enable switch. + * @details If set to @p TRUE the support for UART5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART5) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART5 FALSE +#endif + +/** + * @brief UART driver on USART6 enable switch. + * @details If set to @p TRUE the support for USART6 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_USART6) || defined(__DOXYGEN__) +#define STM32_UART_USE_USART6 FALSE +#endif + +/** + * @brief UART driver on UART7 enable switch. + * @details If set to @p TRUE the support for UART7 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART7) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART7 FALSE +#endif + +/** + * @brief UART driver on UART8 enable switch. + * @details If set to @p TRUE the support for UART8 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART8) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART8 FALSE +#endif + +/** + * @brief USART1 interrupt priority level setting. + */ +#if !defined(STM32_UART_USART1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART1_IRQ_PRIORITY 12 +#endif + +/** + * @brief USART2 interrupt priority level setting. + */ +#if !defined(STM32_UART_USART2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART2_IRQ_PRIORITY 12 +#endif + +/** + * @brief USART3 interrupt priority level setting. + */ +#if !defined(STM32_UART_USART3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART3_IRQ_PRIORITY 12 +#endif + +/** + * @brief UART4 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART4_IRQ_PRIORITY 12 +#endif + +/** + * @brief UART5 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART5_IRQ_PRIORITY 12 +#endif + +/** + * @brief USART6 interrupt priority level setting. + */ +#if !defined(STM32_UART_USART6_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART6_IRQ_PRIORITY 12 +#endif + +/** + * @brief UART7 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART7_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART7_IRQ_PRIORITY 12 +#endif + +/** + * @brief UART8 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART8_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART8_IRQ_PRIORITY 12 +#endif + +/** + * @brief USART1 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_USART1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART1_DMA_PRIORITY 0 +#endif + +/** + * @brief USART2 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_USART2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART2_DMA_PRIORITY 0 +#endif + +/** + * @brief USART3 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_USART3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART3_DMA_PRIORITY 0 +#endif + +/** + * @brief UART4 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_UART4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART4_DMA_PRIORITY 0 +#endif + +/** + * @brief UART5 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_UART5_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART5_DMA_PRIORITY 0 +#endif + +/** + * @brief USART6 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_USART6_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_USART6_DMA_PRIORITY 0 +#endif + +/** + * @brief UART7 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_UART7_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART7_DMA_PRIORITY 0 +#endif + +/** + * @brief UART8 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA channels but + * because of the channels ordering the RX channel has always priority + * over the TX channel. + */ +#if !defined(STM32_UART_UART8_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART8_DMA_PRIORITY 0 +#endif + +/** + * @brief UART DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(STM32_UART_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_UART_USE_USART1 && !STM32_HAS_USART1 +#error "USART1 not present in the selected device" +#endif + +#if STM32_UART_USE_USART2 && !STM32_HAS_USART2 +#error "USART2 not present in the selected device" +#endif + +#if STM32_UART_USE_USART3 && !STM32_HAS_USART3 +#error "USART3 not present in the selected device" +#endif + +#if STM32_UART_USE_UART4 && !STM32_HAS_UART4 +#error "UART4 not present in the selected device" +#endif + +#if STM32_UART_USE_UART5 && !STM32_HAS_UART5 +#error "UART5 not present in the selected device" +#endif + +#if STM32_UART_USE_UART7 && !STM32_HAS_UART7 +#error "UART7 not present in the selected device" +#endif + +#if STM32_UART_USE_UART8 && !STM32_HAS_UART8 +#error "UART8 not present in the selected device" +#endif + +#if !STM32_UART_USE_USART1 && !STM32_UART_USE_USART2 && \ + !STM32_UART_USE_USART3 && !STM32_UART_USE_UART4 && \ + !STM32_UART_USE_UART5 && !STM32_UART_USE_USART6 && \ + !STM32_UART_USE_UART7 && !STM32_UART_USE_UART8 +#error "UART driver activated but no USART/UART peripheral assigned" +#endif + +#if !defined(STM32_USART1_SUPPRESS_ISR) && \ + STM32_UART_USE_USART1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USART1" +#endif + +#if !defined(STM32_USART2_SUPPRESS_ISR) && \ + STM32_UART_USE_USART2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USART2" +#endif + +#if !defined(STM32_USART3_SUPPRESS_ISR) && \ + STM32_UART_USE_USART3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USART3" +#endif + +#if !defined(STM32_UART4_SUPPRESS_ISR) && \ + STM32_UART_USE_UART4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART4" +#endif + +#if !defined(STM32_UART5_SUPPRESS_ISR) && \ + STM32_UART_USE_UART5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART5" +#endif + +#if !defined(STM32_USART6_SUPPRESS_ISR) && \ + STM32_UART_USE_USART6 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART6_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USART6" +#endif + +#if !defined(STM32_UART7_SUPPRESS_ISR) && \ + STM32_UART_USE_UART7 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART7_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART7" +#endif + +#if !defined(STM32_UART8_SUPPRESS_ISR) && \ + STM32_UART_USE_UART8 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART8_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART8" +#endif + +/* Check on DMA priorities.*/ +#if STM32_UART_USE_USART1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to USART1" +#endif + +#if STM32_UART_USE_USART2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to USART2" +#endif + +#if STM32_UART_USE_USART3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to USART3" +#endif + +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART4" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART5_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART5" +#endif + +#if STM32_UART_USE_USART6 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART6_DMA_PRIORITY) +#error "Invalid DMA priority assigned to USART6" +#endif + +#if STM32_UART_USE_UART7 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART7_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART7" +#endif + +#if STM32_UART_USE_UART8 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART8_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART8" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_UART_USE_USART1 && (!defined(STM32_UART_USART1_RX_DMA_STREAM) || \ + !defined(STM32_UART_USART1_TX_DMA_STREAM)) +#error "USART1 DMA streams not defined" +#endif + +#if STM32_UART_USE_USART2 && (!defined(STM32_UART_USART2_RX_DMA_STREAM) || \ + !defined(STM32_UART_USART2_TX_DMA_STREAM)) +#error "USART2 DMA streams not defined" +#endif + +#if STM32_UART_USE_USART3 && (!defined(STM32_UART_USART3_RX_DMA_STREAM) || \ + !defined(STM32_UART_USART3_TX_DMA_STREAM)) +#error "USART3 DMA streams not defined" +#endif + +#if STM32_UART_USE_UART4 && (!defined(STM32_UART_UART4_RX_DMA_STREAM) || \ + !defined(STM32_UART_UART4_TX_DMA_STREAM)) +#error "UART4 DMA streams not defined" +#endif + +#if STM32_UART_USE_UART5 && (!defined(STM32_UART_UART5_RX_DMA_STREAM) || \ + !defined(STM32_UART_UART5_TX_DMA_STREAM)) +#error "UART5 DMA streams not defined" +#endif + +#if STM32_UART_USE_USART6 && (!defined(STM32_UART_USART6_RX_DMA_STREAM) || \ + !defined(STM32_UART_USART6_TX_DMA_STREAM)) +#error "USART6 DMA streams not defined" +#endif + +#if STM32_UART_USE_UART7 && (!defined(STM32_UART_UART7_RX_DMA_STREAM) || \ + !defined(STM32_UART_UART7_TX_DMA_STREAM)) +#error "UART7 DMA streams not defined" +#endif + +#if STM32_UART_USE_UART8 && (!defined(STM32_UART_UART8_RX_DMA_STREAM) || \ + !defined(STM32_UART_UART8_TX_DMA_STREAM)) +#error "UART8 DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_UART_USE_USART1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART1_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to USART1 RX" +#endif + +#if STM32_UART_USE_USART1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART1_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to USART1 TX" +#endif + +#if STM32_UART_USE_USART2 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART2_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to USART2 RX" +#endif + +#if STM32_UART_USE_USART2 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART2_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to USART2 TX" +#endif + +#if STM32_UART_USE_USART3 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART3_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to USART3 RX" +#endif + +#if STM32_UART_USE_USART3 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART3_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to USART3 TX" +#endif + +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART4_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to UART4 RX" +#endif + +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART4_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to UART4 TX" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART5_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to UART5 RX" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART5_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to UART5 TX" +#endif + +#if STM32_UART_USE_USART6 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART6_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to USART6 RX" +#endif + +#if STM32_UART_USE_USART6 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART6_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to USART6 TX" +#endif + +#if STM32_UART_USE_UART7 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART7_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to UART7 RX" +#endif + +#if STM32_UART_USE_UART7 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART7_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to UART7 TX" +#endif + +#if STM32_UART_USE_UART8 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART8_RX_DMA_STREAM) +#error "Invalid DMA channel assigned to UART8 RX" +#endif + +#if STM32_UART_USE_UART8 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART8_TX_DMA_STREAM) +#error "Invalid DMA channel assigned to UART8 TX" +#endif + +/* Devices without DMAMUX require an additional check.*/ +#if STM32_ADVANCED_DMA && !STM32_DMA_SUPPORTS_DMAMUX + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_UART_USE_USART1 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_RX_DMA_STREAM, \ + STM32_USART1_RX_DMA_MSK) +#error "invalid DMA stream associated to USART1 RX" +#endif + +#if STM32_UART_USE_USART1 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_TX_DMA_STREAM, \ + STM32_USART1_TX_DMA_MSK) +#error "invalid DMA stream associated to USART1 TX" +#endif + +#if STM32_UART_USE_USART2 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_RX_DMA_STREAM, \ + STM32_USART2_RX_DMA_MSK) +#error "invalid DMA stream associated to USART2 RX" +#endif + +#if STM32_UART_USE_USART2 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_TX_DMA_STREAM, \ + STM32_USART2_TX_DMA_MSK) +#error "invalid DMA stream associated to USART2 TX" +#endif + +#if STM32_UART_USE_USART3 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_RX_DMA_STREAM, \ + STM32_USART3_RX_DMA_MSK) +#error "invalid DMA stream associated to USART3 RX" +#endif + +#if STM32_UART_USE_USART3 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_TX_DMA_STREAM, \ + STM32_USART3_TX_DMA_MSK) +#error "invalid DMA stream associated to USART3 TX" +#endif + +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_RX_DMA_STREAM, \ + STM32_UART4_RX_DMA_MSK) +#error "invalid DMA stream associated to UART4 RX" +#endif + +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_TX_DMA_STREAM, \ + STM32_UART4_TX_DMA_MSK) +#error "invalid DMA stream associated to UART4 TX" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_RX_DMA_STREAM, \ + STM32_UART5_RX_DMA_MSK) +#error "invalid DMA stream associated to UART5 RX" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_TX_DMA_STREAM, \ + STM32_UART5_TX_DMA_MSK) +#error "invalid DMA stream associated to UART5 TX" +#endif + +#if STM32_UART_USE_USART6 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART6_RX_DMA_STREAM, \ + STM32_USART6_RX_DMA_MSK) +#error "invalid DMA stream associated to USART6 RX" +#endif + +#if STM32_UART_USE_USART6 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_USART6_TX_DMA_STREAM, \ + STM32_USART6_TX_DMA_MSK) +#error "invalid DMA stream associated to USART6 TX" +#endif + +#if STM32_UART_USE_UART7 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART7_RX_DMA_STREAM, \ + STM32_UART7_RX_DMA_MSK) +#error "invalid DMA stream associated to UART7 RX" +#endif + +#if STM32_UART_USE_UART7 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART7_TX_DMA_STREAM, \ + STM32_UART7_TX_DMA_MSK) +#error "invalid DMA stream associated to UART7 TX" +#endif + +#if STM32_UART_USE_UART8 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART8_RX_DMA_STREAM, \ + STM32_UART8_RX_DMA_MSK) +#error "invalid DMA stream associated to UART8 RX" +#endif + +#if STM32_UART_USE_UART8 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART8_TX_DMA_STREAM, \ + STM32_UART8_TX_DMA_MSK) +#error "invalid DMA stream associated to UART8 TX" +#endif + +#endif /* STM32_ADVANCED_DMA && !STM32_DMA_SUPPORTS_DMAMUX */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief UART driver condition flags type. + */ +typedef uint32_t uartflags_t; + +/** + * @brief Structure representing an UART driver. + */ +typedef struct UARTDriver UARTDriver; + +/** + * @brief Generic UART notification callback type. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +typedef void (*uartcb_t)(UARTDriver *uartp); + +/** + * @brief Character received UART notification callback type. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] c received character + */ +typedef void (*uartccb_t)(UARTDriver *uartp, uint16_t c); + +/** + * @brief Receive error UART notification callback type. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] e receive error mask + */ +typedef void (*uartecb_t)(UARTDriver *uartp, uartflags_t e); + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief End of transmission buffer callback. + */ + uartcb_t txend1_cb; + /** + * @brief Physical end of transmission callback. + */ + uartcb_t txend2_cb; + /** + * @brief Receive buffer filled callback. + */ + uartcb_t rxend_cb; + /** + * @brief Character received while out if the @p UART_RECEIVE state. + */ + uartccb_t rxchar_cb; + /** + * @brief Receive error callback. + */ + uartecb_t rxerr_cb; + /* End of the mandatory fields.*/ + /** + * @brief Receiver timeout callback. + * @details Handles both idle and timeout interrupts depending on configured + * flags in CR registers and supported hardware features. + */ + uartcb_t timeout_cb; + /** + * @brief Receiver timeout value in terms of number of bit duration. + * @details Set it to 0 when you want to handle idle interrupt instead of + * hardware timeout. + */ + uint32_t timeout; + /** + * @brief Bit rate. + */ + uint32_t speed; + /** + * @brief Initialization value for the CR1 register. + */ + uint32_t cr1; + /** + * @brief Initialization value for the CR2 register. + */ + uint32_t cr2; + /** + * @brief Initialization value for the CR3 register. + */ + uint32_t cr3; +} UARTConfig; + +/** + * @brief Structure representing an UART driver. + */ +struct UARTDriver { + /** + * @brief Driver state. + */ + uartstate_t state; + /** + * @brief Transmitter state. + */ + uarttxstate_t txstate; + /** + * @brief Receiver state. + */ + uartrxstate_t rxstate; + /** + * @brief Current configuration data. + */ + const UARTConfig *config; +#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Synchronization flag for transmit operations. + */ + bool early; + /** + * @brief Waiting thread on RX. + */ + thread_reference_t threadrx; + /** + * @brief Waiting thread on TX. + */ + thread_reference_t threadtx; +#endif /* UART_USE_WAIT */ +#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the peripheral. + */ + mutex_t mutex; +#endif /* UART_USE_MUTUAL_EXCLUSION */ +#if defined(UART_DRIVER_EXT_FIELDS) + UART_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the USART registers block. + */ + USART_TypeDef *usart; + /** + * @brief Clock frequency for the associated USART/UART. + */ + uint32_t clock; + /** + * @brief Receive DMA mode bit mask. + */ + uint32_t dmarxmode; + /** + * @brief Send DMA mode bit mask. + */ + uint32_t dmatxmode; + /** + * @brief Receive DMA channel. + */ + const stm32_dma_stream_t *dmarx; + /** + * @brief Transmit DMA channel. + */ + const stm32_dma_stream_t *dmatx; + /** + * @brief Default receive buffer while into @p UART_RX_IDLE state. + */ + volatile uint16_t rxbuf; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_UART_USE_USART1 && !defined(__DOXYGEN__) +extern UARTDriver UARTD1; +#endif + +#if STM32_UART_USE_USART2 && !defined(__DOXYGEN__) +extern UARTDriver UARTD2; +#endif + +#if STM32_UART_USE_USART3 && !defined(__DOXYGEN__) +extern UARTDriver UARTD3; +#endif + +#if STM32_UART_USE_UART4 && !defined(__DOXYGEN__) +extern UARTDriver UARTD4; +#endif + +#if STM32_UART_USE_UART5 && !defined(__DOXYGEN__) +extern UARTDriver UARTD5; +#endif + +#if STM32_UART_USE_USART6 && !defined(__DOXYGEN__) +extern UARTDriver UARTD6; +#endif + +#if STM32_UART_USE_UART7 && !defined(__DOXYGEN__) +extern UARTDriver UARTD7; +#endif + +#if STM32_UART_USE_UART8 && !defined(__DOXYGEN__) +extern UARTDriver UARTD8; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void uart_lld_init(void); + void uart_lld_start(UARTDriver *uartp); + void uart_lld_stop(UARTDriver *uartp); + void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf); + size_t uart_lld_stop_send(UARTDriver *uartp); + void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf); + size_t uart_lld_stop_receive(UARTDriver *uartp); + void uart_lld_serve_interrupt(UARTDriver *uartp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_UART */ + +#endif /* HAL_UART_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_lpuart1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_lpuart1.inc new file mode 100644 index 0000000..223ce2e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_lpuart1.inc @@ -0,0 +1,110 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_lpuart1.inc + * @brief Shared LPUART1 handler. + * + * @addtogroup STM32_LPUART1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_LPUART1) +#error "STM32_HAS_LPUART1 not defined in registry" +#endif + +#if STM32_HAS_LPUART1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_LPUART1_PRIORITY) +#error "STM32_IRQ_LPUART1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_LPUART1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_LPUART1_PRIORITY" +#endif + +#endif /* STM32_HAS_LPUART1 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_LPUART1) +#define STM32_LPUART1_IS_USED TRUE +#else +#define STM32_LPUART1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void lpuart1_irq_init(void) { +#if STM32_LPUART1_IS_USED + nvicEnableVector(STM32_LPUART1_NUMBER, STM32_IRQ_LPUART1_PRIORITY); +#endif +} + +static inline void lpuart1_irq_deinit(void) { +#if STM32_LPUART1_IS_USED + nvicDisableVector(STM32_LPUART1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_LPUART1_IS_USED || defined(__DOXYGEN__) +/** + * @brief LPUART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_LPUART1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_LPUART1 + sd_lld_serve_interrupt(&LPSD1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart4.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart4.inc new file mode 100644 index 0000000..5dd7b51 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart4.inc @@ -0,0 +1,121 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_uart4.inc + * @brief Shared UART4 handler. + * + * @addtogroup STM32_UART4_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART4) +#error "STM32_HAS_UART4 not defined in registry" +#endif + +#if STM32_HAS_UART4 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_UART4_PRIORITY) +#error "STM32_IRQ_UART4_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_UART4_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_UART4_PRIORITY" +#endif + +#endif /* STM32_HAS_UART4 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) && \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#error "UART4 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) || \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#define STM32_UART4_IS_USED TRUE +#else +#define STM32_UART4_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void uart4_irq_init(void) { +#if STM32_UART4_IS_USED + nvicEnableVector(STM32_UART4_NUMBER, STM32_IRQ_UART4_PRIORITY); +#endif +} + +static inline void uart4_irq_deinit(void) { +#if STM32_UART4_IS_USED + nvicDisableVector(STM32_UART4_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART4_IS_USED || defined(__DOXYGEN__) +/** + * @brief UART4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART4 + sd_lld_serve_interrupt(&SD4); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART4 + uart_lld_serve_interrupt(&UARTD4); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart5.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart5.inc new file mode 100644 index 0000000..b382d84 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart5.inc @@ -0,0 +1,121 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_uart5.inc + * @brief Shared UART5 handler. + * + * @addtogroup STM32_UART5_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART5) +#error "STM32_HAS_UART5 not defined in registry" +#endif + +#if STM32_HAS_UART5 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_UART5_PRIORITY) +#error "STM32_IRQ_UART5_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_UART5_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_UART5_PRIORITY" +#endif + +#endif /* STM32_HAS_UART5 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART5) && \ + (HAL_USE_UART && STM32_UART_USE_UART5) +#error "UART5 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART5) || \ + (HAL_USE_UART && STM32_UART_USE_UART5) +#define STM32_UART5_IS_USED TRUE +#else +#define STM32_UART5_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void uart5_irq_init(void) { +#if STM32_UART5_IS_USED + nvicEnableVector(STM32_UART5_NUMBER, STM32_IRQ_UART5_PRIORITY); +#endif +} + +static inline void uart5_irq_deinit(void) { +#if STM32_UART5_IS_USED + nvicDisableVector(STM32_UART5_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART5_IS_USED || defined(__DOXYGEN__) +/** + * @brief UART5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART5 + sd_lld_serve_interrupt(&SD5); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART5 + uart_lld_serve_interrupt(&UARTD5); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart7.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart7.inc new file mode 100644 index 0000000..2ec791e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart7.inc @@ -0,0 +1,121 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_uart7.inc + * @brief Shared UART7 handler. + * + * @addtogroup STM32_UART7_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART7) +#error "STM32_HAS_UART7 not defined in registry" +#endif + +#if STM32_HAS_UART7 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_UART7_PRIORITY) +#error "STM32_IRQ_UART7_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_UART7_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_UART7_PRIORITY" +#endif + +#endif /* STM32_HAS_UART7 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART7) && \ + (HAL_USE_UART && STM32_UART_USE_UART7) +#error "UART7 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART7) || \ + (HAL_USE_UART && STM32_UART_USE_UART7) +#define STM32_UART7_IS_USED TRUE +#else +#define STM32_UART7_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void uart7_irq_init(void) { +#if STM32_UART7_IS_USED + nvicEnableVector(STM32_UART7_NUMBER, STM32_IRQ_UART7_PRIORITY); +#endif +} + +static inline void uart7_irq_deinit(void) { +#if STM32_UART7_IS_USED + nvicDisableVector(STM32_UART7_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART7_IS_USED || defined(__DOXYGEN__) +/** + * @brief UART7 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART7 + sd_lld_serve_interrupt(&SD7); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART7 + uart_lld_serve_interrupt(&UARTD7); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart8.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart8.inc new file mode 100644 index 0000000..8958431 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart8.inc @@ -0,0 +1,121 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_uart8.inc + * @brief Shared UART8 handler. + * + * @addtogroup STM32_UART8_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART8) +#error "STM32_HAS_UART8 not defined in registry" +#endif + +#if STM32_HAS_UART8 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_UART8_PRIORITY) +#error "STM32_IRQ_UART8_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_UART8_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_UART8_PRIORITY" +#endif + +#endif /* STM32_HAS_UART8 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART8) && \ + (HAL_USE_UART && STM32_UART_USE_UART8) +#error "UART8 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART8) || \ + (HAL_USE_UART && STM32_UART_USE_UART8) +#define STM32_UART8_IS_USED TRUE +#else +#define STM32_UART8_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void uart8_irq_init(void) { +#if STM32_UART8_IS_USED + nvicEnableVector(STM32_UART8_NUMBER, STM32_IRQ_UART8_PRIORITY); +#endif +} + +static inline void uart8_irq_deinit(void) { +#if STM32_UART8_IS_USED + nvicDisableVector(STM32_UART8_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART8_IS_USED || defined(__DOXYGEN__) +/** + * @brief UART8 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART8 + sd_lld_serve_interrupt(&SD8); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART8 + uart_lld_serve_interrupt(&UARTD8); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart1.inc new file mode 100644 index 0000000..19aac10 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart1.inc @@ -0,0 +1,121 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_usart1.inc + * @brief Shared USART1 handler. + * + * @addtogroup STM32_USART1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART1) +#error "STM32_HAS_USART1 not defined in registry" +#endif + +#if STM32_HAS_USART1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART1_PRIORITY) +#error "STM32_IRQ_USART1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART1_PRIORITY" +#endif + +#endif /* STM32_HAS_USART1 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART1) && \ + (HAL_USE_UART && STM32_UART_USE_USART1) +#error "USART1 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART1) || \ + (HAL_USE_UART && STM32_UART_USE_USART1) +#define STM32_USART1_IS_USED TRUE +#else +#define STM32_USART1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart1_irq_init(void) { +#if STM32_USART1_IS_USED + nvicEnableVector(STM32_USART1_NUMBER, STM32_IRQ_USART1_PRIORITY); +#endif +} + +static inline void usart1_irq_deinit(void) { +#if STM32_USART1_IS_USED + nvicDisableVector(STM32_USART1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART1_IS_USED|| defined(__DOXYGEN__) +/** + * @brief USART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART1 + sd_lld_serve_interrupt(&SD1); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART1 + uart_lld_serve_interrupt(&UARTD1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart2.inc new file mode 100644 index 0000000..c4b9000 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart2.inc @@ -0,0 +1,121 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_usart2.inc + * @brief Shared USART2 handler. + * + * @addtogroup STM32_USART2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART2) +#error "STM32_HAS_USART2 not defined in registry" +#endif + +#if STM32_HAS_USART2 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART2_PRIORITY) +#error "STM32_IRQ_USART2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART2_PRIORITY" +#endif + +#endif /* STM32_HAS_USART2 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART2) && \ + (HAL_USE_UART && STM32_UART_USE_USART2) +#error "USART2 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART2) || \ + (HAL_USE_UART && STM32_UART_USE_USART2) +#define STM32_USART2_IS_USED TRUE +#else +#define STM32_USART2_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart2_irq_init(void) { +#if STM32_USART2_IS_USED + nvicEnableVector(STM32_USART2_NUMBER, STM32_IRQ_USART2_PRIORITY); +#endif +} + +static inline void usart2_irq_deinit(void) { +#if STM32_USART2_IS_USED + nvicDisableVector(STM32_USART2_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART2_IS_USED || defined(__DOXYGEN__) +/** + * @brief USART2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART2 + sd_lld_serve_interrupt(&SD2); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART2 + uart_lld_serve_interrupt(&UARTD2); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3.inc new file mode 100644 index 0000000..ff5dbda --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3.inc @@ -0,0 +1,121 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_usart3.inc + * @brief Shared USART3 handler. + * + * @addtogroup STM32_USART3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART3) +#error "STM32_HAS_USART3 not defined in registry" +#endif + +#if STM32_HAS_USART3 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART3_PRIORITY) +#error "STM32_IRQ_USART3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART3_PRIORITY" +#endif + +#endif /* STM32_HAS_USART3 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART3) && \ + (HAL_USE_UART && STM32_UART_USE_USART3) +#error "USART3 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART3) || \ + (HAL_USE_UART && STM32_UART_USE_USART3) +#define STM32_USART3_IS_USED TRUE +#else +#define STM32_USART3_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart3_irq_init(void) { +#if STM32_USART3_IS_USED + nvicEnableVector(STM32_USART3_NUMBER, STM32_IRQ_USART3_PRIORITY); +#endif +} + +static inline void usart3_irq_deinit(void) { +#if STM32_USART3_IS_USED + nvicDisableVector(STM32_USART3_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART3_IS_USED || defined(__DOXYGEN__) +/** + * @brief USART3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART3 + sd_lld_serve_interrupt(&SD3); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART3 + uart_lld_serve_interrupt(&UARTD3); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3_4_lp1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3_4_lp1.inc new file mode 100644 index 0000000..596237f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3_4_lp1.inc @@ -0,0 +1,157 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_usart3_4_lp1.inc + * @brief Shared USART3, USART4, LPUART1 handler. + * + * @addtogroup STM32_USART3_4_LP1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART3) +#error "STM32_HAS_USART3 not defined in registry" +#endif + +#if !defined(STM32_HAS_UART4) +#error "STM32_HAS_UART4 not defined in registry" +#endif + +#if !defined(STM32_HAS_LPUART1) +#error "STM32_HAS_LPUART1 not defined in registry" +#endif + +#if STM32_HAS_USART3 || STM32_HAS_UART4 || STM32_HAS_LPUART1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART3_4_LP1_PRIORITY) +#error "STM32_IRQ_USART3_4_LP1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART3_4_LP1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART3_4_LP1_PRIORITY" +#endif + +#endif /* STM32_HAS_USART3 || STM32_HAS_UART4 || STM32_HAS_LPUART1 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART3) && \ + (HAL_USE_UART && STM32_UART_USE_USART3) +#error "USART3 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) && \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#error "USART4 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART3) || \ + (HAL_USE_UART && STM32_UART_USE_USART3) +#define STM32_USART3_IS_USED TRUE +#else +#define STM32_USART3_IS_USED FALSE +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) || \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#define STM32_USART4_IS_USED TRUE +#else +#define STM32_USART4_IS_USED FALSE +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_LPUART1) +#define STM32_LPUART1_IS_USED TRUE +#else +#define STM32_LPUART1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart3_usart4_lpuart1_irq_init(void) { +#if STM32_USART3_IS_USED || STM32_USART4_IS_USED || STM32_LPUART1_IS_USED + nvicEnableVector(STM32_USART3_4_LP1_NUMBER, STM32_IRQ_USART3_4_LP1_PRIORITY); +#endif +} + +static inline void usart3_usart4_lpuart1_irq_deinit(void) { +#if STM32_USART3_IS_USED || STM32_USART4_IS_USED || STM32_LPUART1_IS_USED + nvicDisableVector(STM32_USART3_4_LP1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART3_IS_USED || STM32_USART4_IS_USED || \ + STM32_LPUART1_IS_USED || defined(__DOXYGEN__) +/** + * @brief USART4, USART5, LPUART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART3_4_LP1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART3 + sd_lld_serve_interrupt(&SD3); +#endif +#if STM32_SERIAL_USE_UART4 + sd_lld_serve_interrupt(&SD4); +#endif +#if STM32_SERIAL_USE_LPUART1 + sd_lld_serve_interrupt(&LPSD1); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART3 + uart_lld_serve_interrupt(&UARTD3); +#endif +#if STM32_UART_USE_UART4 + uart_lld_serve_interrupt(&UARTD4); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart4_5.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart4_5.inc new file mode 100644 index 0000000..7d003a3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart4_5.inc @@ -0,0 +1,144 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_usart4_5.inc + * @brief Shared USART4, USART5 handler. + * + * @addtogroup STM32_USART4_5_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART4) +#error "STM32_HAS_UART4 not defined in registry" +#endif + +#if !defined(STM32_HAS_UART5) +#error "STM32_HAS_UART5 not defined in registry" +#endif + +#if STM32_HAS_UART4 || STM32_HAS_UART5 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART4_5_PRIORITY) +#error "STM32_IRQ_USART4_5_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART4_5_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART4_5_PRIORITY" +#endif + +#endif /* STM32_HAS_UART4 || STM32_HAS_UART5 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) && \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#error "USART4 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART5) && \ + (HAL_USE_UART && STM32_UART_USE_UART5) +#error "USART5 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) || \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#define STM32_USART4_IS_USED TRUE +#else +#define STM32_USART4_IS_USED FALSE +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART5) || \ + (HAL_USE_UART && STM32_UART_USE_UART45) +#define STM32_USART5_IS_USED TRUE +#else +#define STM32_USART5_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart4_usart5_irq_init(void) { +#if STM32_USART4_IS_USED || STM32_USART5_IS_USED + nvicEnableVector(STM32_USART4_5_NUMBER, STM32_IRQ_USART4_5_PRIORITY); +#endif +} + +static inline void usart4_usart5_irq_deinit(void) { +#if STM32_USART4_IS_USED || STM32_USART5_IS_USED + nvicDisableVector(STM32_USART4_5_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART4_IS_USED || STM32_USART5_IS_USED || \ + defined(__DOXYGEN__) +/** + * @brief USART4, USART5, LPUART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART4_5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART4 + sd_lld_serve_interrupt(&SD4); +#endif +#if STM32_SERIAL_USE_UART5 + sd_lld_serve_interrupt(&SD5); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART4 + uart_lld_serve_interrupt(&UARTD4); +#endif +#if STM32_UART_USE_UART5 + uart_lld_serve_interrupt(&UARTD5); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart6.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart6.inc new file mode 100644 index 0000000..ea812a8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart6.inc @@ -0,0 +1,121 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USARTv2/stm32_usart6.inc + * @brief Shared USART6 handler. + * + * @addtogroup STM32_USART6_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART6) +#error "STM32_HAS_USART6 not defined in registry" +#endif + +#if STM32_HAS_USART6 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART6_PRIORITY) +#error "STM32_IRQ_USART6_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART6_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART6_PRIORITY" +#endif + +#endif /* STM32_HAS_USART6 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART6) && \ + (HAL_USE_UART && STM32_UART_USE_USART6) +#error "USART6 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART6) || \ + (HAL_USE_UART && STM32_UART_USE_USART6) +#define STM32_USART6_IS_USED TRUE +#else +#define STM32_USART6_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart6_irq_init(void) { +#if STM32_USART6_IS_USED + nvicEnableVector(STM32_USART6_NUMBER, STM32_IRQ_USART6_PRIORITY); +#endif +} + +static inline void usart6_irq_deinit(void) { +#if STM32_USART6_IS_USED + nvicDisableVector(STM32_USART6_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART6_IS_USED || defined(__DOXYGEN__) +/** + * @brief USART6 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART6 + sd_lld_serve_interrupt(&SD6); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART6 + uart_lld_serve_interrupt(&UARTD6); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/driver.mk new file mode 100644 index 0000000..1a6d862 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_USB TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USBv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c new file mode 100644 index 0000000..20607b7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c @@ -0,0 +1,874 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USBv1/hal_usb_lld.c + * @brief STM32 USB subsystem low level driver source. + * + * @addtogroup USB + * @{ + */ + +#include + +#include "hal.h" + +#if HAL_USE_USB || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define BTABLE_ADDR 0x0000 + +#define EPR_EP_TYPE_IS_ISO(bits) ((bits & EPR_EP_TYPE_MASK) == EPR_EP_TYPE_ISO) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief USB1 driver identifier.*/ +#if STM32_USB_USE_USB1 || defined(__DOXYGEN__) +USBDriver USBD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief EP0 state. + * @note It is an union because IN and OUT endpoints are never used at the + * same time for EP0. + */ +static union { + /** + * @brief IN EP0 state. + */ + USBInEndpointState in; + /** + * @brief OUT EP0 state. + */ + USBOutEndpointState out; +} ep0_state; + +/** + * @brief Buffer for the EP0 setup packets. + */ +static uint8_t ep0setup_buffer[8]; + +/** + * @brief EP0 initialization structure. + */ +static const USBEndpointConfig ep0config = { + USB_EP_MODE_TYPE_CTRL, + _usb_ep0setup, + _usb_ep0in, + _usb_ep0out, + 0x40, + 0x40, + &ep0_state.in, + &ep0_state.out, + 1, + ep0setup_buffer +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Resets the packet memory allocator. + * + * @param[in] usbp pointer to the @p USBDriver object + */ +static void usb_pm_reset(USBDriver *usbp) { + + /* The first 64 bytes are reserved for the descriptors table. The effective + available RAM for endpoint buffers is just 448 bytes.*/ + usbp->pmnext = 64; +} + +/** + * @brief Resets the packet memory allocator. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] size size of the packet buffer to allocate + * @return The packet buffer address. + */ +static uint32_t usb_pm_alloc(USBDriver *usbp, size_t size) { + uint32_t next; + + next = usbp->pmnext; + usbp->pmnext += (size + 1) & ~1; + osalDbgAssert(usbp->pmnext <= STM32_USB_PMA_SIZE, "PMA overflow"); + return next; +} + +/** + * @brief Reads from a dedicated packet buffer. + * + * @param[in] ep endpoint number + * @param[out] buf buffer where to copy the packet data + * @return The size of the receivee packet. + * + * @notapi + */ +static size_t usb_packet_read_to_buffer(usbep_t ep, uint8_t *buf) { + size_t i, n; + stm32_usb_descriptor_t *udp = USB_GET_DESCRIPTOR(ep); + stm32_usb_pma_t *pmap = USB_ADDR2PTR(udp->RXADDR0); +#if STM32_USB_USE_ISOCHRONOUS + uint32_t epr = STM32_USB->EPR[ep]; + + /* Double buffering is always enabled for isochronous endpoints, and + although we overlap the two buffers for simplicity, we still need + to read from the right counter. The DTOG_RX bit indicates the buffer + that is currently in use by the USB peripheral, that is, the buffer + in which the next received packet will be stored, so we need to + read the counter of the OTHER buffer, which is where the last + received packet was stored.*/ + if (EPR_EP_TYPE_IS_ISO(epr) && !(epr & EPR_DTOG_RX)) + n = (size_t)udp->RXCOUNT1 & RXCOUNT_COUNT_MASK; + else + n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK; +#else + n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK; +#endif + + i = n; + +#if STM32_USB_USE_FAST_COPY + while (i >= 16) { + uint32_t w; + + w = *(pmap + 0); + *(buf + 0) = (uint8_t)w; + *(buf + 1) = (uint8_t)(w >> 8); + w = *(pmap + 1); + *(buf + 2) = (uint8_t)w; + *(buf + 3) = (uint8_t)(w >> 8); + w = *(pmap + 2); + *(buf + 4) = (uint8_t)w; + *(buf + 5) = (uint8_t)(w >> 8); + w = *(pmap + 3); + *(buf + 6) = (uint8_t)w; + *(buf + 7) = (uint8_t)(w >> 8); + w = *(pmap + 4); + *(buf + 8) = (uint8_t)w; + *(buf + 9) = (uint8_t)(w >> 8); + w = *(pmap + 5); + *(buf + 10) = (uint8_t)w; + *(buf + 11) = (uint8_t)(w >> 8); + w = *(pmap + 6); + *(buf + 12) = (uint8_t)w; + *(buf + 13) = (uint8_t)(w >> 8); + w = *(pmap + 7); + *(buf + 14) = (uint8_t)w; + *(buf + 15) = (uint8_t)(w >> 8); + + i -= 16; + buf += 16; + pmap += 8; + } +#endif /* STM32_USB_USE_FAST_COPY */ + + while (i >= 2) { + uint32_t w = *pmap++; + *buf++ = (uint8_t)w; + *buf++ = (uint8_t)(w >> 8); + i -= 2; + } + + if (i >= 1) { + *buf = (uint8_t)*pmap; + } + + return n; +} + +/** + * @brief Writes to a dedicated packet buffer. + * + * @param[in] ep endpoint number + * @param[in] buf buffer where to fetch the packet data + * @param[in] n maximum number of bytes to copy. This value must + * not exceed the maximum packet size for this endpoint. + * + * @notapi + */ +static void usb_packet_write_from_buffer(usbep_t ep, + const uint8_t *buf, + size_t n) { + stm32_usb_descriptor_t *udp = USB_GET_DESCRIPTOR(ep); + stm32_usb_pma_t *pmap = USB_ADDR2PTR(udp->TXADDR0); + int i = (int)n; + +#if STM32_USB_USE_ISOCHRONOUS + uint32_t epr = STM32_USB->EPR[ep]; + + /* Double buffering is always enabled for isochronous endpoints, and + although we overlap the two buffers for simplicity, we still need + to write to the right counter. The DTOG_TX bit indicates the buffer + that is currently in use by the USB peripheral, that is, the buffer + from which the next packet will be sent, so we need to write the + counter of that buffer.*/ + if (EPR_EP_TYPE_IS_ISO(epr) && (epr & EPR_DTOG_TX)) + udp->TXCOUNT1 = (stm32_usb_pma_t)n; + else + udp->TXCOUNT0 = (stm32_usb_pma_t)n; +#else + udp->TXCOUNT0 = (stm32_usb_pma_t)n; +#endif + +#if STM32_USB_USE_FAST_COPY + while (i >= 16) { + uint32_t w; + + w = *(buf + 0); + w |= *(buf + 1) << 8; + *(pmap + 0) = (stm32_usb_pma_t)w; + w = *(buf + 2); + w |= *(buf + 3) << 8; + *(pmap + 1) = (stm32_usb_pma_t)w; + w = *(buf + 4); + w |= *(buf + 5) << 8; + *(pmap + 2) = (stm32_usb_pma_t)w; + w = *(buf + 6); + w |= *(buf + 7) << 8; + *(pmap + 3) = (stm32_usb_pma_t)w; + w = *(buf + 8); + w |= *(buf + 9) << 8; + *(pmap + 4) = (stm32_usb_pma_t)w; + w = *(buf + 10); + w |= *(buf + 11) << 8; + *(pmap + 5) = (stm32_usb_pma_t)w; + w = *(buf + 12); + w |= *(buf + 13) << 8; + *(pmap + 6) = (stm32_usb_pma_t)w; + w = *(buf + 14); + w |= *(buf + 15) << 8; + *(pmap + 7) = (stm32_usb_pma_t)w; + + i -= 16; + buf += 16; + pmap += 8; + } +#endif /* STM32_USB_USE_FAST_COPY */ + + while (i > 0) { + uint32_t w; + + w = *buf++; + w |= *buf++ << 8; + *pmap++ = (stm32_usb_pma_t)w; + i -= 2; + } +} + +/** + * @brief Common ISR code, serves the EP-related interrupts. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +static void usb_serve_endpoints(USBDriver *usbp, uint32_t ep) { + size_t n; + uint32_t epr = STM32_USB->EPR[ep]; + const USBEndpointConfig *epcp = usbp->epc[ep]; + + if (epr & EPR_CTR_TX) { + /* IN endpoint, transmission.*/ + USBInEndpointState *isp = epcp->in_state; + + EPR_CLEAR_CTR_TX(ep); + + isp->txcnt += isp->txlast; + n = isp->txsize - isp->txcnt; + if (n > 0) { + /* Transfer not completed, there are more packets to send.*/ + if (n > epcp->in_maxsize) + n = epcp->in_maxsize; + + /* Writes the packet from the defined buffer.*/ + isp->txbuf += isp->txlast; + isp->txlast = n; + usb_packet_write_from_buffer(ep, isp->txbuf, n); + + /* Starting IN operation.*/ + EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID); + } + else { + /* Transfer completed, invokes the callback.*/ + _usb_isr_invoke_in_cb(usbp, ep); + } + } + if (epr & EPR_CTR_RX) { + /* OUT endpoint, receive.*/ + + EPR_CLEAR_CTR_RX(ep); + + if (epr & EPR_SETUP) { + /* Setup packets handling, setup packets are handled using a + specific callback.*/ + _usb_isr_invoke_setup_cb(usbp, ep); + } + else { + USBOutEndpointState *osp = epcp->out_state; + + /* Reads the packet into the defined buffer.*/ + n = usb_packet_read_to_buffer(ep, osp->rxbuf); + osp->rxbuf += n; + + /* Transaction data updated.*/ + osp->rxcnt += n; + osp->rxsize -= n; + osp->rxpkts -= 1; + + /* The transaction is completed if the specified number of packets + has been received or the current packet is a short packet.*/ + if ((n < epcp->out_maxsize) || (osp->rxpkts == 0)) { + /* Transfer complete, invokes the callback.*/ + _usb_isr_invoke_out_cb(usbp, ep); + } + else { + /* Transfer not complete, there are more packets to receive.*/ + EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID); + } + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USB_USE_USB1 || defined(__DOXYGEN__) +#if STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER +#if STM32_USB_USE_ISOCHRONOUS +/** + * @brief USB high priority interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USB1_HP_HANDLER) { + uint32_t istr; + USBDriver *usbp = &USBD1; + + OSAL_IRQ_PROLOGUE(); + + /* Endpoint events handling.*/ + istr = STM32_USB->ISTR; + while (istr & ISTR_CTR) { + usb_serve_endpoints(usbp, istr & ISTR_EP_ID_MASK); + istr = STM32_USB->ISTR; + } + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_USB_USE_ISOCHRONOUS */ +#endif /* STM32_USB1_LP_NUMBER != STM32_USB1_HP_NUMBER */ + +/** + * @brief USB low priority interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USB1_LP_HANDLER) { + uint32_t istr; + USBDriver *usbp = &USBD1; + + OSAL_IRQ_PROLOGUE(); + + istr = STM32_USB->ISTR; + + /* USB bus reset condition handling.*/ + if (istr & ISTR_RESET) { + STM32_USB->ISTR = ~ISTR_RESET; + + _usb_reset(usbp); + } + + /* USB bus SUSPEND condition handling.*/ + if (istr & ISTR_SUSP) { + STM32_USB->CNTR |= CNTR_FSUSP; +#if STM32_USB_LOW_POWER_ON_SUSPEND + STM32_USB->CNTR |= CNTR_LP_MODE; +#endif + STM32_USB->ISTR = ~ISTR_SUSP; + + _usb_suspend(usbp); + } + + /* USB bus WAKEUP condition handling.*/ + if (istr & ISTR_WKUP) { + uint32_t fnr = STM32_USB->FNR; + if (!(fnr & FNR_RXDP)) { + STM32_USB->CNTR &= ~CNTR_FSUSP; + + _usb_wakeup(usbp); + } +#if STM32_USB_LOW_POWER_ON_SUSPEND + else { + /* Just noise, going back in SUSPEND mode, reference manual 22.4.5, + table 169.*/ + STM32_USB->CNTR |= CNTR_LP_MODE; + } +#endif + STM32_USB->ISTR = ~ISTR_WKUP; + } + + /* SOF handling.*/ + if (istr & ISTR_SOF) { + _usb_isr_invoke_sof_cb(usbp); + STM32_USB->ISTR = ~ISTR_SOF; + } + + /* Endpoint events handling.*/ + while (istr & ISTR_CTR) { + usb_serve_endpoints(usbp, istr & ISTR_EP_ID_MASK); + istr = STM32_USB->ISTR; + } + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_USB_USE_USB1 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level USB driver initialization. + * + * @notapi + */ +void usb_lld_init(void) { + + /* Driver initialization.*/ + usbObjectInit(&USBD1); +} + +/** + * @brief Configures and activates the USB peripheral. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_start(USBDriver *usbp) { + + if (usbp->state == USB_STOP) { + /* Clock activation.*/ +#if STM32_USB_USE_USB1 + if (&USBD1 == usbp) { + /* USB clock enabled.*/ + rccEnableUSB(true); + /* Powers up the transceiver while holding the USB in reset state.*/ + STM32_USB->CNTR = CNTR_FRES; + /* Enabling the USB IRQ vectors, this also gives enough time to allow + the transceiver power up (1uS).*/ +#if STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER + nvicEnableVector(STM32_USB1_HP_NUMBER, STM32_USB_USB1_HP_IRQ_PRIORITY); +#endif + nvicEnableVector(STM32_USB1_LP_NUMBER, STM32_USB_USB1_LP_IRQ_PRIORITY); + /* Releases the USB reset.*/ + STM32_USB->CNTR = 0; + } +#endif + /* Reset procedure enforced on driver start.*/ + usb_lld_reset(usbp); + } +} + +/** + * @brief Deactivates the USB peripheral. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_stop(USBDriver *usbp) { + + /* If in ready state then disables the USB clock.*/ + if (usbp->state != USB_STOP) { +#if STM32_USB_USE_USB1 + if (&USBD1 == usbp) { +#if STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER + nvicDisableVector(STM32_USB1_HP_NUMBER); +#endif + nvicDisableVector(STM32_USB1_LP_NUMBER); + STM32_USB->CNTR = CNTR_PDWN | CNTR_FRES; + rccDisableUSB(); + } +#endif + } +} + +/** + * @brief USB low level reset routine. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_reset(USBDriver *usbp) { + uint32_t cntr; + + /* Post reset initialization.*/ + STM32_USB->BTABLE = BTABLE_ADDR; + STM32_USB->ISTR = 0; + STM32_USB->DADDR = DADDR_EF; + cntr = /*CNTR_ESOFM | */ CNTR_RESETM | CNTR_SUSPM | + CNTR_WKUPM | /*CNTR_ERRM | CNTR_PMAOVRM |*/ CNTR_CTRM; + /* The SOF interrupt is only enabled if a callback is defined for + this service because it is an high rate source.*/ + if (usbp->config->sof_cb != NULL) + cntr |= CNTR_SOFM; + STM32_USB->CNTR = cntr; + + /* Resets the packet memory allocator.*/ + usb_pm_reset(usbp); + + /* EP0 initialization.*/ + usbp->epc[0] = &ep0config; + usb_lld_init_endpoint(usbp, 0); +} + +/** + * @brief Sets the USB address. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_set_address(USBDriver *usbp) { + + STM32_USB->DADDR = (uint32_t)(usbp->address) | DADDR_EF; +} + +/** + * @brief Enables an endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { + uint16_t epr; + stm32_usb_descriptor_t *dp; + const USBEndpointConfig *epcp = usbp->epc[ep]; + + /* Setting the endpoint type. Note that isochronous endpoints cannot be + bidirectional because it uses double buffering and both transmit and + receive descriptor fields are used for either direction.*/ + switch (epcp->ep_mode & USB_EP_MODE_TYPE) { + case USB_EP_MODE_TYPE_ISOC: +#if STM32_USB_USE_ISOCHRONOUS + osalDbgAssert((epcp->in_state == NULL) || (epcp->out_state == NULL), + "isochronous EP cannot be IN and OUT"); + epr = EPR_EP_TYPE_ISO; + break; +#else + osalDbgAssert(false, "isochronous support disabled"); +#endif + /* Falls through.*/ + case USB_EP_MODE_TYPE_BULK: + epr = EPR_EP_TYPE_BULK; + break; + case USB_EP_MODE_TYPE_INTR: + epr = EPR_EP_TYPE_INTERRUPT; + break; + default: + epr = EPR_EP_TYPE_CONTROL; + } + + dp = USB_GET_DESCRIPTOR(ep); + + /* IN endpoint handling.*/ + if (epcp->in_state != NULL) { + dp->TXCOUNT0 = 0; + dp->TXADDR0 = usb_pm_alloc(usbp, epcp->in_maxsize); + +#if STM32_USB_USE_ISOCHRONOUS + if (epr == EPR_EP_TYPE_ISO) { + epr |= EPR_STAT_TX_VALID; + dp->TXCOUNT1 = dp->TXCOUNT0; + dp->TXADDR1 = dp->TXADDR0; /* Both buffers overlapped.*/ + } + else { + epr |= EPR_STAT_TX_NAK; + } +#else + epr |= EPR_STAT_TX_NAK; +#endif + } + + /* OUT endpoint handling.*/ + if (epcp->out_state != NULL) { + uint16_t nblocks; + + /* Endpoint size and address initialization.*/ + if (epcp->out_maxsize > 62) + nblocks = (((((epcp->out_maxsize - 1) | 0x1f) + 1) / 32) << 10) | + 0x8000; + else + nblocks = ((((epcp->out_maxsize - 1) | 1) + 1) / 2) << 10; + dp->RXCOUNT0 = nblocks; + dp->RXADDR0 = usb_pm_alloc(usbp, epcp->out_maxsize); + +#if STM32_USB_USE_ISOCHRONOUS + if (epr == EPR_EP_TYPE_ISO) { + epr |= EPR_STAT_RX_VALID; + dp->RXCOUNT1 = dp->RXCOUNT0; + dp->RXADDR1 = dp->RXADDR0; /* Both buffers overlapped.*/ + } + else { + epr |= EPR_STAT_RX_NAK; + } +#else + epr |= EPR_STAT_RX_NAK; +#endif + } + + /* Resetting the data toggling bits for this endpoint.*/ + if (STM32_USB->EPR[ep] & EPR_DTOG_RX) { + epr |= EPR_DTOG_RX; + } + + if (STM32_USB->EPR[ep] & EPR_DTOG_TX) { + epr |= EPR_DTOG_TX; + } + + /* EPxR register setup.*/ + EPR_SET(ep, epr | ep); + EPR_TOGGLE(ep, epr); +} + +/** + * @brief Disables all the active endpoints except the endpoint zero. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_disable_endpoints(USBDriver *usbp) { + unsigned i; + + /* Resets the packet memory allocator.*/ + usb_pm_reset(usbp); + + /* Disabling all endpoints.*/ + for (i = 1; i <= USB_ENDOPOINTS_NUMBER; i++) { + EPR_TOGGLE(i, 0); + EPR_SET(i, 0); + } +} + +/** + * @brief Returns the status of an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return The endpoint status. + * @retval EP_STATUS_DISABLED The endpoint is not active. + * @retval EP_STATUS_STALLED The endpoint is stalled. + * @retval EP_STATUS_ACTIVE The endpoint is active. + * + * @notapi + */ +usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) { + + (void)usbp; + switch (STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) { + case EPR_STAT_RX_DIS: + return EP_STATUS_DISABLED; + case EPR_STAT_RX_STALL: + return EP_STATUS_STALLED; + default: + return EP_STATUS_ACTIVE; + } +} + +/** + * @brief Returns the status of an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return The endpoint status. + * @retval EP_STATUS_DISABLED The endpoint is not active. + * @retval EP_STATUS_STALLED The endpoint is stalled. + * @retval EP_STATUS_ACTIVE The endpoint is active. + * + * @notapi + */ +usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) { + + (void)usbp; + switch (STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) { + case EPR_STAT_TX_DIS: + return EP_STATUS_DISABLED; + case EPR_STAT_TX_STALL: + return EP_STATUS_STALLED; + default: + return EP_STATUS_ACTIVE; + } +} + +/** + * @brief Reads a setup packet from the dedicated packet buffer. + * @details This function must be invoked in the context of the @p setup_cb + * callback in order to read the received setup packet. + * @pre In order to use this function the endpoint must have been + * initialized as a control endpoint. + * @post The endpoint is ready to accept another packet. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[out] buf buffer where to copy the packet data + * + * @notapi + */ +void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) { + stm32_usb_pma_t *pmap; + stm32_usb_descriptor_t *udp; + uint32_t n; + + (void)usbp; + udp = USB_GET_DESCRIPTOR(ep); + pmap = USB_ADDR2PTR(udp->RXADDR0); + for (n = 0; n < 4; n++) { + *(uint16_t *)buf = (uint16_t)*pmap++; + buf += 2; + } +} + +/** + * @brief Starts a receive operation on an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_start_out(USBDriver *usbp, usbep_t ep) { + USBOutEndpointState *osp = usbp->epc[ep]->out_state; + + /* Transfer initialization.*/ + if (osp->rxsize == 0) /* Special case for zero sized packets.*/ + osp->rxpkts = 1; + else + osp->rxpkts = (uint16_t)((osp->rxsize + usbp->epc[ep]->out_maxsize - 1) / + usbp->epc[ep]->out_maxsize); + + EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID); +} + +/** + * @brief Starts a transmit operation on an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_start_in(USBDriver *usbp, usbep_t ep) { + size_t n; + USBInEndpointState *isp = usbp->epc[ep]->in_state; + + /* Transfer initialization.*/ + n = isp->txsize; + if (n > (size_t)usbp->epc[ep]->in_maxsize) + n = (size_t)usbp->epc[ep]->in_maxsize; + + isp->txlast = n; + usb_packet_write_from_buffer(ep, isp->txbuf, n); + + EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID); +} + +/** + * @brief Brings an OUT endpoint in the stalled state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) { + + (void)usbp; + + EPR_SET_STAT_RX(ep, EPR_STAT_RX_STALL); +} + +/** + * @brief Brings an IN endpoint in the stalled state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) { + + (void)usbp; + + EPR_SET_STAT_TX(ep, EPR_STAT_TX_STALL); +} + +/** + * @brief Brings an OUT endpoint in the active state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) { + + (void)usbp; + + /* Makes sure to not put to NAK an endpoint that is already + transferring.*/ + if ((STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) != EPR_STAT_RX_VALID) + EPR_SET_STAT_TX(ep, EPR_STAT_RX_NAK); +} + +/** + * @brief Brings an IN endpoint in the active state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) { + + (void)usbp; + + /* Makes sure to not put to NAK an endpoint that is already + transferring.*/ + if ((STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) != EPR_STAT_TX_VALID) + EPR_SET_STAT_TX(ep, EPR_STAT_TX_NAK); +} + +#endif /* HAL_USE_USB */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.h new file mode 100644 index 0000000..1270172 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.h @@ -0,0 +1,521 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USBv1/hal_usb_lld.h + * @brief STM32 USB subsystem low level driver header. + * + * @addtogroup USB + * @{ + */ + +#ifndef HAL_USB_LLD_H +#define HAL_USB_LLD_H + +#if HAL_USE_USB || defined(__DOXYGEN__) + +#include "stm32_usb.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Maximum endpoint address. + */ +#define USB_MAX_ENDPOINTS USB_ENDOPOINTS_NUMBER + +/** + * @brief Status stage handling method. + */ +#define USB_EP0_STATUS_STAGE USB_EP0_STATUS_STAGE_SW + +/** + * @brief This device requires the address change after the status packet. + */ +#define USB_SET_ADDRESS_MODE USB_LATE_SET_ADDRESS + +/** + * @brief Method for set address acknowledge. + */ +#define USB_SET_ADDRESS_ACK_HANDLING USB_SET_ADDRESS_ACK_SW + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief USB1 driver enable switch. + * @details If set to @p TRUE the support for USB1 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_USB_USE_USB1) || defined(__DOXYGEN__) +#define STM32_USB_USE_USB1 FALSE +#endif + +/** + * @brief Enables the USB device low power mode on suspend. + */ +#if !defined(STM32_USB_LOW_POWER_ON_SUSPEND) || defined(__DOXYGEN__) +#define STM32_USB_LOW_POWER_ON_SUSPEND FALSE +#endif + +/** + * @brief USB1 interrupt priority level setting. + */ +#if (!defined(STM32_USB_USB1_HP_IRQ_PRIORITY) && \ + (STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER)) || defined(__DOXYGEN__) +#define STM32_USB_USB1_HP_IRQ_PRIORITY 13 +#endif + +/** + * @brief USB1 interrupt priority level setting. + */ +#if !defined(STM32_USB_USB1_LP_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_USB_USB1_LP_IRQ_PRIORITY 14 +#endif + +/** + * @brief Enables isochronous support. + * @note Isochronous support requires special handling and this makes the + * code size increase significantly. + */ +#if !defined(STM32_USB_USE_ISOCHRONOUS) || defined(__DOXYGEN__) +#define STM32_USB_USE_ISOCHRONOUS FALSE +#endif + +/** + * @brief Use faster copy for packets. + * @note Makes the driver larger. + */ +#if !defined(STM32_USB_USE_FAST_COPY) || defined(__DOXYGEN__) +#define STM32_USB_USE_FAST_COPY FALSE +#endif + +/** + * @brief Host wake-up procedure duration. + */ +#if !defined(STM32_USB_HOST_WAKEUP_DURATION) || defined(__DOXYGEN__) +#define STM32_USB_HOST_WAKEUP_DURATION 2 +#endif + +/** + * @brief Allowed deviation for the 48MHz clock. + */ +#if !defined(STM32_USB_48MHZ_DELTA) || defined(__DOXYGEN__) +#define STM32_USB_48MHZ_DELTA 0 +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_USB_USE_USB1 && !STM32_HAS_USB +#error "USB not present in the selected device" +#endif + +#if !STM32_USB_USE_USB1 +#error "USB driver activated but no USB peripheral assigned" +#endif + +#if STM32_USB_USE_USB1 && \ + (STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER) && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_USB_USB1_HP_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USB HP" +#endif + +#if STM32_USB_USE_USB1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_USB_USB1_LP_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to USB LP" +#endif + +#if !defined(STM32_USB1_HP_HANDLER) +#error "STM32_USB1_HP_HANDLER not defined" +#endif + +#if !defined(STM32_USB1_HP_NUMBER) +#error "STM32_USB1_HP_NUMBER not defined" +#endif + +#if !defined(STM32_USB1_LP_HANDLER) +#error "STM32_USB1_LP_HANDLER not defined" +#endif + +#if !defined(STM32_USB1_LP_NUMBER) +#error "STM32_USB1_LP_NUMBER not defined" +#endif + +#if (STM32_USB_HOST_WAKEUP_DURATION < 2) || (STM32_USB_HOST_WAKEUP_DURATION > 15) +#error "invalid STM32_USB_HOST_WAKEUP_DURATION setting, it must be between 2 and 15" +#endif + +#if (STM32_USB_48MHZ_DELTA < 0) || (STM32_USB_48MHZ_DELTA > 250000) +#error "invalid STM32_USB_48MHZ_DELTA setting, it must not exceed 250000" +#endif + +#if (STM32_USBCLK < (48000000 - STM32_USB_48MHZ_DELTA)) || \ + (STM32_USBCLK > (48000000 + STM32_USB_48MHZ_DELTA)) +#error "the USB driver requires a 48MHz clock" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of an IN endpoint state structure. + */ +typedef struct { + /** + * @brief Requested transmit transfer size. + */ + size_t txsize; + /** + * @brief Transmitted bytes so far. + */ + size_t txcnt; + /** + * @brief Pointer to the transmission linear buffer. + */ + const uint8_t *txbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif + /* End of the mandatory fields.*/ + /** + * @brief Size of the last transmitted packet. + */ + size_t txlast; +} USBInEndpointState; + +/** + * @brief Type of an OUT endpoint state structure. + */ +typedef struct { + /** + * @brief Requested receive transfer size. + */ + size_t rxsize; + /** + * @brief Received bytes so far. + */ + size_t rxcnt; + /** + * @brief Pointer to the receive linear buffer. + */ + uint8_t *rxbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif + /* End of the mandatory fields.*/ + /** + * @brief Number of packets to receive. + */ + uint16_t rxpkts; +} USBOutEndpointState; + +/** + * @brief Type of an USB endpoint configuration structure. + * @note Platform specific restrictions may apply to endpoints. + */ +typedef struct { + /** + * @brief Type and mode of the endpoint. + */ + uint32_t ep_mode; + /** + * @brief Setup packet notification callback. + * @details This callback is invoked when a setup packet has been + * received. + * @post The application must immediately call @p usbReadPacket() in + * order to access the received packet. + * @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL + * endpoints, it should be set to @p NULL for other endpoint + * types. + */ + usbepcallback_t setup_cb; + /** + * @brief IN endpoint notification callback. + * @details This field must be set to @p NULL if callback is not required. + */ + usbepcallback_t in_cb; + /** + * @brief OUT endpoint notification callback. + * @details This field must be set to @p NULL if callback is not required. + */ + usbepcallback_t out_cb; + /** + * @brief IN endpoint maximum packet size. + * @details This field must be set to zero if the IN endpoint is not used. + */ + uint16_t in_maxsize; + /** + * @brief OUT endpoint maximum packet size. + * @details This field must be set to zero if the OUT endpoint is not used. + */ + uint16_t out_maxsize; + /** + * @brief @p USBEndpointState associated to the IN endpoint. + * @details This field must be set to @p NULL if the IN endpoint is not + * used. + */ + USBInEndpointState *in_state; + /** + * @brief @p USBEndpointState associated to the OUT endpoint. + * @details This field must be set to @p NULL if the OUT endpoint is not + * used. + */ + USBOutEndpointState *out_state; + /* End of the mandatory fields.*/ + /** + * @brief Reserved field, not currently used. + * @note Initialize this field to 1 in order to be forward compatible. + */ + uint16_t ep_buffers; + /** + * @brief Pointer to a buffer for setup packets. + * @details Setup packets require a dedicated 8-bytes buffer, set this + * field to @p NULL for non-control endpoints. + */ + uint8_t *setup_buf; +} USBEndpointConfig; + +/** + * @brief Type of an USB driver configuration structure. + */ +typedef struct { + /** + * @brief USB events callback. + * @details This callback is invoked when an USB driver event is registered. + */ + usbeventcb_t event_cb; + /** + * @brief Device GET_DESCRIPTOR request callback. + * @note This callback is mandatory and cannot be set to @p NULL. + */ + usbgetdescriptor_t get_descriptor_cb; + /** + * @brief Requests hook callback. + * @details This hook allows to be notified of standard requests or to + * handle non standard requests. + */ + usbreqhandler_t requests_hook_cb; + /** + * @brief Start Of Frame callback. + */ + usbcallback_t sof_cb; + /* End of the mandatory fields.*/ +} USBConfig; + +/** + * @brief Structure representing an USB driver. + */ +struct USBDriver { + /** + * @brief Driver state. + */ + usbstate_t state; + /** + * @brief Current configuration data. + */ + const USBConfig *config; + /** + * @brief Bit map of the transmitting IN endpoints. + */ + uint16_t transmitting; + /** + * @brief Bit map of the receiving OUT endpoints. + */ + uint16_t receiving; + /** + * @brief Active endpoints configurations. + */ + const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1]; + /** + * @brief Fields available to user, it can be used to associate an + * application-defined handler to an IN endpoint. + * @note The base index is one, the endpoint zero does not have a + * reserved element in this array. + */ + void *in_params[USB_MAX_ENDPOINTS]; + /** + * @brief Fields available to user, it can be used to associate an + * application-defined handler to an OUT endpoint. + * @note The base index is one, the endpoint zero does not have a + * reserved element in this array. + */ + void *out_params[USB_MAX_ENDPOINTS]; + /** + * @brief Endpoint 0 state. + */ + usbep0state_t ep0state; + /** + * @brief Next position in the buffer to be transferred through endpoint 0. + */ + uint8_t *ep0next; + /** + * @brief Number of bytes yet to be transferred through endpoint 0. + */ + size_t ep0n; + /** + * @brief Endpoint 0 end transaction callback. + */ + usbcallback_t ep0endcb; + /** + * @brief Setup packet buffer. + */ + uint8_t setup[8]; + /** + * @brief Current USB device status. + */ + uint16_t status; + /** + * @brief Assigned USB address. + */ + uint8_t address; + /** + * @brief Current USB device configuration. + */ + uint8_t configuration; + /** + * @brief State of the driver when a suspend happened. + */ + usbstate_t saved_state; +#if defined(USB_DRIVER_EXT_FIELDS) + USB_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the next address in the packet memory. + */ + uint32_t pmnext; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Returns the current frame number. + * + * @param[in] usbp pointer to the @p USBDriver object + * @return The current frame number. + * + * @notapi + */ +#define usb_lld_get_frame_number(usbp) (STM32_USB->FNR & FNR_FN_MASK) + +/** + * @brief Returns the exact size of a receive transaction. + * @details The received size can be different from the size specified in + * @p usbStartReceiveI() because the last packet could have a size + * different from the expected one. + * @pre The OUT endpoint must have been configured in transaction mode + * in order to use this function. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return Received data size. + * + * @notapi + */ +#define usb_lld_get_transaction_size(usbp, ep) \ + ((usbp)->epc[ep]->out_state->rxcnt) + +#if STM32_USB_HAS_BCDR || defined(__DOXYGEN__) +/** + * @brief Connects the USB device. + * + * @notapi + */ +#if !defined(usb_lld_connect_bus) +#define usb_lld_connect_bus(usbp) (STM32_USB->BCDR |= USB_BCDR_DPPU) +#endif + +/** + * @brief Disconnect the USB device. + * + * @notapi + */ +#if !defined(usb_lld_disconnect_bus) +#define usb_lld_disconnect_bus(usbp) (STM32_USB->BCDR &= ~USB_BCDR_DPPU) +#endif +#endif /* STM32_USB_HAS_BCDR */ + +#if defined(STM32L1XX) +#if !defined(usb_lld_connect_bus) +#define usb_lld_connect_bus(usbp) (SYSCFG->PMC |= SYSCFG_PMC_USB_PU) +#endif + +#if !defined(usb_lld_disconnect_bus) +#define usb_lld_disconnect_bus(usbp) (SYSCFG->PMC &= ~SYSCFG_PMC_USB_PU) +#endif +#endif /* STM32L1XX */ + +/** + * @brief Start of host wake-up procedure. + * + * @notapi + */ +#define usb_lld_wakeup_host(usbp) \ + do { \ + STM32_USB->CNTR |= USB_CNTR_RESUME; \ + osalThreadSleepMilliseconds(STM32_USB_HOST_WAKEUP_DURATION); \ + STM32_USB->CNTR &= ~USB_CNTR_RESUME; \ + } while (false) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_USB_USE_USB1 && !defined(__DOXYGEN__) +extern USBDriver USBD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void usb_lld_init(void); + void usb_lld_start(USBDriver *usbp); + void usb_lld_stop(USBDriver *usbp); + void usb_lld_reset(USBDriver *usbp); + void usb_lld_set_address(USBDriver *usbp); + void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep); + void usb_lld_disable_endpoints(USBDriver *usbp); + usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep); + usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep); + void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf); + void usb_lld_start_out(USBDriver *usbp, usbep_t ep); + void usb_lld_start_in(USBDriver *usbp, usbep_t ep); + void usb_lld_stall_out(USBDriver *usbp, usbep_t ep); + void usb_lld_stall_in(USBDriver *usbp, usbep_t ep); + void usb_lld_clear_out(USBDriver *usbp, usbep_t ep); + void usb_lld_clear_in(USBDriver *usbp, usbep_t ep); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_USB */ + +#endif /* HAL_USB_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/stm32_usb.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/stm32_usb.h new file mode 100644 index 0000000..9a8595e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/stm32_usb.h @@ -0,0 +1,266 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file USBv1/stm32_usb.h + * @brief STM32 USB registers layout header. + * @note This file requires definitions from the ST STM32 header files + * stm32f10x.h or stm32l1xx.h. + * + * @addtogroup USB + * @{ + */ + +#ifndef STM32_USB_H +#define STM32_USB_H + +/** + * @brief Number of the available endpoints. + * @details This value does not include the endpoint 0 which is always present. + */ +#define USB_ENDOPOINTS_NUMBER 7 + +/** + * @brief Width of USB packet memory accesses. + */ +#if STM32_USB_ACCESS_SCHEME_2x16 +typedef uint16_t stm32_usb_pma_t; +#else +typedef uint32_t stm32_usb_pma_t; +#endif + +/** + * @brief USB registers block. + */ +typedef struct { + /** + * @brief Endpoint registers. + */ + volatile uint32_t EPR[USB_ENDOPOINTS_NUMBER + 1]; + /* + * @brief Reserved space. + */ + volatile uint32_t _r20[8]; + /* + * @brief Control Register. + */ + volatile uint32_t CNTR; + /* + * @brief Interrupt Status Register. + */ + volatile uint32_t ISTR; + /* + * @brief Frame Number Register. + */ + volatile uint32_t FNR; + /* + * @brief Device Address Register. + */ + volatile uint32_t DADDR; + /* + * @brief Buffer Table Address. + */ + volatile uint32_t BTABLE; + /* + * @brief LPM Control and Status Register. + */ + volatile uint32_t LPMCSR; +#if STM32_USB_HAS_BCDR + /* + * @brief Battery Charging Detector + */ + volatile uint32_t BCDR; +#endif +} stm32_usb_t; + +/** + * @brief USB descriptor registers block. + */ +typedef struct { + /** + * @brief TX buffer offset register. + */ + volatile stm32_usb_pma_t TXADDR0; + /** + * @brief TX counter register 0. + */ + volatile stm32_usb_pma_t TXCOUNT0; + /** + * @brief RX buffer offset register. + */ + volatile stm32_usb_pma_t RXADDR0; + /** + * @brief RX counter register 0. + */ + volatile stm32_usb_pma_t RXCOUNT0; +} stm32_usb_descriptor_t; + +/** + * @name Register aliases + * @{ + */ +#define RXCOUNT1 TXCOUNT0 +#define TXCOUNT1 RXCOUNT0 +#define RXADDR1 TXADDR0 +#define TXADDR1 RXADDR0 +/** @} */ + +/** + * @brief USB registers block numeric address. + */ +#if defined(USB_BASE) || defined(__DOXYGEN__) +#define STM32_USB_BASE USB_BASE +#else +#define STM32_USB_BASE (APB1PERIPH_BASE + 0x5C00) +#endif + +/** + * @brief USB RAM numeric address. + */ +#if defined(USB_PMAADDR) || defined(__DOXYGEN__) +#define STM32_USBRAM_BASE USB_PMAADDR +#else +#define STM32_USBRAM_BASE (APB1PERIPH_BASE + 0x6000) +#endif + +/** + * @brief Pointer to the USB registers block. + */ +#define STM32_USB ((stm32_usb_t *)STM32_USB_BASE) + +/** + * @brief Pointer to the USB RAM. + */ +#define STM32_USBRAM ((stm32_usb_pma_t *)STM32_USBRAM_BASE) + +/** + * @brief Mask of all the toggling bits in the EPR register. + */ +#define EPR_TOGGLE_MASK (EPR_STAT_TX_MASK | EPR_DTOG_TX | \ + EPR_STAT_RX_MASK | EPR_DTOG_RX | \ + EPR_SETUP) + +#define EPR_EA_MASK 0x000F +#define EPR_STAT_TX_MASK 0x0030 +#define EPR_STAT_TX_DIS 0x0000 +#define EPR_STAT_TX_STALL 0x0010 +#define EPR_STAT_TX_NAK 0x0020 +#define EPR_STAT_TX_VALID 0x0030 +#define EPR_DTOG_TX 0x0040 +#define EPR_SWBUF_RX EPR_DTOG_TX +#define EPR_CTR_TX 0x0080 +#define EPR_EP_KIND 0x0100 +#define EPR_EP_DBL_BUF EPR_EP_KIND +#define EPR_EP_STATUS_OUT EPR_EP_KIND +#define EPR_EP_TYPE_MASK 0x0600 +#define EPR_EP_TYPE_BULK 0x0000 +#define EPR_EP_TYPE_CONTROL 0x0200 +#define EPR_EP_TYPE_ISO 0x0400 +#define EPR_EP_TYPE_INTERRUPT 0x0600 +#define EPR_SETUP 0x0800 +#define EPR_STAT_RX_MASK 0x3000 +#define EPR_STAT_RX_DIS 0x0000 +#define EPR_STAT_RX_STALL 0x1000 +#define EPR_STAT_RX_NAK 0x2000 +#define EPR_STAT_RX_VALID 0x3000 +#define EPR_DTOG_RX 0x4000 +#define EPR_SWBUF_TX EPR_DTOG_RX +#define EPR_CTR_RX 0x8000 + +#define CNTR_FRES 0x0001 +#define CNTR_PDWN 0x0002 +#define CNTR_LP_MODE 0x0004 +#define CNTR_FSUSP 0x0008 +#define CNTR_RESUME 0x0010 +#define CNTR_ESOFM 0x0100 +#define CNTR_SOFM 0x0200 +#define CNTR_RESETM 0x0400 +#define CNTR_SUSPM 0x0800 +#define CNTR_WKUPM 0x1000 +#define CNTR_ERRM 0x2000 +#define CNTR_PMAOVRM 0x4000 +#define CNTR_CTRM 0x8000 + +#define ISTR_EP_ID_MASK 0x000F +#define ISTR_DIR 0x0010 +#define ISTR_ESOF 0x0100 +#define ISTR_SOF 0x0200 +#define ISTR_RESET 0x0400 +#define ISTR_SUSP 0x0800 +#define ISTR_WKUP 0x1000 +#define ISTR_ERR 0x2000 +#define ISTR_PMAOVR 0x4000 +#define ISTR_CTR 0x8000 + +#define FNR_FN_MASK 0x07FF +#define FNR_LSOF 0x1800 +#define FNR_LCK 0x2000 +#define FNR_RXDM 0x4000 +#define FNR_RXDP 0x8000 + +#define DADDR_ADD_MASK 0x007F +#define DADDR_EF 0x0080 + +#define RXCOUNT_COUNT_MASK 0x03FF +#define TXCOUNT_COUNT_MASK 0x03FF + +#define EPR_CTR_MASK (EPR_CTR_TX | EPR_CTR_RX) + +#define EPR_SET(ep, epr) \ + STM32_USB->EPR[ep] = ((epr) & ~EPR_TOGGLE_MASK) | EPR_CTR_MASK + +#define EPR_TOGGLE(ep, epr) \ + STM32_USB->EPR[ep] = (STM32_USB->EPR[ep] ^ ((epr) & EPR_TOGGLE_MASK)) \ + | EPR_CTR_MASK + +#define EPR_SET_STAT_RX(ep, epr) \ + STM32_USB->EPR[ep] = ((STM32_USB->EPR[ep] & \ + ~(EPR_TOGGLE_MASK & ~EPR_STAT_RX_MASK)) ^ \ + (epr)) | EPR_CTR_MASK + +#define EPR_SET_STAT_TX(ep, epr) \ + STM32_USB->EPR[ep] = ((STM32_USB->EPR[ep] & \ + ~(EPR_TOGGLE_MASK & ~EPR_STAT_TX_MASK)) ^ \ + (epr)) | EPR_CTR_MASK + +#define EPR_CLEAR_CTR_RX(ep) \ + STM32_USB->EPR[ep] = (STM32_USB->EPR[ep] & ~EPR_CTR_RX & ~EPR_TOGGLE_MASK)\ + | EPR_CTR_TX + +#define EPR_CLEAR_CTR_TX(ep) \ + STM32_USB->EPR[ep] = (STM32_USB->EPR[ep] & ~EPR_CTR_TX & ~EPR_TOGGLE_MASK)\ + | EPR_CTR_RX + +/** + * @brief Returns an endpoint descriptor pointer. + */ +#define USB_GET_DESCRIPTOR(ep) \ + ((stm32_usb_descriptor_t *)((uint32_t)STM32_USBRAM_BASE + \ + (uint32_t)STM32_USB->BTABLE + \ + (uint32_t)(ep) * \ + sizeof(stm32_usb_descriptor_t))) + +/** + * @brief Converts from a PMA address to a physical address. + */ +#define USB_ADDR2PTR(addr) \ + ((stm32_usb_pma_t *)((addr) * \ + (sizeof(stm32_usb_pma_t) / 2) + \ + STM32_USBRAM_BASE)) + +#endif /* STM32_USB_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/driver.mk new file mode 100644 index 0000000..a4d8bdd --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_WDG TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/xWDGv1 diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c new file mode 100644 index 0000000..42a620e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c @@ -0,0 +1,144 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file xWDGv1/hal_wdg_lld.c + * @brief WDG Driver subsystem low level driver source. + * + * @addtogroup WDG + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define KR_KEY_RELOAD 0xAAAAU +#define KR_KEY_ENABLE 0xCCCCU +#define KR_KEY_WRITE 0x5555U +#define KR_KEY_PROTECT 0x0000U + +#if !defined(IWDG) && defined(IWDG1) +#define IWDG IWDG1 +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if STM32_WDG_USE_IWDG || defined(__DOXYGEN__) +WDGDriver WDGD1; +#endif + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level WDG driver initialization. + * + * @notapi + */ +void wdg_lld_init(void) { + +#if STM32_WDG_USE_IWDG + WDGD1.state = WDG_STOP; + WDGD1.wdg = IWDG; +#endif +} + +/** + * @brief Configures and activates the WDG peripheral. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @notapi + */ +void wdg_lld_start(WDGDriver *wdgp) { + +#if STM32_IWDG_IS_WINDOWED + /* Enable IWDG and unlock for write.*/ + wdgp->wdg->KR = KR_KEY_ENABLE; + wdgp->wdg->KR = KR_KEY_WRITE; + + /* Write configuration.*/ + wdgp->wdg->PR = wdgp->config->pr; + wdgp->wdg->RLR = wdgp->config->rlr; + while (wdgp->wdg->SR != 0) + ; + + /* This also triggers a refresh.*/ + wdgp->wdg->WINR = wdgp->config->winr; +#else + /* Unlock IWDG.*/ + wdgp->wdg->KR = KR_KEY_WRITE; + + /* Write configuration.*/ + while (wdgp->wdg->SR != 0) + ; + wdgp->wdg->PR = wdgp->config->pr; + wdgp->wdg->RLR = wdgp->config->rlr; + + /* Start operations.*/ + wdgp->wdg->KR = KR_KEY_RELOAD; + wdgp->wdg->KR = KR_KEY_ENABLE; +#endif +} + +/** + * @brief Deactivates the WDG peripheral. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @notapi + */ +void wdg_lld_stop(WDGDriver *wdgp) { + + osalDbgAssert(wdgp->state == WDG_STOP, + "IWDG cannot be stopped once activated"); +} + +/** + * @brief Reloads WDG's counter. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @notapi + */ +void wdg_lld_reset(WDGDriver * wdgp) { + + wdgp->wdg->KR = KR_KEY_RELOAD; +} + +#endif /* HAL_USE_WDG == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.h new file mode 100644 index 0000000..7528899 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.h @@ -0,0 +1,183 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file xWDGv1/hal_wdg_lld.h + * @brief WDG Driver subsystem low level driver header. + * + * @addtogroup WDG + * @{ + */ + +#ifndef HAL_WDG_LLD_H +#define HAL_WDG_LLD_H + +#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name RLR register definitions + * @{ + */ +#define STM32_IWDG_RL_MASK (0x00000FFF << 0) +#define STM32_IWDG_RL(n) ((n) << 0) +/** @} */ + +/** + * @name PR register definitions + * @{ + */ +#define STM32_IWDG_PR_MASK (7 << 0) +#define STM32_IWDG_PR_4 0U +#define STM32_IWDG_PR_8 1U +#define STM32_IWDG_PR_16 2U +#define STM32_IWDG_PR_32 3U +#define STM32_IWDG_PR_64 4U +#define STM32_IWDG_PR_128 5U +#define STM32_IWDG_PR_256 6U +/** @} */ + +/** + * @name WINR register definitions + * @{ + */ +#define STM32_IWDG_WIN_MASK (0x00000FFF << 0) +#define STM32_IWDG_WIN(n) ((n) << 0) +#define STM32_IWDG_WIN_DISABLED STM32_IWDG_WIN(0x00000FFF) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief IWDG driver enable switch. + * @details If set to @p TRUE the support for IWDG is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_WDG_USE_IWDG) || defined(__DOXYGEN__) +#define STM32_WDG_USE_IWDG FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_WDG_USE_IWDG && !STM32_HAS_IWDG +#error "IWDG not present in the selected device" +#endif + +#if !STM32_WDG_USE_IWDG +#error "WDG driver activated but no xWDG peripheral assigned" +#endif + +#if !defined(STM32_LSI_ENABLED) +#error "STM32_LSI_ENABLED not defined" +#endif + +#if (STM32_WDG_USE_IWDG == TRUE) && (STM32_LSI_ENABLED == FALSE) +#error "IWDG requires LSI clock" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an WDG driver. + */ +typedef struct WDGDriver WDGDriver; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Configuration of the IWDG_PR register. + * @details See the STM32 reference manual for details. + */ + uint32_t pr; + /** + * @brief Configuration of the IWDG_RLR register. + * @details See the STM32 reference manual for details. + */ + uint32_t rlr; +#if STM32_IWDG_IS_WINDOWED || defined(__DOXYGEN__) + /** + * @brief Configuration of the IWDG_WINR register. + * @details See the STM32 reference manual for details. + * @note This field is not present in F1, F2, F4, L1 sub-families. + */ + uint32_t winr; +#endif +} WDGConfig; + +/** + * @brief Structure representing an WDG driver. + */ +struct WDGDriver { + /** + * @brief Driver state. + */ + wdgstate_t state; + /** + * @brief Current configuration data. + */ + const WDGConfig *config; + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the IWDG registers block. + */ + IWDG_TypeDef *wdg; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_WDG_USE_IWDG && !defined(__DOXYGEN__) +extern WDGDriver WDGD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void wdg_lld_init(void); + void wdg_lld_start(WDGDriver *wdgp); + void wdg_lld_stop(WDGDriver *wdgp); + void wdg_lld_reset(WDGDriver *wdgp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_WDG == TRUE */ + +#endif /* HAL_WDG_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.c new file mode 100644 index 0000000..e9ffb25 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.c @@ -0,0 +1,452 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file STM32H7xx/hal_lld.c + * @brief STM32H7xx HAL subsystem low level driver source. + * + * @addtogroup HAL + * @{ + */ + +#include "hal.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief CMSIS system core clock variable. + * @note It is declared in system_stm32f7xx.h. + */ +uint32_t SystemCoreClock = STM32_CORE_CK; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes the backup domain. + * @note WARNING! Changing clock source impossible without resetting + * of the whole BKP domain. + */ +static inline void init_bkp_domain(void) { + + /* Backup domain access enabled and left open.*/ + PWR->CR1 |= PWR_CR1_DBP; + + /* Reset BKP domain if different clock source selected.*/ + if ((RCC->BDCR & STM32_RTCSEL_MASK) != STM32_RTCSEL) { + /* Backup domain reset.*/ + RCC->BDCR = RCC_BDCR_BDRST; + RCC->BDCR = 0; + } + +#if STM32_LSE_ENABLED +#if defined(STM32_LSE_BYPASS) + /* LSE Bypass.*/ + RCC->BDCR |= STM32_LSEDRV | RCC_BDCR_LSEON | RCC_BDCR_LSEBYP; +#else + /* No LSE Bypass.*/ + RCC->BDCR |= STM32_LSEDRV | RCC_BDCR_LSEON; +#endif + while ((RCC->BDCR & RCC_BDCR_LSERDY) == 0) + ; /* Waits until LSE is stable. */ +#endif + +#if HAL_USE_RTC + /* If the backup domain hasn't been initialized yet then proceed with + initialization.*/ + if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0) { + /* Selects clock source.*/ + RCC->BDCR |= STM32_RTCSEL; + + /* RTC clock enabled.*/ + RCC->BDCR |= RCC_BDCR_RTCEN; + } +#endif /* HAL_USE_RTC */ +} + +/** + * @brief Initializes the PWR unit. + */ +static inline void init_pwr(void) { +#if 0 + PWR_TypeDef *pwr = PWR; /* For inspection.*/ + (void)pwr; +#endif + + /* Lower C3 byte, it must be programmed at very first, then waiting for + power supply to stabilize.*/ + PWR->CR3 = STM32_PWR_CR3 & 0x000000FFU; + while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0) + ; /* CHTODO timeout handling.*/ + + PWR->CR1 = STM32_PWR_CR1 | 0xF0000000U; + PWR->CR2 = STM32_PWR_CR2; + PWR->CR3 = STM32_PWR_CR3; /* Other bits, lower byte is not changed. */ + PWR->CPUCR = STM32_PWR_CPUCR; + PWR->D3CR = STM32_VOS; +#if !defined(STM32_ENFORCE_H7_REV_XY) && !defined(STM32H723xx) + SYSCFG->PWRCR = STM32_ODEN; +#endif + while ((PWR->D3CR & PWR_D3CR_VOSRDY) == 0) + ; /* CHTODO timeout handling.*/ +#if STM32_PWR_CR2 & PWR_CR2_BREN +// while ((PWR->CR2 & PWR_CR2_BRRDY) == 0) +// ; +// rccEnableBKPRAM(true); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level HAL driver initialization. + * + * @notapi + */ +void hal_lld_init(void) { + +#if STM32_NO_INIT == FALSE + /* Reset of all peripherals. AHB3 is not reset entirely because FMC could + have been initialized in the board initialization file (board.c). + Note, GPIOs are not reset because initialized before this point in + board files.*/ + rccResetAHB1(~0); + rccResetAHB2(~0); + rccResetAHB3(~(RCC_AHB3RSTR_FMCRST | + 0x80000000U)); /* Was RCC_AHB3RSTR_CPURST in Rev-V.*/ + rccResetAHB4(~(RCC_APB4RSTR_SYSCFGRST | STM32_GPIO_EN_MASK)); + rccResetAPB1L(~0); + rccResetAPB1H(~0); + rccResetAPB2(~0); + rccResetAPB3(~0); + rccResetAPB4(~0); +#endif /* STM32_NO_INIT == FALSE */ + + /* DMA subsystems initialization.*/ +#if defined(STM32_BDMA_REQUIRED) + bdmaInit(); +#endif +#if defined(STM32_DMA_REQUIRED) + dmaInit(); +#endif +#if defined(STM32_MDMA_REQUIRED) + mdmaInit(); +#endif + + /* IRQ subsystem initialization.*/ + irqInit(); + + /* MPU initialization.*/ +#if (STM32_NOCACHE_SRAM1_SRAM2 == TRUE) || (STM32_NOCACHE_SRAM3 == TRUE) || \ + (STM32_NOCACHE_SRAM4 == TRUE) + { + uint32_t base, size; + +#if (STM32_NOCACHE_SRAM1_SRAM2 == TRUE) && (STM32_NOCACHE_SRAM3 == TRUE) + base = 0x30000000U; + size = MPU_RASR_SIZE_512K; +#elif (STM32_NOCACHE_SRAM1_SRAM2 == TRUE) && (STM32_NOCACHE_SRAM3 == FALSE) + base = 0x30000000U; + size = MPU_RASR_SIZE_256K; +#elif (STM32_NOCACHE_SRAM1_SRAM2 == FALSE) && (STM32_NOCACHE_SRAM3 == TRUE) + base = 0x30040000U; + size = MPU_RASR_SIZE_16K; +#elif (STM32_NOCACHE_SRAM4 == TRUE) + base = 0x38000000U; + size = MPU_RASR_SIZE_16K; +#else +#error "invalid constants used in mcuconf.h" +#endif + + /* The SRAM2 bank can optionally made a non cache-able area for use by + DMA engines.*/ + mpuConfigureRegion(STM32_NOCACHE_MPU_REGION, + base, + MPU_RASR_ATTR_AP_RW_RW | + MPU_RASR_ATTR_NON_CACHEABLE | + size | + MPU_RASR_ENABLE); + mpuEnable(MPU_CTRL_PRIVDEFENA); + + /* Invalidating data cache to make sure that the MPU settings are taken + immediately.*/ + SCB_CleanInvalidateDCache(); + } +#endif +} + +/** + * @brief STM32H7xx clocks and PLL initialization. + * @note All the involved constants come from the file @p board.h. + * @note This function should be invoked just after the system reset. + * + * @special + */ +void stm32_clock_init(void) { +#if STM32_NO_INIT == FALSE + uint32_t cfgr; + +#if 0 + RCC_TypeDef *rcc = RCC; /* For inspection.*/ + (void)rcc; +#endif + +#if defined(STM32_ENFORCE_H7_REV_XY) + /* Fix for errata 2.2.15: Reading from AXI SRAM might lead to data + read corruption. + AXI->TARG7_FN_MOD.*/ + *((volatile uint32_t *)(0x51000000 + 0x1108 + 0x7000)) = 0x00000001U; +#endif + + /* SYSCFG clock enabled here because it is a multi-functional unit shared + among multiple drivers.*/ + rccEnableAPB4(RCC_APB4ENR_SYSCFGEN, true); + + /* PWR initialization.*/ + init_pwr(); + + /* Backup domain initialization.*/ + init_bkp_domain(); + + /* HSI setup, it enforces the reset situation in order to handle possible + problems with JTAG probes and re-initializations.*/ + RCC->CR |= RCC_CR_HSION; /* Make sure HSI is ON. */ + while (!(RCC->CR & RCC_CR_HSIRDY)) + ; /* Wait until HSI is stable. */ + + /* HSI is selected as new source without touching the other fields in + CFGR. This is only required when using a debugger than can cause + restarts.*/ + RCC->CFGR = 0x00000000U; /* Reset SW to HSI. */ + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) + ; /* Wait until HSI is selected. */ + + /* Registers cleared to reset values.*/ +#if STM32_HSI_ENABLED == FALSE + RCC->CR = RCC_CR_HSION; /* CR Reset value. */ +#else + RCC->CR = RCC_CR_HSION | STM32_HSIDIV; /* CR Reset value. */ +#endif + RCC->HSICFGR = 0x40000000U; /* HSICFGR Reset value. */ +#if !defined(STM32_ENFORCE_H7_REV_XY) + RCC->CSICFGR = 0x20000000U; /* CSICFGR Reset value. */ +#endif + RCC->CSR = 0x00000000U; /* CSR reset value. */ + RCC->PLLCFGR = 0x01FF0000U; /* PLLCFGR reset value. */ + + /* Other clock-related settings, done before other things because + recommended in the RM.*/ + cfgr = STM32_MCO2SEL | RCC_CFGR_MCO2PRE_VALUE(STM32_MCO2PRE_VALUE) | + STM32_MCO1SEL | RCC_CFGR_MCO1PRE_VALUE(STM32_MCO1PRE_VALUE) | + RCC_CFGR_RTCPRE_VALUE(STM32_RTCPRE_VALUE) | + STM32_HRTIMSEL | STM32_STOPKERWUCK | STM32_STOPWUCK; +#if STM32_TIMPRE_ENABLE == TRUE + cfgr |= RCC_CFGR_TIMPRE; +#endif + RCC->CFGR = cfgr; + + /* HSE activation with optional bypass.*/ +#if STM32_HSE_ENABLED == TRUE +#if defined(STM32_HSE_BYPASS) + RCC->CR |= RCC_CR_HSEON | RCC_CR_HSEBYP; +#else + RCC->CR |= RCC_CR_HSEON; +#endif + while ((RCC->CR & RCC_CR_HSERDY) == 0) + ; /* Waits until HSE is stable. */ +#endif /* STM32_HSE_ENABLED == TRUE */ + + /* HSI48 activation.*/ +#if STM32_HSI48_ENABLED == TRUE + RCC->CR |= RCC_CR_HSI48ON; + while ((RCC->CR & RCC_CR_HSI48RDY) == 0) + ; /* Waits until HSI48 is stable. */ + +#endif /* STM32_HSI48_ENABLED == TRUE */ + + /* CSI activation.*/ +#if STM32_CSI_ENABLED == TRUE + RCC->CR |= RCC_CR_CSION; + while ((RCC->CR & RCC_CR_CSIRDY) == 0) + ; /* Waits until CSI is stable. */ +#endif /* STM32_CSI_ENABLED == TRUE */ + + /* LSI activation.*/ +#if STM32_LSI_ENABLED == TRUE + RCC->CSR |= RCC_CSR_LSION; + while ((RCC->CSR & RCC_CSR_LSIRDY) == 0) + ; /* Waits until LSI is stable. */ +#endif /* STM32_LSI_ENABLED == TRUE */ + + /* PLLs activation, it happens in parallel in order to + reduce boot time.*/ +#if (STM32_PLL1_ENABLED == TRUE) || \ + (STM32_PLL2_ENABLED == TRUE) || \ + (STM32_PLL3_ENABLED == TRUE) + { + uint32_t onmask = 0; + uint32_t rdymask = 0; + uint32_t cfgmask = 0; + + RCC->PLLCKSELR = RCC_PLLCKSELR_DIVM3_VALUE(STM32_PLL3_DIVM_VALUE) | + RCC_PLLCKSELR_DIVM2_VALUE(STM32_PLL2_DIVM_VALUE) | + RCC_PLLCKSELR_DIVM1_VALUE(STM32_PLL1_DIVM_VALUE) | + RCC_PLLCKSELR_PLLSRC_VALUE(STM32_PLLSRC); + + cfgmask = STM32_PLLCFGR_PLL3RGE | STM32_PLLCFGR_PLL3VCOSEL | RCC_PLLCFGR_PLL3FRACEN | + STM32_PLLCFGR_PLL2RGE | STM32_PLLCFGR_PLL2VCOSEL | RCC_PLLCFGR_PLL2FRACEN | + STM32_PLLCFGR_PLL1RGE | STM32_PLLCFGR_PLL1VCOSEL | RCC_PLLCFGR_PLL1FRACEN; + +#if STM32_PLL1_ENABLED == TRUE + RCC->PLL1FRACR = STM32_PLL1_FRACN; + RCC->PLL1DIVR = STM32_PLL1_DIVR | STM32_PLL1_DIVQ | + STM32_PLL1_DIVP | STM32_PLL1_DIVN; + onmask |= RCC_CR_PLL1ON; + rdymask |= RCC_CR_PLL1RDY; +#if STM32_PLL1_P_ENABLED == TRUE + cfgmask |= RCC_PLLCFGR_DIVP1EN; +#endif +#if STM32_PLL1_Q_ENABLED == TRUE + cfgmask |= RCC_PLLCFGR_DIVQ1EN; +#endif +#if STM32_PLL1_R_ENABLED == TRUE + cfgmask |= RCC_PLLCFGR_DIVR1EN; +#endif +#endif /* STM32_PLL1_ENABLED == TRUE */ + +#if STM32_PLL2_ENABLED == TRUE + RCC->PLL2FRACR = STM32_PLL2_FRACN; + RCC->PLL2DIVR = STM32_PLL2_DIVR | STM32_PLL2_DIVQ | + STM32_PLL2_DIVP | STM32_PLL2_DIVN; + onmask |= RCC_CR_PLL2ON; + rdymask |= RCC_CR_PLL2RDY; +#if STM32_PLL2_P_ENABLED == TRUE + cfgmask |= RCC_PLLCFGR_DIVP2EN; +#endif +#if STM32_PLL2_Q_ENABLED == TRUE + cfgmask |= RCC_PLLCFGR_DIVQ2EN; +#endif +#if STM32_PLL2_R_ENABLED == TRUE + cfgmask |= RCC_PLLCFGR_DIVR2EN; +#endif +#endif /* STM32_PLL2_ENABLED == TRUE */ + +#if STM32_PLL3_ENABLED == TRUE + RCC->PLL3FRACR = STM32_PLL3_FRACN; + RCC->PLL3DIVR = STM32_PLL3_DIVR | STM32_PLL3_DIVQ | + STM32_PLL3_DIVP | STM32_PLL3_DIVN; + onmask |= RCC_CR_PLL3ON; + rdymask |= RCC_CR_PLL3RDY; +#if STM32_PLL3_P_ENABLED == TRUE + cfgmask |= RCC_PLLCFGR_DIVP3EN; +#endif +#if STM32_PLL3_Q_ENABLED == TRUE + cfgmask |= RCC_PLLCFGR_DIVQ3EN; +#endif +#if STM32_PLL3_R_ENABLED == TRUE + cfgmask |= RCC_PLLCFGR_DIVR3EN; +#endif +#endif /* STM32_PLL3_ENABLED == TRUE */ + + /* Activating enabled PLLs and waiting for all of them to become ready.*/ + RCC->PLLCFGR = cfgmask & STM32_PLLCFGR_MASK; + RCC->CR |= onmask; + while ((RCC->CR & rdymask) != rdymask) + ; + } +#endif /* STM32_PLL1_ENABLED || STM32_PLL2_ENABLED || STM32_PLL3_ENABLED */ + + /* AHB and APB dividers.*/ + RCC->D1CFGR = STM32_D1CPRE | STM32_D1PPRE3 | STM32_D1HPRE; + RCC->D2CFGR = STM32_D2PPRE2 | STM32_D2PPRE1; + RCC->D3CFGR = STM32_D3PPRE4; + + /* Peripherals clocks.*/ + RCC->D1CCIPR = STM32_CKPERSEL | STM32_SDMMCSEL +#if !defined(STM32H723xx) + | STM32_QSPISEL | STM32_FMCSEL +#endif + ; + RCC->D2CCIP1R = STM32_SWPSEL | STM32_FDCANSEL | STM32_DFSDM1SEL | + STM32_SPDIFSEL | STM32_SPDIFSEL | STM32_SPI45SEL | + STM32_SPI123SEL | STM32_SAI1SEL +#if !defined(STM32H723xx) + | STM32_SAI23SEL +#endif + ; + RCC->D2CCIP2R = STM32_LPTIM1SEL | STM32_CECSEL | STM32_USBSEL | + STM32_RNGSEL | STM32_USART234578SEL +#if !defined(STM32H723xx) + | STM32_USART16SEL | STM32_I2C123SEL; +#else + | STM32_USART16910SEL | STM32_I2C1235SEL; +#endif + RCC->D3CCIPR = STM32_SPI6SEL | STM32_SAI4BSEL | STM32_SAI4ASEL | + STM32_ADCSEL | STM32_LPTIM345SEL | STM32_LPTIM2SEL | + STM32_I2C4SEL | STM32_LPUART1SEL; + + /* Flash setup.*/ + FLASH->ACR = FLASH_ACR_WRHIGHFREQ_1 | FLASH_ACR_WRHIGHFREQ_0 | + STM32_FLASHBITS; + while ((FLASH->ACR & FLASH_ACR_LATENCY) != + (STM32_FLASHBITS & FLASH_ACR_LATENCY)) { + } + + /* Switching to the configured clock source if it is different + from HSI.*/ +#if STM32_SW != STM32_SW_HSI_CK + RCC->CFGR |= STM32_SW; /* Switches on the selected clock source. */ + while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 3U)) + ; +#endif + +#if 0 + /* Peripheral clock sources.*/ + RCC->DCKCFGR2 = STM32_SDMMCSEL | STM32_CK48MSEL | STM32_CECSEL | + STM32_LPTIM1SEL | STM32_I2C4SEL | STM32_I2C3SEL | + STM32_I2C2SEL | STM32_I2C1SEL | STM32_UART8SEL | + STM32_UART7SEL | STM32_USART6SEL | STM32_UART5SEL | + STM32_UART4SEL | STM32_USART3SEL | STM32_USART2SEL | + STM32_USART1SEL; +#endif + + /* RAM1 2 and 3 clocks enabled.*/ + rccEnableSRAM1(true); + rccEnableSRAM2(true); +#if !defined(STM32H723xx) + rccEnableSRAM3(true); +#endif +#endif /* STM32_NO_INIT */ +} + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.h new file mode 100644 index 0000000..b1b9a42 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.h @@ -0,0 +1,3199 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file STM32H7xx/hal_lld.h + * @brief STM32H7xx HAL subsystem low level driver header. + * @pre This module requires the following macros to be defined in the + * @p board.h file: + * - STM32_LSECLK. + * - STM32_LSEDRV. + * - STM32_LSE_BYPASS (optionally). + * - STM32_HSECLK. + * - STM32_HSE_BYPASS (optionally). + * - STM32_VDD (as hundredths of Volt). + * . + * One of the following macros must also be defined: + * - STM32H743xx, STM32H753xx very high-performance MCUs. + * . + * + * @addtogroup HAL + * @{ + */ + +#ifndef HAL_LLD_H +#define HAL_LLD_H + +#include "stm32_registry.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Platform identification macros + * @{ + */ +#if defined(STM32H723xx) || defined(__DOXYGEN__) +#define PLATFORM_NAME "STM32H723 Single Core Very High Performance with DSP and FPU" + +#elif defined(STM32H742xx) || defined(__DOXYGEN__) +#define PLATFORM_NAME "STM32H742 Single Core Very High Performance with DSP and FPU" + +#elif defined(STM32H743xx) || defined(__DOXYGEN__) +#define PLATFORM_NAME "STM32H743 Single Core Very High Performance with DSP and FPU" + +#elif defined(STM32H753xx) +#define PLATFORM_NAME "STM32H753 Single Core Very High Performance with DSP and FPU" + +#elif defined(STM32H745xx) || defined(__DOXYGEN__) +#define PLATFORM_NAME "STM32H745 Dual Core Very High Performance with DSP and FPU" + +#elif defined(STM32H755xx) +#define PLATFORM_NAME "STM32H755 Dual Core Very High Performance with DSP and FPU" + +#elif defined(STM32H747xx) || defined(__DOXYGEN__) +#define PLATFORM_NAME "STM32H747 Dual Core Very High Performance with DSP and FPU" + +#elif defined(STM32H757xx) +#define PLATFORM_NAME "STM32H757 Dual Core Very High Performance with DSP and FPU" + +#elif defined(STM32H750xx) +#define PLATFORM_NAME "STM32H750 Value Line Very High Performance with DSP and FPU" + +#else +#error "STM32H7xx device not specified" +#endif +/** @} */ + +/** + * @name Sub-family identifier + */ +#if !defined(STM32H7XX) || defined(__DOXYGEN__) +#define STM32H7XX +#endif +/** @} */ + +#if !defined(STM32_ENFORCE_H7_REV_XY) +/** + * @name Absolute Maximum Ratings + * @{ + */ + +#if !defined(STM32H723xx) + +/** + * @brief Absolute maximum system clock. + */ +#define STM32_SYSCLK_MAX 480000000 + +/** + * @brief Maximum SYSCLK clock frequency without voltage boost. + */ +#define STM32_SYSCLK_MAX_NOBOOST 400000000 + +#else // then defined(STM32H723xx) + +/** + * @brief Absolute maximum system clock. + */ +#define STM32_SYSCLK_MAX 550000000 + +/** + * @brief Maximum SYSCLK clock frequency without voltage boost. + */ +#define STM32_SYSCLK_MAX_NOBOOST 550000000 + +#endif // !defined(STM32H723xx) + +/** + * @brief Absolute maximum HCLK clock. + */ +#define STM32_HCLK_MAX (STM32_SYSCLK_MAX / 2) + +/** + * @brief Maximum HSE clock frequency. + */ +#define STM32_HSECLK_MAX 48000000 + +/** + * @brief Maximum HSE clock frequency using an external source. + */ +#define STM32_HSECLK_BYP_MAX 50000000 + +/** + * @brief Minimum HSE clock frequency. + */ +#define STM32_HSECLK_MIN 4000000 + +/** + * @brief Minimum HSE clock frequency. + */ +#define STM32_HSECLK_BYP_MIN 4000000 + +/** + * @brief Maximum LSE clock frequency. + */ +#define STM32_LSE_CK_MAX 32768 + +/** + * @brief Maximum LSE clock frequency. + */ +#define STM32_LSE_CK_BYP_MAX 1000000 + +/** + * @brief Minimum LSE clock frequency. + */ +#define STM32_LSE_CK_MIN 32768 + +/** + * @brief Minimum PLLs input clock frequency.. + */ +#define STM32_PLLIN_MIN 1000000 + +/** + * @brief PLLs input threshold frequency 1. + */ +#define STM32_PLLIN_THRESHOLD1 2000000 + +/** + * @brief PLLs input threshold frequency 2. + */ +#define STM32_PLLIN_THRESHOLD2 4000000 + +/** + * @brief PLLs input threshold frequency 3. + */ +#define STM32_PLLIN_THRESHOLD3 8000000 + +/** + * @brief Maximum PLLs input clock frequency. + */ +#define STM32_PLLIN_MAX 16000000 + +/** + * @brief Minimum PLLs VCO clock frequency. + */ +#define STM32_PLLVCO_MIN 150000000 /* DS says 192, RM says 150. */ + +/** + * @brief Threshold PLLs clock frequency. + */ +#define STM32_PLLVCO_THRESHOLD 420000000 + +/** + * @brief Maximum PLLs VCOH clock frequency. + */ +#define STM32_PLLVCO_MAX 960000000 + +/** + * @brief Maximum APB1 clock frequency. + */ +#define STM32_PCLK1_MAX (STM32_HCLK_MAX / 2) + +/** + * @brief Maximum APB2 clock frequency. + */ +#define STM32_PCLK2_MAX (STM32_HCLK_MAX / 2) + +/** + * @brief Maximum APB3 clock frequency. + */ +#define STM32_PCLK3_MAX (STM32_HCLK_MAX / 2) + +/** + * @brief Maximum APB4 clock frequency. + */ +#define STM32_PCLK4_MAX (STM32_HCLK_MAX / 2) + +/** + * @brief Maximum SPI1, SPI2 and SPI3 clock frequency. + */ +#define STM32_SPI123_MAX 200000000 + +/** + * @brief Maximum SPI4, SPI5 and SPI6 clock frequency. + */ +#define STM32_SPI456_MAX 125000000 + +/** + * @brief Maximum ADC clock frequency. + */ +#define STM32_ADCCLK_MAX 50000000 +/** @} */ + +#else /* defined(STM32_ENFORCE_H7_REV_XY) */ + +#define STM32_SYSCLK_MAX 400000000 +#define STM32_SYSCLK_MAX_NOBOOST 400000000 +#define STM32_HCLK_MAX (STM32_SYSCLK_MAX / 2) +#define STM32_HSECLK_MAX 48000000 +#define STM32_HSECLK_BYP_MAX 50000000 +#define STM32_HSECLK_MIN 4000000 +#define STM32_HSECLK_BYP_MIN 4000000 +#define STM32_LSE_CK_MAX 32768 +#define STM32_LSE_CK_BYP_MAX 1000000 +#define STM32_LSE_CK_MIN 32768 +#define STM32_PLLIN_MIN 1000000 +#define STM32_PLLIN_THRESHOLD1 2000000 +#define STM32_PLLIN_THRESHOLD2 4000000 +#define STM32_PLLIN_THRESHOLD3 8000000 +#define STM32_PLLIN_MAX 16000000 +#define STM32_PLLVCO_MIN 150000000 +#define STM32_PLLVCO_THRESHOLD 420000000 +#define STM32_PLLVCO_MAX 836000000 +#define STM32_PCLK1_MAX (STM32_HCLK_MAX / 2) +#define STM32_PCLK2_MAX (STM32_HCLK_MAX / 2) +#define STM32_PCLK3_MAX (STM32_HCLK_MAX / 2) +#define STM32_PCLK4_MAX (STM32_HCLK_MAX / 2) +#define STM32_SPI123_MAX 133000000 +#define STM32_SPI456_MAX 100000000 +#define STM32_ADCCLK_MAX 36000000 + +#endif /* defined(STM32_ENFORCE_H7_REV_XY) */ + +/** + * @name Internal clock sources frequencies + * @{ + */ +#define STM32_HSI_OSC 64000000 +#define STM32_HSI48_OSC 48000000 +#define STM32_CSI_OSC 4000000 +#define STM32_LSI_OSC 32000 +/** @} */ + +/** + * @name Register helpers not found in ST headers + * @{ + */ +#define RCC_CR_HSIDIV_VALUE(n) ((n) << 3U) + +#define RCC_CFGR_SW_VALUE(n) ((n) << 0U) +#define RCC_CFGR_RTCPRE_VALUE(n) ((n) << 8U) +#define RCC_CFGR_MCO1PRE_VALUE(n) ((n) << 18U) +#define RCC_CFGR_MCO1_VALUE(n) ((n) << 22U) +#define RCC_CFGR_MCO2PRE_VALUE(n) ((n) << 25U) +#define RCC_CFGR_MCO2_VALUE(n) ((n) << 29U) + +#define RCC_D1CFGR_D1HPRE_VALUE(n) ((n) << RCC_D1CFGR_HPRE_Pos) +#define RCC_D1CFGR_D1CPRE_VALUE(n) ((n) << RCC_D1CFGR_D1CPRE_Pos) +#define RCC_D1CFGR_D1PPRE3_VALUE(n) ((n) << RCC_D1CFGR_D1PPRE_Pos) + +#define RCC_D2CFGR_D2PPRE1_VALUE(n) ((n) << RCC_D2CFGR_D2PPRE1_Pos) +#define RCC_D2CFGR_D2PPRE2_VALUE(n) ((n) << RCC_D2CFGR_D2PPRE2_Pos) + +#define RCC_D3CFGR_D3PPRE4_VALUE(n) ((n) << RCC_D3CFGR_D3PPRE_Pos) + +#define RCC_PLLCKSELR_PLLSRC_VALUE(n) ((n) << RCC_PLLCKSELR_PLLSRC_Pos) + +#define RCC_PLLCKSELR_DIVM1_VALUE(n) ((n) << RCC_PLLCKSELR_DIVM1_Pos) +#define RCC_PLLCKSELR_DIVM2_VALUE(n) ((n) << RCC_PLLCKSELR_DIVM2_Pos) +#define RCC_PLLCKSELR_DIVM3_VALUE(n) ((n) << RCC_PLLCKSELR_DIVM3_Pos) + +#define RCC_PLL1DIVR_DIVN1_VALUE(n) ((n) << RCC_PLL1DIVR_N1) +#define RCC_PLL1DIVR_DIVP1_VALUE(n) ((n) << RCC_PLL1DIVR_P1) +#define RCC_PLL1DIVR_DIVQ1_VALUE(n) ((n) << RCC_PLL1DIVR_Q1) +#define RCC_PLL1DIVR_DIVR1_VALUE(n) ((n) << RCC_PLL1DIVR_R1) + +#define RCC_PLL1FRACR_FRACN1_VALUE(n) ((n) << RCC_PLL1FRACR_FRACN1_Pos) + +#define RCC_PLL2DIVR_DIVN2_VALUE(n) ((n) << RCC_PLL2DIVR_N2) +#define RCC_PLL2DIVR_DIVP2_VALUE(n) ((n) << RCC_PLL2DIVR_P2) +#define RCC_PLL2DIVR_DIVQ2_VALUE(n) ((n) << RCC_PLL2DIVR_Q2) +#define RCC_PLL2DIVR_DIVR2_VALUE(n) ((n) << RCC_PLL2DIVR_R2) + +#define RCC_PLL2FRACR_FRACN2_VALUE(n) ((n) << RCC_PLL2FRACR_FRACN2_Pos) + +#define RCC_PLL3DIVR_DIVN3_VALUE(n) ((n) << RCC_PLL3DIVR_N3) +#define RCC_PLL3DIVR_DIVP3_VALUE(n) ((n) << RCC_PLL3DIVR_P3) +#define RCC_PLL3DIVR_DIVQ3_VALUE(n) ((n) << RCC_PLL3DIVR_Q3) +#define RCC_PLL3DIVR_DIVR3_VALUE(n) ((n) << RCC_PLL3DIVR_R3) + +#define RCC_PLL3FRACR_FRACN3_VALUE(n) ((n) << RCC_PLL3FRACR_FRACN3_Pos) + +#define RCC_D1CCIPR_CKPERSEL_VALUE(n) ((n) << RCC_D1CCIPR_CKPERSEL_Pos) +#define RCC_D1CCIPR_SDMMCSEL_VALUE(n) ((n) << RCC_D1CCIPR_SDMMCSEL_Pos) +#if !defined(STM32H723xx) +#define RCC_D1CCIPR_QSPISEL_VALUE(n) ((n) << RCC_D1CCIPR_QSPISEL_Pos) +#endif +#define RCC_D1CCIPR_FMCSEL_VALUE(n) ((n) << RCC_D1CCIPR_FMCSEL_Pos) + +#define RCC_D2CCIP1R_SWPSEL_VALUE(n) ((n) << RCC_D2CCIP1R_SWPSEL_Pos) +#define RCC_D2CCIP1R_FDCANSEL_VALUE(n) ((n) << RCC_D2CCIP1R_FDCANSEL_Pos) +#define RCC_D2CCIP1R_DFSDM1SEL_VALUE(n) ((n) << RCC_D2CCIP1R_DFSDM1SEL_Pos) +#define RCC_D2CCIP1R_SPDIFSEL_VALUE(n) ((n) << RCC_D2CCIP1R_SPDIFSEL_Pos) +#define RCC_D2CCIP1R_SPI45SEL_VALUE(n) ((n) << RCC_D2CCIP1R_SPI45SEL_Pos) +#define RCC_D2CCIP1R_SPI123SEL_VALUE(n) ((n) << RCC_D2CCIP1R_SPI123SEL_Pos) +#if !defined(STM32H723xx) +#define RCC_D2CCIP1R_SAI23SEL_VALUE(n) ((n) << RCC_D2CCIP1R_SAI23SEL_Pos) +#endif +#define RCC_D2CCIP1R_SAI1SEL_VALUE(n) ((n) << RCC_D2CCIP1R_SAI1SEL_Pos) + +#define RCC_D2CCIP2R_LPTIM1SEL_VALUE(n) ((n) << RCC_D2CCIP2R_LPTIM1SEL_Pos) +#define RCC_D2CCIP2R_CECSEL_VALUE(n) ((n) << RCC_D2CCIP2R_CECSEL_Pos) +#define RCC_D2CCIP2R_USBSEL_VALUE(n) ((n) << RCC_D2CCIP2R_USBSEL_Pos) +#if !defined(STM32H723xx) +#define RCC_D2CCIP2R_I2C123SEL_VALUE(n) ((n) << RCC_D2CCIP2R_I2C123SEL_Pos) +#else +#define RCC_D2CCIP2R_I2C1235SEL_VALUE(n) ((n) << RCC_D2CCIP2R_I2C1235SEL_Pos) +#endif +#define RCC_D2CCIP2R_RNGSEL_VALUE(n) ((n) << RCC_D2CCIP2R_RNGSEL_Pos) +#if !defined(STM32H723xx) +#define RCC_D2CCIP2R_USART16SEL_VALUE(n) ((n) << RCC_D2CCIP2R_USART16SEL_Pos) +#else +#define RCC_D2CCIP2R_USART16910SEL_VALUE(n) ((n) << RCC_D2CCIP2R_USART16910SEL_Pos) +#endif +#define RCC_D2CCIP2R_USART234578SEL_VALUE(n) ((n) << RCC_D2CCIP2R_USART28SEL_Pos) + +#define RCC_D3CCIPR_SPI6SEL_VALUE(n) ((n) << RCC_D3CCIPR_SPI6SEL_Pos) +#define RCC_D3CCIPR_SAI4BSEL_VALUE(n) ((n) << RCC_D3CCIPR_SAI4BSEL_Pos) +#define RCC_D3CCIPR_SAI4ASEL_VALUE(n) ((n) << RCC_D3CCIPR_SAI4ASEL_Pos) +#define RCC_D3CCIPR_ADCSEL_VALUE(n) ((n) << RCC_D3CCIPR_ADCSEL_Pos) +#define RCC_D3CCIPR_LPTIM345SEL_VALUE(n) ((n) << RCC_D3CCIPR_LPTIM345SEL_Pos) +#define RCC_D3CCIPR_LPTIM2SEL_VALUE(n) ((n) << RCC_D3CCIPR_LPTIM2SEL_Pos) +#define RCC_D3CCIPR_I2C4SEL_VALUE(n) ((n) << RCC_D3CCIPR_I2C4SEL_Pos) +#define RCC_D3CCIPR_LPUART1SEL_VALUE(n) ((n) << RCC_D3CCIPR_LPUART1SEL_Pos) + +#define RCC_BDCR_RTCSEL_VALUE(n) ((n) << RCC_BDCR_RTCSEL_Pos) +/** @} */ + +/** + * @name Configuration switches to be used in @p mcuconf.h + * @{ + */ +#define STM32_ODEN_DISABLED 0U +#define STM32_ODEN_ENABLED (SYSCFG_PWRCR_ODEN) + +#define STM32_VOS_SCALE3 (PWR_D3CR_VOS_0) +#define STM32_VOS_SCALE2 (PWR_D3CR_VOS_1) +#define STM32_VOS_SCALE1 (PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0) + +#define STM32_SW_HSI_CK RCC_CFGR_SW_VALUE(0U) +#define STM32_SW_CSI_CK RCC_CFGR_SW_VALUE(1U) +#define STM32_SW_HSE_CK RCC_CFGR_SW_VALUE(2U) +#define STM32_SW_PLL1_P_CK RCC_CFGR_SW_VALUE(3U) + +#define STM32_D1CPRE_DIV1 RCC_D1CFGR_D1CPRE_VALUE(0U) +#define STM32_D1CPRE_DIV2 RCC_D1CFGR_D1CPRE_VALUE(8U) +#define STM32_D1CPRE_DIV4 RCC_D1CFGR_D1CPRE_VALUE(9U) +#define STM32_D1CPRE_DIV8 RCC_D1CFGR_D1CPRE_VALUE(10U) +#define STM32_D1CPRE_DIV16 RCC_D1CFGR_D1CPRE_VALUE(11U) +#define STM32_D1CPRE_DIV64 RCC_D1CFGR_D1CPRE_VALUE(12U) +#define STM32_D1CPRE_DIV128 RCC_D1CFGR_D1CPRE_VALUE(13U) +#define STM32_D1CPRE_DIV256 RCC_D1CFGR_D1CPRE_VALUE(14U) +#define STM32_D1CPRE_DIV512 RCC_D1CFGR_D1CPRE_VALUE(15U) + +#define STM32_D1HPRE_DIV1 RCC_D1CFGR_D1HPRE_VALUE(0U) +#define STM32_D1HPRE_DIV2 RCC_D1CFGR_D1HPRE_VALUE(8U) +#define STM32_D1HPRE_DIV4 RCC_D1CFGR_D1HPRE_VALUE(9U) +#define STM32_D1HPRE_DIV8 RCC_D1CFGR_D1HPRE_VALUE(10U) +#define STM32_D1HPRE_DIV16 RCC_D1CFGR_D1HPRE_VALUE(11U) +#define STM32_D1HPRE_DIV64 RCC_D1CFGR_D1HPRE_VALUE(12U) +#define STM32_D1HPRE_DIV128 RCC_D1CFGR_D1HPRE_VALUE(13U) +#define STM32_D1HPRE_DIV256 RCC_D1CFGR_D1HPRE_VALUE(14U) +#define STM32_D1HPRE_DIV512 RCC_D1CFGR_D1HPRE_VALUE(15U) + +#define STM32_D1PPRE3_DIV1 RCC_D1CFGR_D1PPRE3_VALUE(0U) +#define STM32_D1PPRE3_DIV2 RCC_D1CFGR_D1PPRE3_VALUE(4U) +#define STM32_D1PPRE3_DIV4 RCC_D1CFGR_D1PPRE3_VALUE(5U) +#define STM32_D1PPRE3_DIV8 RCC_D1CFGR_D1PPRE3_VALUE(6U) +#define STM32_D1PPRE3_DIV16 RCC_D1CFGR_D1PPRE3_VALUE(7U) + +#define STM32_D2PPRE1_DIV1 RCC_D2CFGR_D2PPRE1_VALUE(0U) +#define STM32_D2PPRE1_DIV2 RCC_D2CFGR_D2PPRE1_VALUE(4U) +#define STM32_D2PPRE1_DIV4 RCC_D2CFGR_D2PPRE1_VALUE(5U) +#define STM32_D2PPRE1_DIV8 RCC_D2CFGR_D2PPRE1_VALUE(6U) +#define STM32_D2PPRE1_DIV16 RCC_D2CFGR_D2PPRE1_VALUE(7U) + +#define STM32_D2PPRE2_DIV1 RCC_D2CFGR_D2PPRE2_VALUE(0U) +#define STM32_D2PPRE2_DIV2 RCC_D2CFGR_D2PPRE2_VALUE(4U) +#define STM32_D2PPRE2_DIV4 RCC_D2CFGR_D2PPRE2_VALUE(5U) +#define STM32_D2PPRE2_DIV8 RCC_D2CFGR_D2PPRE2_VALUE(6U) +#define STM32_D2PPRE2_DIV16 RCC_D2CFGR_D2PPRE2_VALUE(7U) + +#define STM32_D3PPRE4_DIV1 RCC_D3CFGR_D3PPRE4_VALUE(0U) +#define STM32_D3PPRE4_DIV2 RCC_D3CFGR_D3PPRE4_VALUE(4U) +#define STM32_D3PPRE4_DIV4 RCC_D3CFGR_D3PPRE4_VALUE(5U) +#define STM32_D3PPRE4_DIV8 RCC_D3CFGR_D3PPRE4_VALUE(6U) +#define STM32_D3PPRE4_DIV16 RCC_D3CFGR_D3PPRE4_VALUE(7U) + +#define STM32_HSIDIV_DIV1 RCC_CR_HSIDIV_VALUE(0U) +#define STM32_HSIDIV_DIV2 RCC_CR_HSIDIV_VALUE(1U) +#define STM32_HSIDIV_DIV4 RCC_CR_HSIDIV_VALUE(2U) +#define STM32_HSIDIV_DIV8 RCC_CR_HSIDIV_VALUE(3U) + +#define STM32_MCO1SEL_HSI_CK RCC_CFGR_MCO1_VALUE(0U) +#define STM32_MCO1SEL_LSE_CK RCC_CFGR_MCO1_VALUE(1U) +#define STM32_MCO1SEL_HSE_CK RCC_CFGR_MCO1_VALUE(2U) +#define STM32_MCO1SEL_PLL1_Q_CK RCC_CFGR_MCO1_VALUE(3U) +#define STM32_MCO1SEL_HSI48_CK RCC_CFGR_MCO1_VALUE(4U) + +#define STM32_MCO2SEL_SYS_CK RCC_CFGR_MCO2_VALUE(0U) +#define STM32_MCO2SEL_PLL2_P_CK RCC_CFGR_MCO2_VALUE(1U) +#define STM32_MCO2SEL_HSE_CK RCC_CFGR_MCO2_VALUE(2U) +#define STM32_MCO2SEL_PLL1_P_CK RCC_CFGR_MCO2_VALUE(3U) +#define STM32_MCO2SEL_CSI_CK RCC_CFGR_MCO2_VALUE(4U) +#define STM32_MCO2SEL_LSI_CK RCC_CFGR_MCO2_VALUE(5U) + +#define STM32_RTCSEL_MASK RCC_BDCR_RTCSEL_Msk +#define STM32_RTCSEL_NOCLK RCC_BDCR_RTCSEL_VALUE(0U) +#define STM32_RTCSEL_LSE_CK RCC_BDCR_RTCSEL_VALUE(1U) +#define STM32_RTCSEL_LSI_CK RCC_BDCR_RTCSEL_VALUE(2U) +#define STM32_RTCSEL_HSE_1M_CK RCC_BDCR_RTCSEL_VALUE(3U) + +#define STM32_HRTIMSEL_C_CLK RCC_CFGR_HRTIMSEL + +#define STM32_STOPKERWUCK_ENABLED RCC_CFGR_STOPKERWUCK + +#define STM32_STOPWUCK_ENABLED RCC_CFGR_STOPKERWUCK + +#define STM32_PLLSRC_HSI_CK RCC_PLLCKSELR_PLLSRC_VALUE(0U) +#define STM32_PLLSRC_CSI_CK RCC_PLLCKSELR_PLLSRC_VALUE(1U) +#define STM32_PLLSRC_HSE_CK RCC_PLLCKSELR_PLLSRC_VALUE(2U) +#define STM32_PLLSRC_DISABLE RCC_PLLCKSELR_PLLSRC_VALUE(23U) + +#define STM32_CKPERSEL_HSI_CK RCC_D1CCIPR_CKPERSEL_VALUE(0U) +#define STM32_CKPERSEL_CSI_CK RCC_D1CCIPR_CKPERSEL_VALUE(1U) +#define STM32_CKPERSEL_HSE_CK RCC_D1CCIPR_CKPERSEL_VALUE(2U) + +#define STM32_SDMMCSEL_PLL1_Q_CK RCC_D1CCIPR_SDMMCSEL_VALUE(0U) +#define STM32_SDMMCSEL_PLL2_R_CK RCC_D1CCIPR_SDMMCSEL_VALUE(1U) + +#if !defined(STM32H723xx) +#define STM32_QSPISEL_HCLK RCC_D1CCIPR_QSPISEL_VALUE(0U) +#define STM32_QSPISEL_PLL1_Q_CK RCC_D1CCIPR_QSPISEL_VALUE(1U) +#define STM32_QSPISEL_PLL2_R_CK RCC_D1CCIPR_QSPISEL_VALUE(2U) +#define STM32_QSPISEL_PER_CK RCC_D1CCIPR_QSPISEL_VALUE(3U) +#endif + +#define STM32_FMCSEL_HCLK RCC_D1CCIPR_FMCSEL_VALUE(0U) +#define STM32_FMCSEL_PLL1_Q_CK RCC_D1CCIPR_FMCSEL_VALUE(1U) +#define STM32_FMCSEL_PLL2_R_CK RCC_D1CCIPR_FMCSEL_VALUE(2U) +#define STM32_FMCSEL_PER_CK RCC_D1CCIPR_FMCSEL_VALUE(3U) + +#define STM32_SWPSEL_PCLK1 RCC_D2CCIP1R_SWPSEL_VALUE(0U) +#define STM32_SWPSEL_HSI_KER_CK RCC_D2CCIP1R_SWPSEL_VALUE(1U) + +#define STM32_FDCANSEL_HSE_CK RCC_D2CCIP1R_FDCANSEL_VALUE(0U) +#define STM32_FDCANSEL_PLL1_Q_CK RCC_D2CCIP1R_FDCANSEL_VALUE(1U) +#define STM32_FDCANSEL_PLL2_Q_CK RCC_D2CCIP1R_FDCANSEL_VALUE(2U) + +#define STM32_DFSDM1SEL_PCLK2 RCC_D2CCIP1R_DFSDM1SEL_VALUE(0U) +#define STM32_DFSDM1SEL_SYS_CK RCC_D2CCIP1R_DFSDM1SEL_VALUE(1U) + +#define STM32_SPDIFSEL_PLL1_Q_CK RCC_D2CCIP1R_SPDIFSEL_VALUE(0U) +#define STM32_SPDIFSEL_PLL2_R_CK RCC_D2CCIP1R_SPDIFSEL_VALUE(1U) +#define STM32_SPDIFSEL_PLL3_R_CK RCC_D2CCIP1R_SPDIFSEL_VALUE(2U) +#define STM32_SPDIFSEL_HSI_KET_CLK RCC_D2CCIP1R_SPDIFSEL_VALUE(3U) + +#define STM32_SPI45SEL_PCLK2 RCC_D2CCIP1R_SPI45SEL_VALUE(0U) +#define STM32_SPI45SEL_PLL2_Q_CK RCC_D2CCIP1R_SPI45SEL_VALUE(1U) +#define STM32_SPI45SEL_PLL3_Q_CK RCC_D2CCIP1R_SPI45SEL_VALUE(2U) +#define STM32_SPI45SEL_HSI_KER_CK RCC_D2CCIP1R_SPI45SEL_VALUE(3U) +#define STM32_SPI45SEL_CSI_KER_CK RCC_D2CCIP1R_SPI45SEL_VALUE(4U) +#define STM32_SPI45SEL_HSE_CK RCC_D2CCIP1R_SPI45SEL_VALUE(5U) + +#define STM32_SPI123SEL_PLL1_Q_CK RCC_D2CCIP1R_SPI123SEL_VALUE(0U) +#define STM32_SPI123SEL_PLL2_P_CK RCC_D2CCIP1R_SPI123SEL_VALUE(1U) +#define STM32_SPI123SEL_PLL3_P_CK RCC_D2CCIP1R_SPI123SEL_VALUE(2U) +#define STM32_SPI123SEL_I2S_CKIN RCC_D2CCIP1R_SPI123SEL_VALUE(3U) +#define STM32_SPI123SEL_PER_CK RCC_D2CCIP1R_SPI123SEL_VALUE(4U) + +#if !defined(STM32H723xx) +#define STM32_SAI23SEL_PLL1_Q_CK RCC_D2CCIP1R_SAI23SEL_VALUE(0U) +#define STM32_SAI23SEL_PLL2_P_CK RCC_D2CCIP1R_SAI23SEL_VALUE(1U) +#define STM32_SAI23SEL_PLL3_P_CK RCC_D2CCIP1R_SAI23SEL_VALUE(2U) +#define STM32_SAI23SEL_I2S_CKIN RCC_D2CCIP1R_SAI23SEL_VALUE(3U) +#define STM32_SAI23SEL_PER_CK RCC_D2CCIP1R_SAI23SEL_VALUE(4U) +#endif + +#define STM32_SAI1SEL_PLL1_Q_CK RCC_D2CCIP1R_SAI1SEL_VALUE(0U) +#define STM32_SAI1SEL_PLL2_P_CK RCC_D2CCIP1R_SAI1SEL_VALUE(1U) +#define STM32_SAI1SEL_PLL3_P_CK RCC_D2CCIP1R_SAI1SEL_VALUE(2U) +#define STM32_SAI1SEL_I2S_CKIN RCC_D2CCIP1R_SAI1SEL_VALUE(3U) +#define STM32_SAI1SEL_PER_CK RCC_D2CCIP1R_SAI1SEL_VALUE(4U) + +#define STM32_LPTIM1SEL_PCLK1 RCC_D2CCIP2R_LPTIM1SEL_VALUE(0U) +#define STM32_LPTIM1SEL_PLL2_P_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(1U) +#define STM32_LPTIM1SEL_PLL3_R_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(2U) +#define STM32_LPTIM1SEL_LSE_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(3U) +#define STM32_LPTIM1SEL_LSI_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(4U) +#define STM32_LPTIM1SEL_PER_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(5U) + +#define STM32_CECSEL_LSE_CK RCC_D2CCIP2R_CECSEL_VALUE(0U) +#define STM32_CECSEL_LSI_CK RCC_D2CCIP2R_CECSEL_VALUE(1U) +#define STM32_CECSEL_CSI_KER_CK RCC_D2CCIP2R_CECSEL_VALUE(2U) +#define STM32_CECSEL_DISABLE RCC_D2CCIP2R_CECSEL_VALUE(3U) + +#define STM32_USBSEL_DISABLE RCC_D2CCIP2R_USBSEL_VALUE(0U) +#define STM32_USBSEL_PLL1_Q_CK RCC_D2CCIP2R_USBSEL_VALUE(1U) +#define STM32_USBSEL_PLL3_Q_CK RCC_D2CCIP2R_USBSEL_VALUE(2U) +#define STM32_USBSEL_HSI48_CK RCC_D2CCIP2R_USBSEL_VALUE(3U) + +#define STM32_I2C1235SEL_PCLK1 RCC_D2CCIP2R_I2C1235SEL_VALUE(0U) +#define STM32_I2C1235SEL_PLL3_R_CK RCC_D2CCIP2R_I2C1235SEL_VALUE(1U) +#define STM32_I2C1235SEL_HSI_KER_CK RCC_D2CCIP2R_I2C1235SEL_VALUE(2U) +#define STM32_I2C1235SEL_CSI_KER_CK RCC_D2CCIP2R_I2C1235SEL_VALUE(3U) + +#define STM32_RNGSEL_HSI48_CK RCC_D2CCIP2R_RNGSEL_VALUE(0U) +#define STM32_RNGSEL_PLL1_Q_CK RCC_D2CCIP2R_RNGSEL_VALUE(1U) +#define STM32_RNGSEL_LSE_CK RCC_D2CCIP2R_RNGSEL_VALUE(2U) +#define STM32_RNGSEL_LSI_CK RCC_D2CCIP2R_RNGSEL_VALUE(3U) + +#if !defined(STM32H723xx) +#define STM32_USART16SEL_PCLK2 RCC_D2CCIP2R_USART16SEL_VALUE(0U) +#define STM32_USART16SEL_PLL2_Q_CK RCC_D2CCIP2R_USART16SEL_VALUE(1U) +#define STM32_USART16SEL_PLL3_Q_CK RCC_D2CCIP2R_USART16SEL_VALUE(2U) +#define STM32_USART16SEL_HSI_KER_CK RCC_D2CCIP2R_USART16SEL_VALUE(3U) +#define STM32_USART16SEL_CSI_KER_CK RCC_D2CCIP2R_USART16SEL_VALUE(4U) +#define STM32_USART16SEL_LSE_CK RCC_D2CCIP2R_USART16SEL_VALUE(5U) +#else +#define STM32_USART16910SEL_PCLK2 RCC_D2CCIP2R_USART16910SEL_VALUE(0U) +#define STM32_USART16910SEL_PLL2_Q_CK RCC_D2CCIP2R_USART16910SEL_VALUE(1U) +#define STM32_USART16910SEL_PLL3_Q_CK RCC_D2CCIP2R_USART16910SEL_VALUE(2U) +#define STM32_USART16910SEL_HSI_KER_CK RCC_D2CCIP2R_USART16910SEL_VALUE(3U) +#define STM32_USART16910SEL_CSI_KER_CK RCC_D2CCIP2R_USART16910SEL_VALUE(4U) +#define STM32_USART16910SEL_LSE_CK RCC_D2CCIP2R_USART16910SEL_VALUE(5U) +#endif + +#define STM32_USART234578SEL_PCLK1 RCC_D2CCIP2R_USART234578SEL_VALUE(0U) +#define STM32_USART234578SEL_PLL2_Q_CK RCC_D2CCIP2R_USART234578SEL_VALUE(1U) +#define STM32_USART234578SEL_PLL3_Q_CK RCC_D2CCIP2R_USART234578SEL_VALUE(2U) +#define STM32_USART234578SEL_HSI_KER_CK RCC_D2CCIP2R_USART234578SEL_VALUE(3U) +#define STM32_USART234578SEL_CSI_KER_CK RCC_D2CCIP2R_USART234578SEL_VALUE(4U) +#define STM32_USART234578SEL_LSE_CK RCC_D2CCIP2R_USART234578SEL_VALUE(5U) + +#define STM32_SPI6SEL_PCLK4 RCC_D3CCIPR_SPI6SEL_VALUE(0U) +#define STM32_SPI6SEL_PLL2_Q_CK RCC_D3CCIPR_SPI6SEL_VALUE(1U) +#define STM32_SPI6SEL_PLL3_Q_CK RCC_D3CCIPR_SPI6SEL_VALUE(2U) +#define STM32_SPI6SEL_HSI_KER_CK RCC_D3CCIPR_SPI6SEL_VALUE(3U) +#define STM32_SPI6SEL_CSI_KER_CK RCC_D3CCIPR_SPI6SEL_VALUE(4U) +#define STM32_SPI6SEL_HSE_CK RCC_D3CCIPR_SPI6SEL_VALUE(5U) + +#define STM32_SAI4BSEL_PLL1_Q_CK RCC_D3CCIPR_SAI4BSEL_VALUE(0U) +#define STM32_SAI4BSEL_PLL2_P_CK RCC_D3CCIPR_SAI4BSEL_VALUE(1U) +#define STM32_SAI4BSEL_PLL3_P_CK RCC_D3CCIPR_SAI4BSEL_VALUE(2U) +#define STM32_SAI4BSEL_I2S_CKIN RCC_D3CCIPR_SAI4BSEL_VALUE(3U) +#define STM32_SAI4BSEL_PER_CK RCC_D3CCIPR_SAI4BSEL_VALUE(4U) + +#define STM32_SAI4ASEL_PLL1_Q_CK RCC_D3CCIPR_SAI4ASEL_VALUE(0U) +#define STM32_SAI4ASEL_PLL2_P_CK RCC_D3CCIPR_SAI4ASEL_VALUE(1U) +#define STM32_SAI4ASEL_PLL3_P_CK RCC_D3CCIPR_SAI4ASEL_VALUE(2U) +#define STM32_SAI4ASEL_I2S_CKIN RCC_D3CCIPR_SAI4ASEL_VALUE(3U) +#define STM32_SAI4ASEL_PER_CK RCC_D3CCIPR_SAI4ASEL_VALUE(4U) + +#define STM32_ADCSEL_PLL2_P_CK RCC_D3CCIPR_ADCSEL_VALUE(0U) +#define STM32_ADCSEL_PLL3_R_CK RCC_D3CCIPR_ADCSEL_VALUE(1U) +#define STM32_ADCSEL_PER_CK RCC_D3CCIPR_ADCSEL_VALUE(2U) +#define STM32_ADCSEL_DISABLE RCC_D3CCIPR_ADCSEL_VALUE(3U) + +#define STM32_LPTIM345SEL_PCLK4 RCC_D3CCIPR_LPTIM345SEL_VALUE(0U) +#define STM32_LPTIM345SEL_PLL2_P_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(1U) +#define STM32_LPTIM345SEL_PLL3_P_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(2U) +#define STM32_LPTIM345SEL_LSE_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(3U) +#define STM32_LPTIM345SEL_LSI_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(4U) +#define STM32_LPTIM345SEL_PER_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(5U) + +#define STM32_LPTIM2SEL_PCLK4 RCC_D3CCIPR_LPTIM2SEL_VALUE(0U) +#define STM32_LPTIM2SEL_PLL2_P_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(1U) +#define STM32_LPTIM2SEL_PLL3_P_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(2U) +#define STM32_LPTIM2SEL_LSE_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(3U) +#define STM32_LPTIM2SEL_LSI_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(4U) +#define STM32_LPTIM2SEL_PER_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(5U) + +#define STM32_I2C4SEL_PCLK4 RCC_D3CCIPR_I2C4SEL_VALUE(0U) +#define STM32_I2C4SEL_PLL3_R_CK RCC_D3CCIPR_I2C4SEL_VALUE(1U) +#define STM32_I2C4SEL_HSI_KER_CK RCC_D3CCIPR_I2C4SEL_VALUE(2U) +#define STM32_I2C4SEL_CSI_KER_CK RCC_D3CCIPR_I2C4SEL_VALUE(3U) + +#define STM32_LPUART1SEL_PCLK4 RCC_D3CCIPR_LPUART1SEL_VALUE(0U) +#define STM32_LPUART1SEL_PLL2_Q_CK RCC_D3CCIPR_LPUART1SEL_VALUE(1U) +#define STM32_LPUART1SEL_PLL3_Q_CK RCC_D3CCIPR_LPUART1SEL_VALUE(2U) +#define STM32_LPUART1SEL_HSI_KER_CK RCC_D3CCIPR_LPUART1SEL_VALUE(3U) +#define STM32_LPUART1SEL_CSI_KER_CK RCC_D3CCIPR_LPUART1SEL_VALUE(4U) +#define STM32_LPUART1SEL_LSE_CK RCC_D3CCIPR_LPUART1SEL_VALUE(5U) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief Disables the PWR/RCC initialization in the HAL. + * @note All the clock tree constants are calculated but the initialization + * is not performed. + */ +#if !defined(STM32_NO_INIT) || defined(__DOXYGEN__) +#define STM32_NO_INIT FALSE +#endif + +/** + * @brief Target code for this HAL configuration. + * @note Core 1 is the Cortex-M7, core 2 is the Cortex-M4. + */ +#if !defined(STM32_TARGET_CORE) || defined(__DOXYGEN__) +#define STM32_TARGET_CORE 1 +#endif + +/** + * @brief MPU region to be used for no-cache RAM area. + */ +#if !defined(STM32_NOCACHE_MPU_REGION) || defined(__DOXYGEN__) +#define STM32_NOCACHE_MPU_REGION MPU_REGION_6 +#endif + +/** + * @brief Add no-cache attribute to SRAM1 and SRAM2. + * @note MPU region 7 is used if enabled. + */ +#if !defined(STM32_NOCACHE_SRAM1_SRAM2) || defined(__DOXYGEN__) +#define STM32_NOCACHE_SRAM1_SRAM2 FALSE +#endif + +/** + * @brief Add no-cache attribute to SRAM3. + * @note MPU region 7 is used if enabled. + */ +#if !defined(STM32_NOCACHE_SRAM3) || defined(__DOXYGEN__) +#define STM32_NOCACHE_SRAM3 TRUE +#endif + +/** + * @brief PWR CR1 initializer. + */ +#if !defined(STM32_PWR_CR1) || defined(__DOXYGEN__) +#define STM32_PWR_CR1 (PWR_CR1_SVOS_1 | \ + PWR_CR1_SVOS_0) +#endif + +/** + * @brief PWR CR2 initializer. + */ +#if !defined(STM32_PWR_CR2) || defined(__DOXYGEN__) +#define STM32_PWR_CR2 (PWR_CR2_BREN) +#endif + +/** + * @brief PWR CR3 initializer. + */ +#if !defined(STM32_PWR_CR3) || defined(__DOXYGEN__) +#define STM32_PWR_CR3 (PWR_CR3_LDOEN | \ + PWR_CR3_USBREGEN | \ + PWR_CR3_USB33DEN) +#endif + +/** + * @brief PWR CPUCR initializer. + */ +#if !defined(STM32_PWR_CPUCR) || defined(__DOXYGEN__) +#define STM32_PWR_CPUCR 0 +#endif + +/** + * @brief VOS setting. + */ +#if !defined(STM32_VOS) || defined(__DOXYGEN__) +#define STM32_VOS STM32_VOS_SCALE1 +#endif + +/** + * @brief Enables or disables the HSI clock source. + */ +#if !defined(STM32_HSI_ENABLED) || defined(__DOXYGEN__) +#define STM32_HSI_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the LSI clock source. + */ +#if !defined(STM32_LSI_ENABLED) || defined(__DOXYGEN__) +#define STM32_LSI_ENABLED FALSE +#endif + +/** + * @brief Enables or disables the LSI clock source. + */ +#if !defined(STM32_CSI_ENABLED) || defined(__DOXYGEN__) +#define STM32_CSI_ENABLED FALSE +#endif + +/** + * @brief Enables or disables the HSI48 clock source. + */ +#if !defined(STM32_HSI48_ENABLED) || defined(__DOXYGEN__) +#define STM32_HSI48_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the HSE clock source. + */ +#if !defined(STM32_HSE_ENABLED) || defined(__DOXYGEN__) +#define STM32_HSE_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the LSE clock source. + */ +#if !defined(STM32_LSE_ENABLED) || defined(__DOXYGEN__) +#define STM32_LSE_ENABLED TRUE +#endif + +/** + * @brief HSI divider. + */ +#if !defined(STM32_HSIDIV) || defined(__DOXYGEN__) +#define STM32_HSIDIV STM32_HSIDIV_DIV1 +#endif + +/** + * @brief Clock source for all PLLs. + */ +#if !defined(STM32_PLLSRC) || defined(__DOXYGEN__) +#define STM32_PLLSRC STM32_PLLSRC_HSE_CK +#endif + +/** + * @brief Masking of PLLCFGR register. + * @note By default all options in PLLCFGR are enabled, this option + * allows to mask specific bits for power saving reasons. + * Use with caution. + */ +#if !defined(STM32_PLLCFGR_MASK) || defined(__DOXYGEN__) +#define STM32_PLLCFGR_MASK ~0 +#endif + +/** + * @brief Enables or disables the PLL1. + */ +#if !defined(STM32_PLL1_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL1_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the PLL1 P output. + */ +#if !defined(STM32_PLL1_P_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL1_P_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the PLL1 Q output. + */ +#if !defined(STM32_PLL1_Q_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL1_Q_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the PLL1 R output. + */ +#if !defined(STM32_PLL1_R_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL1_R_ENABLED TRUE +#endif + +/** + * @brief PLL1 DIVM divider. + * @note The allowed values are 1..63. + */ +#if !defined(STM32_PLL1_DIVM_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL1_DIVM_VALUE 4 +#endif + +/** + * @brief PLL1 DIVN multiplier. + * @note The allowed values are 4..512. + */ +#if !defined(STM32_PLL1_DIVN_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL1_DIVN_VALUE 400 +#endif + +/** + * @brief PLL1 FRACN multiplier, zero if no fractional part. + * @note The allowed values are 0..8191. + */ +#if !defined(STM32_PLL1_FRACN_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL1_FRACN_VALUE 0 +#endif + +/** + * @brief PLL1 DIVP divider. + * @note The allowed values are 2..128, odd values not allowed. + */ +#if !defined(STM32_PLL1_DIVP_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL1_DIVP_VALUE 2 +#endif + +/** + * @brief PLL1 DIVQ divider. + * @note The allowed values are 1..128. + */ +#if !defined(STM32_PLL1_DIVQ_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL1_DIVQ_VALUE 8 +#endif + +/** + * @brief PLL1 DIVR divider. + * @note The allowed values are 1..128. + */ +#if !defined(STM32_PLL1_DIVR_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL1_DIVR_VALUE 8 +#endif + +/** + * @brief Enables or disables the PLL2. + */ +#if !defined(STM32_PLL2_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL2_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the PLL2 P output. + */ +#if !defined(STM32_PLL2_P_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL1_2_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the PLL2 Q output. + */ +#if !defined(STM32_PLL2_Q_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL2_Q_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the PLL2 R output. + */ +#if !defined(STM32_PLL2_R_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL2_R_ENABLED TRUE +#endif + +/** + * @brief PLL2 DIVM divider. + * @note The allowed values are 1..63. + */ +#if !defined(STM32_PLL2_DIVM_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL2_DIVM_VALUE 4 +#endif + +/** + * @brief PLL2 DIVN multiplier. + * @note The allowed values are 4..512. + */ +#if !defined(STM32_PLL2_DIVN_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL2_DIVN_VALUE 400 +#endif + +/** + * @brief PLL2 FRACN multiplier, zero if no fractional part. + * @note The allowed values are 0..8191. + */ +#if !defined(STM32_PLL2_FRACN_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL2_FRACN_VALUE 0 +#endif + +/** + * @brief PLL2 DIVP divider. + * @note The allowed values are 2..128, odd values not allowed. + */ +#if !defined(STM32_PLL2_DIVP_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL2_DIVP_VALUE 40 +#endif + +/** + * @brief PLL2 DIVQ divider. + * @note The allowed values are 1..128. + */ +#if !defined(STM32_PLL2_DIVQ_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL2_DIVQ_VALUE 8 +#endif + +/** + * @brief PLL2 DIVR divider. + * @note The allowed values are 1..128. + */ +#if !defined(STM32_PLL2_DIVR_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL2_DIVR_VALUE 8 +#endif + +/** + * @brief Enables or disables the PLL3. + */ +#if !defined(STM32_PLL3_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL3_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the PLL3 P output. + */ +#if !defined(STM32_PLL3_P_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL3_P_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the PLL3 Q output. + */ +#if !defined(STM32_PLL3_Q_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL3_Q_ENABLED TRUE +#endif + +/** + * @brief Enables or disables the PLL3 R output. + */ +#if !defined(STM32_PLL3_R_ENABLED) || defined(__DOXYGEN__) +#define STM32_PLL3_R_ENABLED TRUE +#endif + +/** + * @brief PLL3 DIVM divider. + * @note The allowed values are 1..63. + */ +#if !defined(STM32_PLL3_DIVM_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL3_DIVM_VALUE 4 +#endif + +/** + * @brief PLL3 DIVN multiplier. + * @note The allowed values are 4..512. + */ +#if !defined(STM32_PLL3_DIVN_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL3_DIVN_VALUE 400 +#endif + +/** + * @brief PLL3 FRACN multiplier, zero if no fractional part. + * @note The allowed values are 0..8191. + */ +#if !defined(STM32_PLL3_FRACN_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL3_FRACN_VALUE 0 +#endif + +/** + * @brief PLL3 DIVP divider. + * @note The allowed values are 2..128, odd values not allowed. + */ +#if !defined(STM32_PLL3_DIVP_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL3_DIVP_VALUE 8 +#endif + +/** + * @brief PLL3 DIVQ divider. + * @note The allowed values are 1..128. + */ +#if !defined(STM32_PLL3_DIVQ_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL3_DIVQ_VALUE 8 +#endif + +/** + * @brief PLL3 DIVR divider. + * @note The allowed values are 1..128. + */ +#if !defined(STM32_PLL3_DIVR_VALUE) || defined(__DOXYGEN__) +#define STM32_PLL3_DIVR_VALUE 8 +#endif + +/** + * @brief Peripherals clock selector. + */ +#if !defined(STM32_CKPERSEL) || defined(__DOXYGEN__) +#define STM32_CKPERSEL STM32_CKPERSEL_HSE_CK +#endif + +/** + * @brief MCO1 clock selector. + */ +#if !defined(STM32_MCO1SEL) || defined(__DOXYGEN__) +#define STM32_MCO1SEL STM32_MCO1SEL_HSI_CK +#endif + +/** + * @brief MCO1 clock prescaler. + */ +#if !defined(STM32_MCO1PRE_VALUE) || defined(__DOXYGEN__) +#define STM32_MCO1PRE_VALUE 4 +#endif + +/** + * @brief MCO2 clock selector. + */ +#if !defined(STM32_MCO2SEL) || defined(__DOXYGEN__) +#define STM32_MCO2SEL STM32_MCO2SEL_SYS_CK +#endif + +/** + * @brief MCO2 clock prescaler. + */ +#if !defined(STM32_MCO2PRE_VALUE) || defined(__DOXYGEN__) +#define STM32_MCO2PRE_VALUE 4 +#endif + +/** + * @brief TIM clock prescaler selection. + */ +#if !defined(STM32_TIMPRE_ENABLE) || defined(__DOXYGEN__) +#define STM32_TIMPRE_ENABLE FALSE +#endif + +/** + * @brief HRTIM clock prescaler selection. + */ +#if !defined(STM32_HRTIMSEL) || defined(__DOXYGEN__) +#define STM32_HRTIMSEL 0 +#endif + +/** + * @brief Kernel clock selection after a wake up from system Stop. + */ +#if !defined(STM32_STOPKERWUCK) || defined(__DOXYGEN__) +#define STM32_STOPKERWUCK 0 +#endif + +/** + * @brief System clock selection after a wake up from system Stop. + */ +#if !defined(STM32_STOPWUCK) || defined(__DOXYGEN__) +#define STM32_STOPWUCK 0 +#endif + +/** + * @brief RTC HSE prescaler value. + * @note The allowed values are 2..63. + */ +#if !defined(STM32_RTCPRE_VALUE) || defined(__DOXYGEN__) +#define STM32_RTCPRE_VALUE 8 +#endif + +/** + * @brief Main clock source selection. + * @note This setting can be modified at runtime. + */ +#if !defined(STM32_SW) || defined(__DOXYGEN__) +#define STM32_SW STM32_SW_PLL1_P_CK1_P_CK +#endif + +/** + * @brief RTC clock selector. + * @note This setting can be modified at runtime. + */ +#if !defined(STM32_RTCSEL) || defined(__DOXYGEN__) +#define STM32_RTCSEL STM32_RTCSEL_LSE_CK +#endif + +/** + * @brief Clock domain 1 core bus prescaler. + * @note This setting can be modified at runtime. + */ +#if !defined(STM32_D1CPRE) || defined(__DOXYGEN__) +#define STM32_D1CPRE STM32_D1CPRE_DIV1 +#endif + +/** + * @brief Clock domain 1 HPRE prescaler. + * @note This setting can be modified at runtime. + */ +#if !defined(STM32_D1HPRE) || defined(__DOXYGEN__) +#define STM32_D1HPRE STM32_D1HPRE_DIV4 +#endif + +/** + * @brief Clock domain 1 peripherals bus prescaler. + * @note This setting can be modified at runtime. + */ +#if !defined(STM32_D1PPRE3) || defined(__DOXYGEN__) +#define STM32_D1PPRE3 STM32_D1PPRE3_DIV1 +#endif + +/** + * @brief Clock domain 2 peripherals bus 1 prescaler. + * @note This setting can be modified at runtime. + */ +#if !defined(STM32_D2PPRE1) || defined(__DOXYGEN__) +#define STM32_D2PPRE1 STM32_D2PPRE1_DIV1 +#endif + +/** + * @brief Clock domain 2 peripherals bus 2 prescaler. + * @note This setting can be modified at runtime. + */ +#if !defined(STM32_D2PPRE2) || defined(__DOXYGEN__) +#define STM32_D2PPRE2 STM32_D2PPRE2_DIV1 +#endif + +/** + * @brief Clock domain 3 peripherals bus prescaler. + * @note This setting can be modified at runtime. + */ +#if !defined(STM32_D3PPRE4) || defined(__DOXYGEN__) +#define STM32_D3PPRE4 STM32_D3PPRE4_DIV1 +#endif + +/** + * @brief SDMMC clock source. + */ +#if !defined(STM32_SDMMCSEL) || defined(__DOXYGEN__) +#define STM32_SDMMCSEL STM32_SDMMCSEL_PLL1_Q_CK +#endif + +/** + * @brief QSPI clock source. + */ +#if !defined(STM32H723xx) && (!defined(STM32_QSPISEL) || defined(__DOXYGEN__)) +#define STM32_QSPISEL STM32_QSPISEL_HCLK +#endif + +/** + * @brief FMC clock source. + */ +#if !defined(STM32H723xx) && (!defined(STM32_FMCSEL) || defined(__DOXYGEN__)) +#define STM32_FMCSEL STM32_QSPISEL_HCLK +#endif + +/** + * @brief SWP clock source. + */ +#if !defined(STM32_SWPSEL) || defined(__DOXYGEN__) +#define STM32_SWPSEL STM32_SWPSEL_PCLK1 +#endif + +/** + * @brief FDCAN clock source. + */ +#if !defined(STM32_FDCANSEL) || defined(__DOXYGEN__) +#define STM32_FDCANSEL STM32_FDCANSEL_HSE_CK +#endif + +/** + * @brief DFSDM1 clock source. + */ +#if !defined(STM32_DFSDM1SEL) || defined(__DOXYGEN__) +#define STM32_DFSDM1SEL STM32_DFSDM1SEL_PCLK2 +#endif + +/** + * @brief SPDIF clock source. + */ +#if !defined(STM32_SPDIFSEL) || defined(__DOXYGEN__) +#define STM32_SPDIFSEL STM32_SPDIFSEL_PLL1_Q_CK +#endif + +/** + * @brief SPI45 clock source. + */ +#if !defined(STM32_SPI45SEL) || defined(__DOXYGEN__) +#define STM32_SPI45SEL STM32_SPI45SEL_PCLK2 +#endif + +/** + * @brief SPI123 clock source. + */ +#if !defined(STM32_SPI123SEL) || defined(__DOXYGEN__) +#define STM32_SPI123SEL STM32_SPI123SEL_PLL1_Q_CK +#endif + +/** + * @brief SAI23 clock source. + */ +#if !defined(STM32H723xx) && (!defined(STM32_SAI23SEL) || defined(__DOXYGEN__)) +#define STM32_SAI23SEL STM32_SAI23SEL_PLL1_Q_CK +#endif + +/** + * @brief SAI1 clock source. + */ +#if !defined(STM32_SAI1SEL) || defined(__DOXYGEN__) +#define STM32_SAI1SEL STM32_SAI1SEL_PLL1_Q_CK +#endif + +/** + * @brief LPTIM1 clock source. + */ +#if !defined(STM32_LPTIM1SEL) || defined(__DOXYGEN__) +#define STM32_LPTIM1SEL STM32_LPTIM1_PCLK1 +#endif + +/** + * @brief CEC clock source. + */ +#if !defined(STM32_CECSEL) || defined(__DOXYGEN__) +#define STM32_CECSEL STM32_CECSEL_LSE_CK +#endif + +/** + * @brief USB clock source. + */ +#if !defined(STM32_USBSEL) || defined(__DOXYGEN__) +#define STM32_USBSEL STM32_USBSEL_PLL3_Q_CK +#endif + +#if !defined(STM32H723xx) + +/** + * @brief I2C123 clock source. + */ +#if !defined(STM32_I2C123SEL) || defined(__DOXYGEN__) +#define STM32_I2C123SEL STM32_I2C123SEL_PCLK1 +#endif + +#else // below for defined(STM32H723xx) + +#if !defined(STM32_I2C1235SEL) || defined(__DOXYGEN__) +#define STM32_I2C1235SEL STM32_I2C1235SEL_PCLK1 +#endif + +#endif // defined(STM32H723xx) + +/** + * @brief RNG clock source. + */ +#if !defined(STM32_RNGSEL) || defined(__DOXYGEN__) +#define STM32_RNGSEL STM32_RNGSEL_HSI48_CK +#endif + +#if !defined(STM32H723xx) +/** + * @brief USART16 clock source. + */ +#if !defined(STM32_USART16SEL) || defined(__DOXYGEN__) +#define STM32_USART16SEL STM32_USART16SEL_PCLK2 +#endif +#else +/** + * @brief USART16910 clock source. + */ +#if !defined(STM32_USART16910SEL) || defined(__DOXYGEN__) +#define STM32_USART16910SEL STM32_USART16910SEL_PCLK2 +#endif +#endif // !defined(STM32H723xx) + +/** + * @brief USART234578 clock source. + */ +#if !defined(STM32_USART234578SEL) || defined(__DOXYGEN__) +#define STM32_USART234578SEL STM32_USART234578SEL_PCLK1 +#endif + +/** + * @brief SPI6SEL clock source. + */ +#if !defined(STM32_SPI6SEL) || defined(__DOXYGEN__) +#define STM32_SPI6SEL STM32_SPI6SEL_PCLK4 +#endif + +/** + * @brief SAI4BSEL clock source. + */ +#if !defined(STM32_SAI4BSEL) || defined(__DOXYGEN__) +#define STM32_SAI4BSEL STM32_SAI4BSEL_PLL1_Q_CK +#endif + +/** + * @brief SAI4ASEL clock source. + */ +#if !defined(STM32_SAI4ASEL) || defined(__DOXYGEN__) +#define STM32_SAI4ASEL STM32_SAI4ASEL_PLL1_Q_CK +#endif + +/** + * @brief ADCSEL clock source. + */ +#if !defined(STM32_ADCSEL) || defined(__DOXYGEN__) +#define STM32_ADCSEL STM32_ADCSEL_PLL2_P_CK +#endif + +/** + * @brief LPTIM345SEL clock source. + */ +#if !defined(STM32_LPTIM345SEL) || defined(__DOXYGEN__) +#define STM32_LPTIM345SEL STM32_LPTIM345SEL_PCLK4 +#endif + +/** + * @brief LPTIM2SEL clock source. + */ +#if !defined(STM32_LPTIM2SEL) || defined(__DOXYGEN__) +#define STM32_LPTIM2SEL STM32_LPTIM2SEL_PCLK4 +#endif + +/** + * @brief I2C4SEL clock source. + */ +#if !defined(STM32_I2C4SEL) || defined(__DOXYGEN__) +#define STM32_I2C4SEL STM32_I2C4SEL_PCLK4 +#endif + +/** + * @brief LPUART1SEL clock source. + */ +#if !defined(STM32_LPUART1SEL) || defined(__DOXYGEN__) +#define STM32_LPUART1SEL STM32_LPUART1SEL_PCLK4 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* + * Configuration-related checks. + */ +#if !defined(STM32H7xx_MCUCONF) +#error "Using a wrong mcuconf.h file, STM32H7xx_MCUCONF not defined" +#endif + +#if defined(STM32H750xx)&& !defined(STM32H750_MCUCONF) +#error "Using a wrong mcuconf.h file, STM32H750_MCUCONF not defined" +#endif + +#if defined(STM32H742xx)&& !defined(STM32H742_MCUCONF) +#error "Using a wrong mcuconf.h file, STM32H742_MCUCONF not defined" +#endif + +#if defined(STM32H743xx)&& !defined(STM32H743_MCUCONF) +#error "Using a wrong mcuconf.h file, STM32H743_MCUCONF not defined" +#endif + +#if defined(STM32H753xx)&& !defined(STM32H753_MCUCONF) +#error "Using a wrong mcuconf.h file, STM32H753_MCUCONF not defined" +#endif + +#if defined(STM32H745xx)&& !defined(STM32H745_MCUCONF) +#error "Using a wrong mcuconf.h file, STM32H745_MCUCONF not defined" +#endif + +#if defined(STM32H755xx)&& !defined(STM32H755_MCUCONF) +#error "Using a wrong mcuconf.h file, STM32H755_MCUCONF not defined" +#endif + +#if defined(STM32H747xx)&& !defined(STM32H747_MCUCONF) +#error "Using a wrong mcuconf.h file, STM32H747_MCUCONF not defined" +#endif + +#if defined(STM32H757xx)&& !defined(STM32H757_MCUCONF) +#error "Using a wrong mcuconf.h file, STM32H757_MCUCONF not defined" +#endif + +/* + * Board file checks. + */ +#if !defined(STM32_LSECLK) +#error "STM32_LSECLK not defined in board.h" +#endif +#if !defined(STM32_LSEDRV) +#error "STM32_LSEDRV not defined in board.h" +#endif +#if !defined(STM32_HSECLK) +#error "STM32_HSECLK not defined in board.h" +#endif + +/** + * @name Constants depending on VOS and ODEN setting + * @{ + */ +#if STM32_VOS == STM32_VOS_SCALE1 +#define STM32_0WS_THRESHOLD 70000000U +#define STM32_1WS_THRESHOLD 140000000U +#define STM32_2WS_THRESHOLD 210000000U +#define STM32_3WS_THRESHOLD 225000000U +#define STM32_4WS_THRESHOLD 240000000U +#define STM32_PLLOUT_MAX 480000000U +#define STM32_PLLOUT_MIN 1500000U + +#elif STM32_VOS == STM32_VOS_SCALE2 +#define STM32_0WS_THRESHOLD 55000000U +#define STM32_1WS_THRESHOLD 110000000U +#define STM32_2WS_THRESHOLD 165000000U +#define STM32_3WS_THRESHOLD 225000000U +#define STM32_4WS_THRESHOLD 0U +#define STM32_PLLOUT_MAX 300000000U +#define STM32_PLLOUT_MIN 1500000U + +#elif STM32_VOS == STM32_VOS_SCALE3 +#define STM32_0WS_THRESHOLD 45000000U +#define STM32_1WS_THRESHOLD 90000000U +#define STM32_2WS_THRESHOLD 135000000U +#define STM32_3WS_THRESHOLD 180000000U +#define STM32_4WS_THRESHOLD 225000000U +#define STM32_PLLOUT_MAX 200000000U +#define STM32_PLLOUT_MIN 1500000U + +#else +#error "invalid STM32_VOS setting specified" +#endif +/** @} */ + +/* + * HSI related checks. + */ +#if STM32_HSI_ENABLED +#define STM32_HSICLK STM32_HSI_OSC + +#else /* !STM32_HSI_ENABLED */ +#define STM32_HSICLK 0U + +#if STM32_SW == STM32_SW_HSI_CK +#error "HSI not enabled, required by STM32_SW" +#endif + +#if (STM32_PLLSRC == STM32_PLLSRC_HSI_CK) && \ + (STM32_PLL1_ENABLED || STM32_PLL2_ENABLED || STM32_PLL3_ENABLED) +#error "HSI not enabled, required by STM32_PLLSRC and STM32_PLLx_ENABLED" +#endif + +#if STM32_CKPERSEL == STM32_CKPERSEL_HSI_CK +#error "HSI not enabled, required by STM32_CKPERSEL" +#endif + +#if STM32_MCO1SEL == STM32_MCO1SEL_HSI_CK +#error "HSI not enabled, required by STM32_MCO1SEL" +#endif + +#endif /* !STM32_HSI_ENABLED */ + +/* + * HSI48 related checks. + */ +#if STM32_HSI48_ENABLED +#define STM32_HSI48_CK STM32_HSI48_OSC + +#else /* !STM32_HSI48_ENABLED */ +#define STM32_HSI48_CK 0U + +#if STM32_MCO1SEL == STM32_MCO1SEL_HSI48_CK +#error "HSI48 not enabled, required by STM32_MCO1SEL" +#endif + +#endif /* !STM32_HSI48_ENABLED */ + +/* + * CSI related checks. + */ +#if STM32_CSI_ENABLED +#define STM32_CSI_CK STM32_CSI_OSC + +#else /* !STM32_CSI_ENABLED */ +#define STM32_CSI_CK 0U + +#if STM32_SW == STM32_SW_CSI_CK +#error "CSI not enabled, required by STM32_SW" +#endif + +#if (STM32_PLLSRC == STM32_PLLSRC_CSI_CK) && \ + (STM32_PLL1_ENABLED || STM32_PLL2_ENABLED || STM32_PLL3_ENABLED) +#error "CSI not enabled, required by STM32_PLLSRC and STM32_PLLx_ENABLED" +#endif + +#if STM32_CKPERSEL == STM32_CKPERSEL_CSI_CK +#error "CSI not enabled, required by STM32_CKPERSEL" +#endif + +#if STM32_MCO2SEL == STM32_MCO2SEL_CSI_CK +#error "CSI not enabled, required by STM32_MCO2SEL" +#endif + +#endif /* !STM32_CSI_ENABLED */ + +/* + * HSE related checks. + */ +#if STM32_HSE_ENABLED + +#if !defined(STM32_HSECLK) +#error "HSE frequency not defined" +#endif + +#define STM32_HSE_CK STM32_HSECLK + +#if STM32_HSECLK == 0 +#error "HSE oscllator not available" +#else /* STM32_HSECLK != 0 */ +#if defined(STM32_HSE_BYPASS) +#if (STM32_HSECLK < STM32_HSECLK_BYP_MIN) || (STM32_HSECLK > STM32_HSECLK_BYP_MAX) +#error "STM32_HSECLK outside acceptable range (STM32_HSECLK_BYP_MIN..STM32_HSECLK_BYP_MAX)" +#endif +#else /* !defined(STM32_HSE_BYPASS) */ +#if (STM32_HSECLK < STM32_HSECLK_MIN) || (STM32_HSECLK > STM32_HSECLK_MAX) +#error "STM32_HSECLK outside acceptable range (STM32_HSECLK_MIN..STM32_HSECLK_MAX)" +#endif +#endif /* !defined(STM32_HSE_BYPASS) */ +#endif /* STM32_HSECLK != 0 */ +#else /* !STM32_HSE_ENABLED */ + +#if STM32_SW == STM32_SW_HSE_CK +#error "HSE not enabled, required by STM32_SW" +#endif + +#if (STM32_PLLSRC == STM32_PLLSRC_HSE_CK) && \ + (STM32_PLL1_ENABLED || STM32_PLL2_ENABLED || STM32_PLL3_ENABLED) +#error "HSE not enabled, required by STM32_PLLSRC and STM32_PLLx_ENABLED" +#endif + +#if STM32_MCO1SEL == STM32_MCO1SEL_HSE_CK +#error "HSE not enabled, required by STM32_MCO1SEL" +#endif + +#if STM32_MCO2SEL == STM32_MCO2SEL_HSE_CK +#error "HSE not enabled, required by STM32_MCO2SEL" +#endif + +#if STM32_RTCSEL == STM32_RTCSEL_HSE_1M_CK +#error "HSE not enabled, required by STM32_RTCSEL" +#endif + +#endif /* !STM32_HSE_ENABLED */ + +/* + * LSI related checks. + */ +#if STM32_LSI_ENABLED +#define STM32_LSI_CK STM32_LSI_OSC + +#else /* !STM32_LSI_ENABLED */ +#define STM32_LSI_CK 0U + +#if STM32_RTCSEL == STM32_RTCSEL_LSI_CK +#error "LSI not enabled, required by STM32_RTCSEL" +#endif + +#if STM32_MCO2SEL == STM32_MCO2SEL_LSI_CK +#error "HSE not enabled, required by STM32_MCO2SEL" +#endif + +#endif /* !STM32_LSI_ENABLED */ + +/* + * LSE related checks. + */ +#if STM32_LSE_ENABLED + +#if !defined(STM32_LSECLK) +#error "LSE frequency not defined" +#endif + +#define STM32_LSE_CK STM32_LSECLK + +#if (STM32_LSE_CK == 0) +#error "LSE oscillator not available" +#endif + +#if defined(STM32_LSE_BYPASS) +#if (STM32_LSE_CK < STM32_LSE_CK_MIN) || (STM32_LSE_CK > STM32_LSE_CK_BYP_MAX) +#error "STM32_LSE_CK outside acceptable range (STM32_LSE_CK_MIN..STM32_LSE_CK_BYP_MAX)" +#endif +#else +#if (STM32_LSE_CK < STM32_LSE_CK_MIN) || (STM32_LSE_CK > STM32_LSE_CK_MAX) +#error "STM32_LSE_CK outside acceptable range (STM32_LSE_CK_MIN..STM32_LSE_CK_MAX)" +#endif +#endif + +#if !defined(STM32_LSEDRV) +#error "STM32_LSEDRV not defined" +#endif + +#if (STM32_LSEDRV >> 3) > 3 +#error "STM32_LSEDRV outside acceptable range ((0<<3)..(3<<3))" +#endif + +#else /* !STM32_LSE_ENABLED */ + +#if STM32_RTCSEL == STM32_RTCSEL_LSE_CK +#error "LSE not enabled, required by STM32_RTCSEL" +#endif + +#if STM32_MCO1SEL == STM32_MCO1SEL_LSE_CK +#error "LSE not enabled, required by STM32_MCO1SEL" +#endif + +#endif /* !STM32_LSE_ENABLED */ + +/** + * @brief HSI divided clock. + */ +#if (STM32_HSIDIV == STM32_HSIDIV_DIV1) || defined(__DOXYGEN__) +#define STM32_HSI_CK (STM32_HSICLK / 1U) +#elif STM32_HSIDIV == STM32_HSIDIV_DIV2 +#define STM32_HSI_CK (STM32_HSICLK / 2U) +#elif STM32_HSIDIV == STM32_HSIDIV_DIV4 +#define STM32_HSI_CK (STM32_HSICLK / 4U) +#elif STM32_HSIDIV == STM32_HSIDIV_DIV8 +#define STM32_HSI_CK (STM32_HSICLK / 8U) +#else +#error "invalid STM32_HSIDIV value specified" +#endif + +/** + * @brief HSE divided clock for RTC. + */ +#if ((STM32_RTCPRE_VALUE >= 2) && (STM32_RTCPRE_VALUE <= 63)) || \ + defined(__DOXYGEN__) +#define STM32_HSE_1M_CK (STM32_HSE_CK / STM32_RTCPRE_VALUE) +#else +#error "invalid STM32_RTCPRE_VALUE value specified" +#endif + +/** + * @brief PLLs input clock frequency. + */ +#if (STM32_PLLSRC == STM32_PLLSRC_HSE_CK) || defined(__DOXYGEN__) +#define STM32_PLLCLKIN STM32_HSE_CK + +#elif STM32_PLLSRC == STM32_PLLSRC_HSI_CK +#define STM32_PLLCLKIN STM32_HSI_CK + +#elif STM32_PLLSRC == STM32_PLLSRC_CSI_CK +#define STM32_PLLCLKIN STM32_CSI_CK + +#elif STM32_PLLSRC == STM32_PLLSRC_DISABLE + +#else +#error "invalid STM32_PLLSRC value specified" +#endif + +#if STM32_PLLSRC != STM32_PLLSRC_DISABLE + +/** + * @brief PLL1 DIVM field. + */ +#if ((STM32_PLL1_DIVM_VALUE >= 1) && (STM32_PLL1_DIVM_VALUE <= 63)) || \ + defined(__DOXYGEN__) +#define STM32_PLL1_DIVM (STM32_PLL1_DIVM_VALUE << 4) +#define STM32_PLL1_REF_CK (STM32_PLLCLKIN / STM32_PLL1_DIVM_VALUE) +#else +#error "invalid STM32_PLL1_DIVM_VALUE value specified" +#endif + +/* + * PLL1 input frequency range check. + */ +#if (STM32_PLL1_REF_CK < STM32_PLLIN_MIN) || (STM32_PLL1_REF_CK > STM32_PLLIN_MAX) +#error "STM32_PLL1_REF_CK outside acceptable range (STM32_PLLIN_MIN..STM32_PLLIN_MAX)" +#endif + +/** + * @brief PLL1 input range selector. + */ +#if (STM32_PLL1_REF_CK < STM32_PLLIN_THRESHOLD1) || defined(__DOXYGEN__) +#define STM32_PLLCFGR_PLL1RGE RCC_PLLCFGR_PLL1RGE_0 +#elif STM32_PLL1_REF_CK < STM32_PLLIN_THRESHOLD2 +#define STM32_PLLCFGR_PLL1RGE RCC_PLLCFGR_PLL1RGE_1 +#elif STM32_PLL1_REF_CK < STM32_PLLIN_THRESHOLD3 +#define STM32_PLLCFGR_PLL1RGE RCC_PLLCFGR_PLL1RGE_2 +#else +#define STM32_PLLCFGR_PLL1RGE RCC_PLLCFGR_PLL1RGE_3 +#endif + +/** + * @brief PLL2 DIVM field. + */ +#if ((STM32_PLL2_DIVM_VALUE >= 1) && (STM32_PLL2_DIVM_VALUE <= 63)) || \ + defined(__DOXYGEN__) +#define STM32_PLL2_DIVM (STM32_PLL2_DIVM_VALUE << 12) +#define STM32_PLL2_REF_CK (STM32_PLLCLKIN / STM32_PLL2_DIVM_VALUE) +#else +#error "invalid STM32_PLL2_DIVM_VALUE value specified" +#endif + +/* + * PLL2 input frequency range check. + */ +#if (STM32_PLL2_REF_CK < STM32_PLLIN_MIN) || (STM32_PLL2_REF_CK > STM32_PLLIN_MAX) +#error "STM32_PLL2_REF_CK outside acceptable range (STM32_PLLIN_MIN..STM32_PLLIN_MAX)" +#endif + +/** + * @brief PLL2 input range selector. + */ +#if (STM32_PLL2_REF_CK < STM32_PLLIN_THRESHOLD1) || defined(__DOXYGEN__) +#define STM32_PLLCFGR_PLL2RGE RCC_PLLCFGR_PLL2RGE_0 +#elif STM32_PLL2_REF_CK < STM32_PLLIN_THRESHOLD2 +#define STM32_PLLCFGR_PLL2RGE RCC_PLLCFGR_PLL2RGE_1 +#elif STM32_PLL2_REF_CK < STM32_PLLIN_THRESHOLD3 +#define STM32_PLLCFGR_PLL2RGE RCC_PLLCFGR_PLL2RGE_2 +#else +#define STM32_PLLCFGR_PLL2RGE RCC_PLLCFGR_PLL2RGE_3 +#endif + +/** + * @brief PLL3 DIVM field. + */ +#if ((STM32_PLL3_DIVM_VALUE >= 1) && (STM32_PLL3_DIVM_VALUE <= 63)) || \ + defined(__DOXYGEN__) +#define STM32_PLL3_DIVM (STM32_PLL3_DIVM_VALUE << 20) +#define STM32_PLL3_REF_CK (STM32_PLLCLKIN / STM32_PLL3_DIVM_VALUE) +#else +#error "invalid STM32_PLL3_DIVM_VALUE value specified" +#endif + +/* + * PLL3 input frequency range check. + */ +#if (STM32_PLL3_REF_CK < STM32_PLLIN_MIN) || (STM32_PLL3_REF_CK > STM32_PLLIN_MAX) +#error "STM32_PLL3_REF_CK outside acceptable range (STM32_PLLIN_MIN..STM32_PLLIN_MAX)" +#endif + +/** + * @brief PLL3 input range selector. + */ +#if (STM32_PLL3_REF_CK < STM32_PLLIN_THRESHOLD1) || defined(__DOXYGEN__) +#define STM32_PLLCFGR_PLL3RGE RCC_PLLCFGR_PLL3RGE_0 +#elif STM32_PLL3_REF_CK < STM32_PLLIN_THRESHOLD2 +#define STM32_PLLCFGR_PLL3RGE RCC_PLLCFGR_PLL3RGE_1 +#elif STM32_PLL3_REF_CK < STM32_PLLIN_THRESHOLD3 +#define STM32_PLLCFGR_PLL3RGE RCC_PLLCFGR_PLL3RGE_2 +#else +#define STM32_PLLCFGR_PLL3RGE RCC_PLLCFGR_PLL3RGE_3 +#endif + +/** + * @brief PLL1 DIVN field. + */ +#if ((STM32_PLL1_DIVN_VALUE >= 4) && (STM32_PLL1_DIVN_VALUE <= 512)) || \ + defined(__DOXYGEN__) +#define STM32_PLL1_DIVN ((STM32_PLL1_DIVN_VALUE - 1U) << 0U) +#else +#error "invalid STM32_PLL1_DIVN_VALUE value specified" +#endif + +/** + * @brief PLL2 DIVN field. + */ +#if ((STM32_PLL2_DIVN_VALUE >= 4) && (STM32_PLL2_DIVN_VALUE <= 512)) || \ + defined(__DOXYGEN__) +#define STM32_PLL2_DIVN ((STM32_PLL2_DIVN_VALUE - 1U) << 0U) +#else +#error "invalid STM32_PLL2_DIVN_VALUE value specified" +#endif + +/** + * @brief PLL3 DIVN field. + */ +#if ((STM32_PLL3_DIVN_VALUE >= 4) && (STM32_PLL3_DIVN_VALUE <= 512)) || \ + defined(__DOXYGEN__) +#define STM32_PLL3_DIVN ((STM32_PLL3_DIVN_VALUE - 1U) << 0U) +#else +#error "invalid STM32_PLL3_DIVN_VALUE value specified" +#endif + +/** + * @brief PLL1 FRACN field. + */ +#if ((STM32_PLL1_FRACN_VALUE >= 0) && (STM32_PLL1_FRACN_VALUE <= 8191)) || \ + defined(__DOXYGEN__) +#define STM32_PLL1_FRACN (STM32_PLL1_FRACN_VALUE << 3U) +#else +#error "invalid STM32_PLL1_FRACN_VALUE value specified" +#endif + +/** + * @brief PLL2 FRACN field. + */ +#if ((STM32_PLL2_FRACN_VALUE >= 0) && (STM32_PLL2_FRACN_VALUE <= 8191)) || \ + defined(__DOXYGEN__) +#define STM32_PLL2_FRACN (STM32_PLL2_FRACN_VALUE << 3U) +#else +#error "invalid STM32_PLL2_FRACN_VALUE value specified" +#endif + +/** + * @brief PLL3 FRACN field. + */ +#if ((STM32_PLL3_FRACN_VALUE >= 0) && (STM32_PLL3_FRACN_VALUE <= 8191)) || \ + defined(__DOXYGEN__) +#define STM32_PLL3_FRACN (STM32_PLL3_FRACN_VALUE << 3U) +#else +#error "invalid STM32_PLL3_FRACN_VALUE value specified" +#endif + +/** + * @brief PLL1 DIVP field. + */ +#if ((STM32_PLL1_DIVP_VALUE >= 2) && (STM32_PLL1_DIVP_VALUE <= 128) && \ + ((STM32_PLL1_DIVP_VALUE & 1U) == 0U)) || \ + defined(__DOXYGEN__) +#define STM32_PLL1_DIVP ((STM32_PLL1_DIVP_VALUE - 1U) << 9U) +#else +#error "invalid STM32_PLL1_DIVP_VALUE value specified" +#endif + +/** + * @brief PLL2 DIVP field. + */ +#if ((STM32_PLL2_DIVP_VALUE >= 2) && (STM32_PLL2_DIVP_VALUE <= 128)) || \ + defined(__DOXYGEN__) +#define STM32_PLL2_DIVP ((STM32_PLL2_DIVP_VALUE - 1U) << 9U) +#else +#error "invalid STM32_PLL2_DIVP_VALUE value specified" +#endif + +/** + * @brief PLL3 DIVP field. + */ +#if ((STM32_PLL3_DIVP_VALUE >= 2) && (STM32_PLL3_DIVP_VALUE <= 128)) || \ + defined(__DOXYGEN__) +#define STM32_PLL3_DIVP ((STM32_PLL3_DIVP_VALUE - 1U) << 9U) +#else +#error "invalid STM32_PLL3_DIVP_VALUE value specified" +#endif + +/** + * @brief PLL1 DIVQ field. + */ +#if ((STM32_PLL1_DIVQ_VALUE >= 1) && (STM32_PLL1_DIVQ_VALUE <= 128)) || \ + defined(__DOXYGEN__) +#define STM32_PLL1_DIVQ ((STM32_PLL1_DIVQ_VALUE - 1U) << 16U) +#else +#error "invalid STM32_PLL1_DIVQ_VALUE value specified" +#endif + +/** + * @brief PLL2 DIVQ field. + */ +#if ((STM32_PLL2_DIVQ_VALUE >= 1) && (STM32_PLL2_DIVQ_VALUE <= 128)) || \ + defined(__DOXYGEN__) +#define STM32_PLL2_DIVQ ((STM32_PLL2_DIVQ_VALUE - 1U) << 16U) +#else +#error "invalid STM32_PLL2_DIVQ_VALUE value specified" +#endif + +/** + * @brief PLL3 DIVQ field. + */ +#if ((STM32_PLL3_DIVQ_VALUE >= 1) && (STM32_PLL3_DIVQ_VALUE <= 128)) || \ + defined(__DOXYGEN__) +#define STM32_PLL3_DIVQ ((STM32_PLL3_DIVQ_VALUE - 1U) << 16U) +#else +#error "invalid STM32_PLL3_DIVQ_VALUE value specified" +#endif + +/** + * @brief PLL1 DIVR field. + */ +#if ((STM32_PLL1_DIVR_VALUE >= 1) && (STM32_PLL1_DIVR_VALUE <= 128)) || \ + defined(__DOXYGEN__) +#define STM32_PLL1_DIVR ((STM32_PLL1_DIVR_VALUE - 1U) << 24U) +#else +#error "invalid STM32_PLL1_DIVR_VALUE value specified" +#endif + +/** + * @brief PLL2 DIVR field. + */ +#if ((STM32_PLL2_DIVR_VALUE >= 1) && (STM32_PLL2_DIVR_VALUE <= 128)) || \ + defined(__DOXYGEN__) +#define STM32_PLL2_DIVR ((STM32_PLL2_DIVR_VALUE - 1U) << 24U) +#else +#error "invalid STM32_PLL2_DIVR_VALUE value specified" +#endif + +/** + * @brief PLL3 DIVR field. + */ +#if ((STM32_PLL3_DIVR_VALUE >= 1) && (STM32_PLL3_DIVR_VALUE <= 128)) || \ + defined(__DOXYGEN__) +#define STM32_PLL3_DIVR ((STM32_PLL3_DIVR_VALUE - 1U) << 24U) +#else +#error "invalid STM32_PLL3_DIVR_VALUE value specified" +#endif + +/** + * @brief PLL1 VCO frequency. + */ +#define STM32_PLL1_VCO_CK (STM32_PLL1_REF_CK * STM32_PLL1_DIVN_VALUE) + +/* + * PLL1 VCO frequency range check. + */ +#if (STM32_PLL1_VCO_CK < STM32_PLLVCO_MIN) || (STM32_PLL1_VCO_CK > STM32_PLLVCO_MAX) +#error "STM32_PLL1_VCO_CK outside acceptable range (STM32_PLLVCO_MIN..STM32_PLLVCO_MAX)" +#endif + +/* + * PLL1 VCO mode. + */ +#if (STM32_PLL1_VCO_CK > STM32_PLLVCO_THRESHOLD) || defined(__DOXYGEN__) +#define STM32_PLLCFGR_PLL1VCOSEL 0U +#else +#define STM32_PLLCFGR_PLL1VCOSEL RCC_PLLCFGR_PLL1VCOSEL +#endif + +/** + * @brief PLL2 VCO frequency. + */ +#define STM32_PLL2_VCO_CK (STM32_PLL2_REF_CK * STM32_PLL2_DIVN_VALUE) + +/* + * PLL2 VCO frequency range check. + */ +#if STM32_PLL2_ENABLED == TRUE +#if (STM32_PLL2_VCO_CK < STM32_PLLVCO_MIN) || (STM32_PLL2_VCO_CK > STM32_PLLVCO_MAX) +#error "STM32_PLL2_VCO_CK outside acceptable range (STM32_PLLVCO_MIN..STM32_PLLVCO_MAX)" +#endif +#endif // STM32_PLL2_ENABLED == TRUE + +/* + * PLL2 VCO mode. + */ +#if (STM32_PLL2_VCO_CK > STM32_PLLVCO_THRESHOLD) || defined(__DOXYGEN__) +#define STM32_PLLCFGR_PLL2VCOSEL 0U +#else +#define STM32_PLLCFGR_PLL2VCOSEL RCC_PLLCFGR_PLL2VCOSEL +#endif + +/** + * @brief PLL3 VCO frequency. + */ +#define STM32_PLL3_VCO_CK (STM32_PLL3_REF_CK * STM32_PLL3_DIVN_VALUE) + +/* + * PLL3 VCO frequency range check. + */ +#if STM32_PLL3_ENABLED == TRUE +#if (STM32_PLL3_VCO_CK < STM32_PLLVCO_MIN) || (STM32_PLL3_VCO_CK > STM32_PLLVCO_MAX) +#error "STM32_PLL3_VCO_CK outside acceptable range (STM32_PLLVCO_MIN..STM32_PLLVCO_MAX)" +#endif +#endif // STM32_PLL3_ENABLED == TRUE + +/* + * PLL3 VCO mode. + */ +#if (STM32_PLL3_VCO_CK > STM32_PLLVCO_THRESHOLD) || defined(__DOXYGEN__) +#define STM32_PLLCFGR_PLL3VCOSEL 0U +#else +#define STM32_PLLCFGR_PLL3VCOSEL RCC_PLLCFGR_PLL3VCOSEL +#endif + +#endif // STM32_PLLSRC != STM32_PLLSRC_DISABLE + +#if ((STM32_PLL1_ENABLED == TRUE) && (STM32_PLL1_P_ENABLED == TRUE)) || \ + defined(__DOXYGEN__) +/** + * @brief PLL1 P output clock frequency. + */ +#define STM32_PLL1_P_CK (STM32_PLL1_VCO_CK / STM32_PLL1_DIVP_VALUE) + +/* + * PLL1 P output frequency range check. + */ +#if (STM32_PLL1_P_CK < STM32_PLLOUT_MIN) || (STM32_PLL1_P_CK > STM32_PLLOUT_MAX) +#error "STM32_PLL1_P_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)" +#endif +#else +#define STM32_PLL1_P_CK 0U +#endif + +#if ((STM32_PLL2_ENABLED == TRUE) && (STM32_PLL2_P_ENABLED == TRUE)) || \ + defined(__DOXYGEN__) +/** + * @brief PLL2 P output clock frequency. + */ +#define STM32_PLL2_P_CK (STM32_PLL2_VCO_CK / STM32_PLL2_DIVP_VALUE) + +/* + * PLL2 P output frequency range check. + */ +#if (STM32_PLL2_P_CK < STM32_PLLOUT_MIN) || (STM32_PLL2_P_CK > STM32_PLLOUT_MAX) +#error "STM32_PLL2_P_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)" +#endif +#else +#define STM32_PLL2_P_CK 0U +#endif + +#if ((STM32_PLL3_ENABLED == TRUE) && (STM32_PLL3_P_ENABLED == TRUE)) || \ + defined(__DOXYGEN__) +/** + * @brief PLL3 P output clock frequency. + */ +#define STM32_PLL3_P_CK (STM32_PLL3_VCO_CK / STM32_PLL3_DIVP_VALUE) + +/* + * PLL3 P output frequency range check. + */ +#if (STM32_PLL3_P_CK < STM32_PLLOUT_MIN) || (STM32_PLL3_P_CK > STM32_PLLOUT_MAX) +#error "STM32_PLL3_P_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)" +#endif +#else +#define STM32_PLL3_P_CK 0U +#endif + +#if ((STM32_PLL1_ENABLED == TRUE) && (STM32_PLL1_Q_ENABLED == TRUE)) || \ + defined(__DOXYGEN__) +/** + * @brief PLL1 Q output clock frequency. + */ +#define STM32_PLL1_Q_CK (STM32_PLL1_VCO_CK / STM32_PLL1_DIVQ_VALUE) + +/* + * PLL1 Q output frequency range check. + */ +#if (STM32_PLL1_Q_CK < STM32_PLLOUT_MIN) || (STM32_PLL1_Q_CK > STM32_PLLOUT_MAX) +#error "STM32_PLL1_Q_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)" +#endif +#else +#define STM32_PLL1_Q_CK 0U +#endif + +#if ((STM32_PLL2_ENABLED == TRUE) && (STM32_PLL2_Q_ENABLED == TRUE)) || \ + defined(__DOXYGEN__) +/** + * @brief PLL2 Q output clock frequency. + */ +#define STM32_PLL2_Q_CK (STM32_PLL2_VCO_CK / STM32_PLL2_DIVQ_VALUE) + +/* + * PLL2 Q output frequency range check. + */ +#if (STM32_PLL2_Q_CK < STM32_PLLOUT_MIN) || (STM32_PLL2_Q_CK > STM32_PLLOUT_MAX) +#error "STM32_PLL2_Q_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)" +#endif +#else +#define STM32_PLL2_Q_CK 0U +#endif + +#if ((STM32_PLL3_ENABLED == TRUE) && (STM32_PLL3_Q_ENABLED == TRUE)) || \ + defined(__DOXYGEN__) +/** + * @brief PLL3 Q output clock frequency. + */ +#define STM32_PLL3_Q_CK (STM32_PLL3_VCO_CK / STM32_PLL3_DIVQ_VALUE) + +/* + * PLL3 Q output frequency range check. + */ +#if (STM32_PLL3_Q_CK < STM32_PLLOUT_MIN) || (STM32_PLL3_Q_CK > STM32_PLLOUT_MAX) +#error "STM32_PLL3_Q_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)" +#endif +#else +#define STM32_PLL3_Q_CK 0U +#endif + +#if ((STM32_PLL1_ENABLED == TRUE) && (STM32_PLL1_R_ENABLED == TRUE)) || \ + defined(__DOXYGEN__) +/** + * @brief PLL1 R output clock frequency. + */ +#define STM32_PLL1_R_CK (STM32_PLL1_VCO_CK / STM32_PLL1_DIVR_VALUE) + +/* + * PLL1 R output frequency range check. + */ +#if (STM32_PLL1_R_CK < STM32_PLLOUT_MIN) || (STM32_PLL1_R_CK > STM32_PLLOUT_MAX) +#error "STM32_PLL1_R_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)" +#endif +#else +#define STM32_PLL1_R_CK 0U +#endif + +#if ((STM32_PLL2_ENABLED == TRUE) && (STM32_PLL2_R_ENABLED == TRUE)) || \ + defined(__DOXYGEN__) +/** + * @brief PLL2 R output clock frequency. + */ +#define STM32_PLL2_R_CK (STM32_PLL2_VCO_CK / STM32_PLL2_DIVR_VALUE) + +/* + * PLL2 R output frequency range check. + */ +#if (STM32_PLL2_R_CK < STM32_PLLOUT_MIN) || (STM32_PLL2_R_CK > STM32_PLLOUT_MAX) +#error "STM32_PLL2_R_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)" +#endif +#else +#define STM32_PLL2_R_CK 0U +#endif + +#if ((STM32_PLL3_ENABLED == TRUE) && (STM32_PLL3_R_ENABLED == TRUE)) || \ + defined(__DOXYGEN__) +/** + * @brief PLL3 R output clock frequency. + */ +#define STM32_PLL3_R_CK (STM32_PLL3_VCO_CK / STM32_PLL3_DIVR_VALUE) + +/* + * PLL3 R output frequency range check. + */ +#if (STM32_PLL3_R_CK < STM32_PLLOUT_MIN) || (STM32_PLL3_R_CK > STM32_PLLOUT_MAX) +#error "STM32_PLL3_R_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)" +#endif +#else +#define STM32_PLL3_R_CK 0U +#endif + +/** + * @brief System clock source. + */ +#if (STM32_SW == STM32_SW_HSI_CK) || defined(__DOXYGEN__) +#define STM32_SYS_CK STM32_HSI_CK + +#elif (STM32_SW == STM32_SW_CSI_CK) +#define STM32_SYS_CK STM32_CSI_CK + +#elif (STM32_SW == STM32_SW_HSE_CK) +#define STM32_SYS_CK STM32_HSE_CK + +#elif (STM32_SW == STM32_SW_PLL1_P_CK) +#define STM32_SYS_CK STM32_PLL1_P_CK + +#else +#error "invalid STM32_SW value specified" +#endif + +/* + * Check on the system clock. + */ +#if STM32_SYS_CK > STM32_SYSCLK_MAX +#error "STM32_SYS_CK above maximum rated frequency (STM32_SYSCLK_MAX)" +#endif + +/* + * ODEN setting based on clock frequency. + */ +#if STM32_SYS_CK > STM32_SYSCLK_MAX_NOBOOST +#define STM32_ODEN STM32_ODEN_ENABLED +#else +#define STM32_ODEN STM32_ODEN_DISABLED +#endif + +/** + * @brief Peripherals clock source. + */ +#if (STM32_CKPERSEL == STM32_CKPERSEL_HSI_CK) || defined(__DOXYGEN__) +#define STM32_PER_CK STM32_HSI_CK + +#elif (STM32_CKPERSEL == STM32_CKPERSEL_CSI_CK) +#define STM32_PER_CK STM32_CSI_CK + +#elif (STM32_CKPERSEL == STM32_CKPERSEL_HSE_CK) +#define STM32_PER_CK STM32_HSE_CK + +#else +#error "invalid STM32_CKPERSEL value specified" +#endif + +/* + * Check on the peripherals clock. + */ +#if STM32_PER_CK > STM32_HCLK_MAX +#error "STM32_PER_CK above maximum rated frequency (STM32_HCLK_MAX)" +#endif + +/** + * @brief MCO1 divider clock. + */ +#if (STM32_MCO1SEL == STM32_MCO1SEL_HSI_CK) || defined(__DOXYGEN__) +#define STM32_MCO1DIVCLK STM32_HSI_CK + +#elif STM32_MCO1SEL == STM32_MCO1SEL_LSE_CK +#define STM32_MCO1DIVCLK STM32_LSE_CK + +#elif STM32_MCO1SEL == STM32_MCO1SEL_HSE_CK +#define STM32_MCO1DIVCLK STM32_HSE_CK + +#elif STM32_MCO1SEL == STM32_MCO1SEL_PLL1_Q_CK +#define STM32_MCO1DIVCLK STM32_PLL1_P_CK + +#elif STM32_MCO1SEL == STM32_MCO1SEL_HSI48_CK +#define STM32_MCO1DIVCLK STM32_HSI48_CK + +#else +#error "invalid STM32_MCO1SEL value specified" +#endif + +/** + * @brief MCO1 output pin clock. + */ +#if (STM32_MCO1PRE_VALUE < 1) || (STM32_MCO1PRE_VALUE > 15) +#error "STM32_MCO1PRE_VALUE outside acceptable range (1..15)" +#endif + +/** + * @brief MCO2 divider clock. + */ +#if (STM32_MCO2SEL == STM32_MCO2SEL_SYS_CK) || defined(__DOXYGEN__) +#define STM32_MCO2DIVCLK STM32_SYS_CK + +#elif STM32_MCO2SEL == STM32_MCO2SEL_PLL1_P_CK +#define STM32_MCO2DIVCLK STM32_PLL2_P_CK + +#elif STM32_MCO2SEL == STM32_MCO2SEL_HSE_CK +#define STM32_MCO2DIVCLK STM32_HSE_CK + +#elif STM32_MCO2SEL == STM32_MCO2SEL_PLL2_P_CK +#define STM32_MCO2DIVCLK STM32_PLL2_P_CK + +#elif STM32_MCO2SEL == STM32_MCO2SEL_CSI_CK +#define STM32_MCO2DIVCLK STM32_CSI_CK + +#elif STM32_MCO2SEL == STM32_MCO2SEL_LSI_CK +#define STM32_MCO2DIVCLK STM32_LSI_CK + +#else +#error "invalid STM32_MCO2SEL value specified" +#endif + +/** + * @brief MCO2 output pin clock. + */ +#if (STM32_MCO2PRE_VALUE < 1) || (STM32_MCO2PRE_VALUE > 15) +#error "STM32_MCO2PRE_VALUE outside acceptable range (1..15)" +#endif + +/** + * @brief RTC clock. + */ +#if (STM32_RTCSEL == STM32_RTCSEL_NOCLK) || defined(__DOXYGEN__) +#define STM32_RTC_CK 0 + +#elif STM32_RTCSEL == STM32_RTCSEL_LSE_CK +#define STM32_RTC_CK STM32_LSE_CK + +#elif STM32_RTCSEL == STM32_RTCSEL_LSI_CK +#define STM32_RTC_CK STM32_LSI_CK + +#elif STM32_RTCSEL == STM32_RTCSEL_HSE_1M_CK +#define STM32_RTC_CK STM32_HSE_1M_CK + +#else +#error "invalid STM32_RTCSEL value specified" +#endif + +/* + * Check on the RTC clock. + */ +#if STM32_RTC_CK > 1000000 +#error "STM32_RTC_CK above maximum rated frequency (1000000)" +#endif + +/** + * @brief D1CPRE clock. + */ +#if (STM32_D1CPRE == STM32_D1CPRE_DIV1) || defined(__DOXYGEN__) +#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 1U) +#elif STM32_D1CPRE == STM32_D1CPRE_DIV2 +#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 2U) +#elif STM32_D1CPRE == STM32_D1CPRE_DIV4 +#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 4U) +#elif STM32_D1CPRE == STM32_D1CPRE_DIV8 +#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 8U) +#elif STM32_D1CPRE == STM32_D1CPRE_DIV16 +#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 16U) +#elif STM32_D1CPRE == STM32_D1CPRE_DIV64 +#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 64U) +#elif STM32_D1CPRE == STM32_D1CPRE_DIV128 +#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 128U) +#elif STM32_D1CPRE == STM32_D1CPRE_DIV256 +#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 256U) +#elif STM32_D1CPRE == STM32_D1CPRE_DIV512 +#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 512U) +#else +#error "invalid STM32_D1CPRE value specified" +#endif + +/** + * @brief HCLK clock. + */ +#if (STM32_D1HPRE == STM32_D1HPRE_DIV1) || defined(__DOXYGEN__) +#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 1U) +#elif STM32_D1HPRE == STM32_D1HPRE_DIV2 +#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 2U) +#elif STM32_D1HPRE == STM32_D1HPRE_DIV4 +#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 4U) +#elif STM32_D1HPRE == STM32_D1HPRE_DIV8 +#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 8U) +#elif STM32_D1HPRE == STM32_D1HPRE_DIV16 +#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 16U) +#elif STM32_D1HPRE == STM32_D1HPRE_DIV64 +#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 64U) +#elif STM32_D1HPRE == STM32_D1HPRE_DIV128 +#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 128U) +#elif STM32_D1HPRE == STM32_D1HPRE_DIV256 +#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 256U) +#elif STM32_D1HPRE == STM32_D1HPRE_DIV512 +#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 512U) +#else +#error "invalid STM32_D1HPRE value specified" +#endif + +/** + * @brief Core clock. + */ +#define STM32_CORE1_CK STM32_SYS_D1CPRE_CK + +/** + * @brief Core clock. + */ +#define STM32_CORE2_CK STM32_HCLK + +#if (STM32_TARGET_CORE == 1) || defined(__DOXYGEN__) + +#if STM32_HAS_M7 != TRUE +#error "Cortex-M7 not present in this device" +#endif +#define STM32_CORE_CK STM32_CORE1_CK + +#elif STM32_TARGET_CORE == 2 + +#if STM32_HAS_M4 != TRUE +#error "Cortex-M4 not present in this device" +#endif +#define STM32_CORE_CK STM32_CORE2_CK + +#else +#error "invalid STM32_TARGET_CORE value specified" +#endif + +/* + * AHB frequency check. + */ +#if STM32_HCLK > STM32_HCLK_MAX +#error "STM32_HCLK exceeding maximum frequency (STM32_HCLK_MAX)" +#endif + +/** + * @brief D1 PCLK3 clock. + */ +#if (STM32_D1PPRE3 == STM32_D1PPRE3_DIV1) || defined(__DOXYGEN__) +#define STM32_PCLK3 (STM32_HCLK / 1U) +#elif STM32_D1PPRE3 == STM32_D1PPRE3_DIV2 +#define STM32_PCLK3 (STM32_HCLK / 2U) +#elif STM32_D1PPRE3 == STM32_D1PPRE3_DIV4 +#define STM32_PCLK3 (STM32_HCLK / 4U) +#elif STM32_D1PPRE3 == STM32_D1PPRE3_DIV8 +#define STM32_PCLK3 (STM32_HCLK / 8U) +#elif STM32_D1PPRE3 == STM32_D1PPRE3_DIV16 +#define STM32_PCLK3 (STM32_HCLK / 16U) +#else +#error "invalid STM32_D1PPRE3 value specified" +#endif + +/* + * D1 PCLK3 frequency check. + */ +#if STM32_PCLK3 > STM32_PCLK3_MAX +#error "STM32_PCLK3 exceeding maximum frequency (STM32_PCLK3_MAX)" +#endif + +/** + * @brief D2 PCLK1 clock. + */ +#if (STM32_D2PPRE1 == STM32_D2PPRE1_DIV1) || defined(__DOXYGEN__) +#define STM32_PCLK1 (STM32_HCLK / 1U) +#elif STM32_D2PPRE1 == STM32_D2PPRE1_DIV2 +#define STM32_PCLK1 (STM32_HCLK / 2U) +#elif STM32_D2PPRE1 == STM32_D2PPRE1_DIV4 +#define STM32_PCLK1 (STM32_HCLK / 4U) +#elif STM32_D2PPRE1 == STM32_D2PPRE1_DIV8 +#define STM32_PCLK1 (STM32_HCLK / 8U) +#elif STM32_D2PPRE1 == STM32_D2PPRE1_DIV16 +#define STM32_PCLK1 (STM32_HCLK / 16U) +#else +#error "invalid STM32_D2PPRE1 value specified" +#endif + +/* + * D2 PCLK1 frequency check. + */ +#if STM32_PCLK1 > STM32_PCLK1_MAX +#error "STM32_PCLK1 exceeding maximum frequency (STM32_PCLK1_MAX)" +#endif + +/** + * @brief D2 PCLK2 clock. + */ +#if (STM32_D2PPRE2 == STM32_D2PPRE2_DIV1) || defined(__DOXYGEN__) +#define STM32_PCLK2 (STM32_HCLK / 1U) +#elif STM32_D2PPRE2 == STM32_D2PPRE2_DIV2 +#define STM32_PCLK2 (STM32_HCLK / 2U) +#elif STM32_D2PPRE2 == STM32_D2PPRE2_DIV4 +#define STM32_PCLK2 (STM32_HCLK / 4U) +#elif STM32_D2PPRE2 == STM32_D2PPRE2_DIV8 +#define STM32_PCLK2 (STM32_HCLK / 8U) +#elif STM32_D2PPRE2 == STM32_D2PPRE2_DIV16 +#define STM32_PCLK2 (STM32_HCLK / 16U) +#else +#error "invalid STM32_D2PPRE2 value specified" +#endif + +/* + * D2 PCLK2 frequency check. + */ +#if STM32_PCLK2 > STM32_PCLK2_MAX +#error "STM32_PCLK2 exceeding maximum frequency (STM32_PCLK2_MAX)" +#endif + +/** + * @brief D3 PCLK4 clock. + */ +#if (STM32_D3PPRE4 == STM32_D3PPRE4_DIV1) || defined(__DOXYGEN__) +#define STM32_PCLK4 (STM32_HCLK / 1U) +#elif STM32_D3PPRE4 == STM32_D3PPRE4_DIV2 +#define STM32_PCLK4 (STM32_HCLK / 2U) +#elif STM32_D3PPRE4 == STM32_D3PPRE4_DIV4 +#define STM32_PCLK4 (STM32_HCLK / 4U) +#elif STM32_D3PPRE4 == STM32_D3PPRE4_DIV8 +#define STM32_PCLK4 (STM32_HCLK / 8U) +#elif STM32_D3PPRE4 == STM32_D3PPRE4_DIV16 +#define STM32_PCLK4 (STM32_HCLK / 16U) +#else +#error "invalid STM32_D3PPRE4 value specified" +#endif + +/* + * D3 PCLK4 frequency check. + */ +#if STM32_PCLK4 > STM32_PCLK4_MAX +#error "STM32_PCLK4 exceeding maximum frequency (STM32_PCLK4_MAX)" +#endif + +/** + * @brief Flash settings. + */ +#if (STM32_HCLK <= STM32_0WS_THRESHOLD) || defined(__DOXYGEN__) +#define STM32_FLASHBITS 0x00000000 + +#elif STM32_HCLK <= STM32_1WS_THRESHOLD +#define STM32_FLASHBITS 0x00000001 + +#elif STM32_HCLK <= STM32_2WS_THRESHOLD +#define STM32_FLASHBITS 0x00000002 + +#elif STM32_HCLK <= STM32_3WS_THRESHOLD +#define STM32_FLASHBITS 0x00000003 + +#elif STM32_HCLK <= STM32_4WS_THRESHOLD +#define STM32_FLASHBITS 0x00000004 + +#else +#define STM32_FLASHBITS 0x00000007 +#endif + +#if (STM32_D2PPRE1 == STM32_D2PPRE1_DIV1) || defined(__DOXYGEN__) +/** + * @brief Clock of timers connected to APB1 + */ +#define STM32_TIMCLK1 (STM32_PCLK1 * 1) +#else +#if (STM32_TIMPRE_ENABLE == FALSE) || (STM32_D2PPRE1 == STM32_D2PPRE1_DIV2) +#define STM32_TIMCLK1 (STM32_PCLK1 * 2) +#else +#define STM32_TIMCLK1 (STM32_PCLK1 * 4) +#endif +#endif + +#if (STM32_D2PPRE2 == STM32_D2PPRE2_DIV1) || defined(__DOXYGEN__) +/** + * @brief Clock of timers connected to APB2. + */ +#define STM32_TIMCLK2 (STM32_PCLK2 * 1) +#else +#if (STM32_TIMPRE_ENABLE == FALSE) || (STM32_D2PPRE2 == STM32_D2PPRE2_DIV2) +#define STM32_TIMCLK2 (STM32_PCLK2 * 2) +#else +#define STM32_TIMCLK2 (STM32_PCLK2 * 4) +#endif +#endif + +#if (STM32_LPTIM1SEL == STM32_LPTIM1SEL_PCLK1) || defined(__DOXYGEN__) +/** + * @brief LPTIM1 clock. + */ +#define STM32_LPTIM1CLK STM32_PCLK1 + +#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_PLL2_P_CK +#define STM32_LPTIM1CLK STM32_PLL2_P_CK +#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_PLL3_R_CK +#define STM32_LPTIM1CLK STM32_PLL3_R_CK +#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_LSE_CK +#define STM32_LPTIM1CLK STM32_LSE_CK +#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_LSI_CK +#define STM32_LPTIM1CLK STM32_LSI_CK +#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_PER_CK +#define STM32_LPTIM1CLK STM32_PER_CK +#else +#error "invalid source selected for STM32_LPTIM1SEL clock" +#endif + +#if (STM32_LPTIM2SEL == STM32_LPTIM2SEL_PCLK4) || defined(__DOXYGEN__) +/** + * @brief LPTIM2 clock. + */ +#define STM32_LPTIM2CLK STM32_PCLK4 + +#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_PLL2_P_CK +#define STM32_LPTIM2CLK STM32_PLL2_P_CK +#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_PLL3_P_CK +#define STM32_LPTIM2CLK STM32_PLL3_P_CK +#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_LSE_CK +#define STM32_LPTIM2CLK STM32_LSE_CK +#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_LSI_CK +#define STM32_LPTIM2CLK STM32_LSI_CK +#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_PER_CK +#define STM32_LPTIM2CLK STM32_PER_CK +#else +#error "invalid source selected for STM32_LPTIM2SEL clock" +#endif + +#if (STM32_LPTIM345SEL == STM32_LPTIM345SEL_PCLK4) || defined(__DOXYGEN__) +/** + * @brief LPTIM3 clock. + */ +#define STM32_LPTIM3CLK STM32_PCLK4 + +/** + * @brief LPTIM4 clock. + */ +#define STM32_LPTIM4CLK STM32_PCLK4 + +/** + * @brief LPTIM5 clock. + */ +#define STM32_LPTIM5CLK STM32_PCLK4 + +#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_PLL2_P_CK +#define STM32_LPTIM3CLK STM32_PLL2_P_CK +#define STM32_LPTIM4CLK STM32_PLL2_P_CK +#define STM32_LPTIM5CLK STM32_PLL2_P_CK +#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_PLL3_P_CK +#define STM32_LPTIM3CLK STM32_PLL3_P_CK +#define STM32_LPTIM4CLK STM32_PLL3_P_CK +#define STM32_LPTIM5CLK STM32_PLL3_P_CK +#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_LSE_CK +#define STM32_LPTIM3CLK STM32_LSE_CK +#define STM32_LPTIM4CLK STM32_LSE_CK +#define STM32_LPTIM5CLK STM32_LSE_CK +#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_LSI_CK +#define STM32_LPTIM3CLK STM32_LSI_CK +#define STM32_LPTIM4CLK STM32_LSI_CK +#define STM32_LPTIM5CLK STM32_LSI_CK +#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_PER_CK +#define STM32_LPTIM3CLK STM32_PER_CK +#define STM32_LPTIM4CLK STM32_PER_CK +#define STM32_LPTIM5CLK STM32_PER_CK +#else +#error "invalid source selected for STM32_LPTIM345SEL clock" +#endif + +#if !defined(STM32H723xx) +#if (STM32_USART16SEL == STM32_USART16SEL_PCLK2) || defined(__DOXYGEN__) +/** + * @brief USART1 clock. + */ +#define STM32_USART1CLK STM32_PCLK2 + +/** + * @brief USART6 clock. + */ +#define STM32_USART6CLK STM32_PCLK2 + +#elif STM32_USART16SEL == STM32_USART16SEL_PLL2_Q_CK +#define STM32_USART1CLK STM32_PLL2_Q_CK +#define STM32_USART6CLK STM32_PLL2_Q_CK +#elif STM32_USART16SEL == STM32_USART16SEL_PLL3_Q_CK +#define STM32_USART1CLK STM32_PLL3_Q_CK +#define STM32_USART6CLK STM32_PLL3_Q_CK +#elif STM32_USART16SEL == STM32_USART16SEL_HSI_KER_CK +#define STM32_USART1CLK STM32_HSI_CK +#define STM32_USART6CLK STM32_HSI_CK +#elif STM32_USART16SEL == STM32_USART16SEL_CSI_KER_CK +#define STM32_USART1CLK STM32_CSI_CK +#define STM32_USART6CLK STM32_CSI_CK +#elif STM32_USART16SEL == STM32_USART16SEL_LSE_CK +#define STM32_USART1CLK STM32_LSE_CK +#define STM32_USART6CLK STM32_LSE_CK +#else +#error "invalid source selected for STM32_USART16SEL clock" +#endif +#else // then defined(STM32H723xx) +#if (STM32_USART16910SEL == STM32_USART16910SEL_PCLK2) || defined(__DOXYGEN__) + +#define STM32_USART1CLK STM32_PCLK2 +#define STM32_USART6CLK STM32_PCLK2 +#define STM32_USART9CLK STM32_PCLK2 +#define STM32_USART10CLK STM32_PCLK2 + +#elif STM32_USART16910SEL == STM32_USART16910SEL_PLL2_Q_CK +#define STM32_USART1CLK STM32_PLL2_Q_CK +#define STM32_USART6CLK STM32_PLL2_Q_CK +#define STM32_USART9CLK STM32_PLL2_Q_CK +#define STM32_USART10CLK STM32_PLL2_Q_CK +#elif STM32_USART16910SEL == STM32_USART16910SEL_PLL3_Q_CK +#define STM32_USART1CLK STM32_PLL3_Q_CK +#define STM32_USART6CLK STM32_PLL3_Q_CK +#define STM32_USART9CLK STM32_PLL3_Q_CK +#define STM32_USART10CLK STM32_PLL3_Q_CK +#elif STM32_USART16910SEL == STM32_USART16910SEL_HSI_KER_CK +#define STM32_USART1CLK STM32_HSI_CK +#define STM32_USART6CLK STM32_HSI_CK +#define STM32_USART9CLK STM32_HSI_CK +#define STM32_USART10CLK STM32_HSI_CK +#elif STM32_USART16910SEL == STM32_USART16910SEL_CSI_KER_CK +#define STM32_USART1CLK STM32_CSI_CK +#define STM32_USART6CLK STM32_CSI_CK +#define STM32_USART9CLK STM32_CSI_CK +#define STM32_USART10CLK STM32_CSI_CK +#elif STM32_USART16910SEL == STM32_USART16910SEL_LSE_CK +#define STM32_USART1CLK STM32_LSE_CK +#define STM32_USART6CLK STM32_LSE_CK +#define STM32_USART9CLK STM32_LSE_CK +#define STM32_USART10CLK STM32_LSE_CK +#else +#error "invalid source selected for STM32_USART16910SEL clock" +#endif +#endif // !defined(STM32H723xx) + +#if (STM32_USART234578SEL == STM32_USART234578SEL_PCLK1) || defined(__DOXYGEN__) +/** + * @brief USART2 clock. + */ +#define STM32_USART2CLK STM32_PCLK1 + +/** + * @brief USART3 clock. + */ +#define STM32_USART3CLK STM32_PCLK1 + +/** + * @brief USART4 clock. + */ +#define STM32_UART4CLK STM32_PCLK1 + +/** + * @brief USART5 clock. + */ +#define STM32_UART5CLK STM32_PCLK1 + +/** + * @brief USART7 clock. + */ +#define STM32_UART7CLK STM32_PCLK1 + +/** + * @brief USART8 clock. + */ +#define STM32_UART8CLK STM32_PCLK1 + +#elif STM32_USART234578SEL == STM32_USART234578SEL_PLL2_Q_CK +#define STM32_USART2CLK STM32_PLL2_Q_CK +#define STM32_USART3CLK STM32_PLL2_Q_CK +#define STM32_UART4CLK STM32_PLL2_Q_CK +#define STM32_UART5CLK STM32_PLL2_Q_CK +#define STM32_UART7CLK STM32_PLL2_Q_CK +#define STM32_UART8CLK STM32_PLL2_Q_CK +#elif STM32_USART234578SEL == STM32_USART234578SEL_PLL3_Q_CK +#define STM32_USART2CLK STM32_PLL3_Q_CK +#define STM32_USART3CLK STM32_PLL3_Q_CK +#define STM32_UART4CLK STM32_PLL3_Q_CK +#define STM32_UART5CLK STM32_PLL3_Q_CK +#define STM32_UART7CLK STM32_PLL3_Q_CK +#define STM32_UART8CLK STM32_PLL3_Q_CK +#elif STM32_USART234578SEL == STM32_USART234578SEL_HSI_KER_CK +#define STM32_USART2CLK STM32_HSI_CK +#define STM32_USART3CLK STM32_HSI_CK +#define STM32_UART4CLK STM32_HSI_CK +#define STM32_UART5CLK STM32_HSI_CK +#define STM32_UART7CLK STM32_HSI_CK +#define STM32_UART8CLK STM32_HSI_CK +#elif STM32_USART234578SEL == STM32_USART234578SEL_CSI_KER_CK +#define STM32_USART2CLK STM32_CSI_CK +#define STM32_USART3CLK STM32_CSI_CK +#define STM32_UART4CLK STM32_CSI_CK +#define STM32_UART5CLK STM32_CSI_CK +#define STM32_UART7CLK STM32_CSI_CK +#define STM32_UART8CLK STM32_CSI_CK +#elif STM32_USART234578SEL == STM32_USART234578SEL_LSE_CK +#define STM32_USART2CLK STM32_LSE_CK +#define STM32_USART3CLK STM32_LSE_CK +#define STM32_UART4CLK STM32_LSE_CK +#define STM32_UART6CLK STM32_LSE_CK +#define STM32_UART7CLK STM32_LSE_CK +#define STM32_UART8CLK STM32_LSE_CK +#else +#error "invalid source selected for STM32_USART234578SEL clock" +#endif + +#if (STM32_LPUART1SEL == STM32_LPUART1SEL_PCLK4) || defined(__DOXYGEN__) +/** + * @brief LPUART1 clock. + */ +#define STM32_LPUART1CLK STM32_PCLK4 + +#elif STM32_LPUART1SEL == STM32_LPUART1SEL_PLL2_Q_CK +#define STM32_LPUART1CLK STM32_PLL2_Q_CK +#elif STM32_LPUART1SEL == STM32_LPUART1SEL_PLL3_Q_CK +#define STM32_LPUART1CLK STM32_PLL3_Q_CK +#elif STM32_LPUART1SEL == STM32_LPUART1SEL_HSI_KER_CK +#define STM32_LPUART1CLK STM32_HSI_CK +#elif STM32_LPUART1SEL == STM32_LPUART1SEL_CSI_KER_CK +#define STM32_LPUART1CLK STM32_CSI_CK +#elif STM32_LPUART1SEL == STM32_LPUART1SEL_LSE_CK +#define STM32_LPUART1CLK STM32_LSE_CK +#else +#error "invalid source selected for STM32_LPUART1SEL clock" +#endif + +#if (STM32_SPI123SEL == STM32_SPI123SEL_PLL1_Q_CK) || defined(__DOXYGEN__) +/** + * @brief SPI1 clock. + */ +#define STM32_SPI1CLK STM32_PLL1_Q_CK + +/** + * @brief SPI2 clock. + */ +#define STM32_SPI2CLK STM32_PLL1_Q_CK + +/** + * @brief SPI3 clock. + */ +#define STM32_SPI3CLK STM32_PLL1_Q_CK +#elif STM32_SPI123SEL == STM32_SPI123SEL_PLL2_P_CK +#define STM32_SPI1CLK STM32_PLL2_P_CK +#define STM32_SPI2CLK STM32_PLL2_P_CK +#define STM32_SPI3CLK STM32_PLL2_P_CK +#elif STM32_SPI123SEL == STM32_SPI123SEL_PLL3_P_CK +#define STM32_SPI1CLK STM32_PLL3_P_CK +#define STM32_SPI2CLK STM32_PLL3_P_CK +#define STM32_SPI3CLK STM32_PLL3_P_CK +#elif STM32_SPI123SEL == STM32_SPI123SEL_I2S_CKIN +#define STM32_SPI1CLK 0 /* Unknown, would require a board value */ +#define STM32_SPI2CLK 0 /* Unknown, would require a board value */ +#define STM32_SPI3CLK 0 /* Unknown, would require a board value */ +#elif STM32_SPI123SEL == STM32_SPI123SEL_PER_CK +#define STM32_SPI1CLK STM32_PER_CK +#define STM32_SPI2CLK STM32_PER_CK +#define STM32_SPI3CLK STM32_PER_CK +#else +#error "invalid source selected for STM32_SPI123SEL clock" +#endif + +#if (STM32_SPI45SEL == STM32_SPI45SEL_PCLK2) || defined(__DOXYGEN__) +/** + * @brief SPI4 clock. + */ +#define STM32_SPI4CLK STM32_PCLK2 + +/** + * @brief SPI5 clock. + */ +#define STM32_SPI5CLK STM32_PCLK2 + +#elif STM32_SPI45SEL == STM32_SPI45SEL_PLL2_Q_CK +#define STM32_SPI4CLK STM32_PLL2_Q_CK +#define STM32_SPI5CLK STM32_PLL2_Q_CK +#elif STM32_SPI45SEL == STM32_SPI45SEL_PLL3_Q_CK +#define STM32_SPI4CLK STM32_PLL3_Q_CK +#define STM32_SPI5CLK STM32_PLL3_Q_CK +#elif STM32_SPI45SEL == STM32_SPI45SEL_HSI_KER_CK +#define STM32_SPI4CLK STM32_HSI_CK +#define STM32_SPI5CLK STM32_HSI_CK +#elif STM32_SPI45SEL == STM32_SPI45SEL_CSI_KER_CK +#define STM32_SPI4CLK STM32_CSI_CK +#define STM32_SPI5CLK STM32_CSI_CK +#elif STM32_SPI45SEL == STM32_SPI45SEL_HSE_CK +#define STM32_SPI4CLK STM32_HSE_CK +#define STM32_SPI5CLK STM32_HSE_CK +#else +#error "invalid source selected for STM32_SPI45SEL clock" +#endif + +#if (STM32_SPI6SEL == STM32_SPI6SEL_PCLK4) || defined(__DOXYGEN__) +/** + * @brief SPI6 clock. + */ +#define STM32_SPI6CLK STM32_PCLK4 + +#elif STM32_SPI6SEL == STM32_SPI6SEL_PLL2_Q_CK +#define STM32_SPI6CLK STM32_PLL2_Q_CK +#elif STM32_SPI6SEL == STM32_SPI6SEL_PLL3_Q_CK +#define STM32_SPI6CLK STM32_PLL3_Q_CK +#elif STM32_SPI6SEL == STM32_SPI6SEL_HSI_KER_CK +#define STM32_SPI6CLK STM32_HSI_CK +#elif STM32_SPI6SEL == STM32_SPI6SEL_CSI_KER_CK +#define STM32_SPI6CLK STM32_CSI_CK +#elif STM32_SPI6SEL == STM32_SPI6SEL_HSE_CK +#define STM32_SPI6CLK STM32_HSE_CK +#else +#error "invalid source selected for STM32_SPI6SEL clock" +#endif + +#if !defined(STM32H723xx) +#if (STM32_I2C123SEL == STM32_I2C123SEL_PCLK1) || defined(__DOXYGEN__) +/** + * @brief I2C1 clock. + */ +#define STM32_I2C1CLK STM32_PCLK1 + +/** + * @brief I2C2 clock. + */ +#define STM32_I2C2CLK STM32_PCLK1 + +/** + * @brief I2C3 clock. + */ +#define STM32_I2C3CLK STM32_PCLK1 + +#elif STM32_I2C123SEL == STM32_I2C123SEL_PLL3_R_CK +#define STM32_I2C1CLK STM32_PLL3_R_CK +#define STM32_I2C2CLK STM32_PLL3_R_CK +#define STM32_I2C2CLK STM32_PLL3_R_CK + +#elif STM32_I2C123SEL == STM32_I2C123SEL_HSI_KER_CK +#define STM32_I2C1CLK STM32_HSI_CK +#define STM32_I2C2CLK STM32_HSI_CK +#define STM32_I2C2CLK STM32_HSI_CK + +#elif STM32_I2C123SEL == STM32_I2C123SEL_CSI_KER_CK +#define STM32_I2C1CLK STM32_CSI_CK +#define STM32_I2C2CLK STM32_CSI_CK +#define STM32_I2C2CLK STM32_CSI_CK +#else +#error "invalid source selected for STM32_I2C123SEL clock" +#endif +#else // then defined(STM32H723xx) +#if (STM32_I2C1235SEL == STM32_I2C1235SEL_PCLK1) || defined(__DOXYGEN__) + +#define STM32_I2C1CLK STM32_PCLK1 +#define STM32_I2C2CLK STM32_PCLK1 +#define STM32_I2C3CLK STM32_PCLK1 +#define STM32_I2C5CLK STM32_PCLK1 + +#elif STM32_I2C1235SEL == STM32_I2C1235SEL_PLL3_R_CK +#define STM32_I2C1CLK STM32_PLL3_R_CK +#define STM32_I2C2CLK STM32_PLL3_R_CK +#define STM32_I2C3CLK STM32_PLL3_R_CK +#define STM32_I2C5CLK STM32_PLL3_R_CK + +#elif STM32_I2C1235SEL == STM32_I2C1235SEL_HSI_KER_CK +#define STM32_I2C1CLK STM32_HSI_CK +#define STM32_I2C2CLK STM32_HSI_CK +#define STM32_I2C3CLK STM32_HSI_CK +#define STM32_I2C5CLK STM32_HSI_CK + +#elif STM32_I2C1235SEL == STM32_I2C1235SEL_CSI_KER_CK +#define STM32_I2C1CLK STM32_CSI_CK +#define STM32_I2C2CLK STM32_CSI_CK +#define STM32_I2C3CLK STM32_CSI_CK +#define STM32_I2C5CLK STM32_CSI_CK +#else +#error "invalid source selected for STM32_I2C1235SEL clock" +#endif +#endif // !defined(STM32H723xx) + +#if (STM32_I2C4SEL == STM32_I2C4SEL_PCLK4) || defined(__DOXYGEN__) +/** + * @brief I2C1 clock. + */ +#define STM32_I2C4CLK STM32_PCLK4 + +#elif STM32_I2C4SEL == STM32_I2C4SEL_PLL3_R_CK +#define STM32_I2C4CLK STM32_PLL3_R_CK +#elif STM32_I2C4SEL == STM32_I2C4SEL_HSI_KER_CK +#define STM32_I2C4CLK STM32_HSI_CK +#elif STM32_I2C4SEL == STM32_I2C4SEL_CSI_KER_CK +#define STM32_I2C4CLK STM32_CSI_CK +#else +#error "invalid source selected for STM32_I2C4SEL clock" +#endif + +#if (STM32_SAI1SEL == STM32_SAI1SEL_PLL1_Q_CK) || defined(__DOXYGEN__) +/** + * @brief SAI1 clock. + */ +#define STM32_SAI1CLK STM32_PLL1_Q_CK + +#elif STM32_SAI1SEL == STM32_SAI1SEL_PLL2_P_CK +#define STM32_SAI1CLK STM32_PLL2_P_CK +#elif STM32_SAI1SEL == STM32_SAI1SEL_PLL3_P_CK +#define STM32_SAI1CLK STM32_PLL3_P_CK +#elif STM32_SAI1SEL == STM32_SAI1SEL_I2S_CKIN +#define STM32_SAI1CLK 0 /* Unknown, would require a board value */ +#elif STM32_SAI1SEL == STM32_SAI1SEL_PER_CK +#define STM32_SAI1CLK STM32_PER_CK +#else +#error "invalid source selected for STM32_SAI1SEL clock" +#endif + +#if !defined(STM32H723xx) +#if (STM32_SAI23SEL == STM32_SAI23SEL_PLL1_Q_CK) || defined(__DOXYGEN__) +/** + * @brief SAI2 clock. + */ +#define STM32_SAI2CLK STM32_PLL1_Q_CK + +/** + * @brief SAI3 clock. + */ +#define STM32_SAI3CLK STM32_PLL1_Q_CK + +#elif STM32_SAI23SEL == STM32_SAI23SEL_PLL2_P_CK +#define STM32_SAI2CLK STM32_PLL2_P_CK +#define STM32_SAI3CLK STM32_PLL2_P_CK +#elif STM32_SAI23SEL == STM32_SAI23SEL_PLL3_P_CK +#define STM32_SAI2CLK STM32_PLL3_P_CK +#define STM32_SAI3CLK STM32_PLL3_P_CK +#elif STM32_SAI23SEL == STM32_SAI23SEL_I2S_CKIN +#define STM32_SAI2CLK 0 /* Unknown, would require a board value */ +#define STM32_SAI3CLK 0 /* Unknown, would require a board value */ +#elif STM32_SAI23SEL == STM32_SAI23SEL_PER_CK +#define STM32_SAI2CLK STM32_PER_CK +#define STM32_SAI3CLK STM32_PER_CK +#else +#error "invalid source selected for STM32_SAI23SEL clock" +#endif +#endif // !defined(STM32H723xx) + +#if (STM32_SAI4ASEL == STM32_SAI4ASEL_PLL1_Q_CK) || defined(__DOXYGEN__) +/** + * @brief SAI4A clock. + */ +#define STM32_SAI4ACLK STM32_PLL1_Q_CK + +#elif STM32_SAI4ASEL == STM32_SAI4ASEL_PLL2_P_CK +#define STM32_SAI4ACLK STM32_PLL2_P_CK +#elif STM32_SAI4ASEL == STM32_SAI4ASEL_PLL3_P_CK +#define STM32_SAI4ACLK STM32_PLL3_P_CK +#elif STM32_SAI4ASEL == STM32_SAI4ASEL_I2S_CKIN +#define STM32_SAI4ACLK 0 /* Unknown, would require a board value */ +#elif STM32_SAI4ASEL == STM32_SAI4ASEL_PER_CK +#define STM32_SAI4ACLK STM32_PER_CK +#else +#error "invalid source selected for STM32_SAI4ASEL clock" +#endif + +#if (STM32_SAI4BSEL == STM32_SAI4BSEL_PLL1_Q_CK) || defined(__DOXYGEN__) +/** + * @brief SAI4B clock. + */ +#define STM32_SAI4BCLK STM32_PLL1_Q_CK + +#elif STM32_SAI4BSEL == STM32_SAI4BSEL_PLL2_P_CK +#define STM32_SAI4BCLK STM32_PLL2_P_CK +#elif STM32_SAI4BSEL == STM32_SAI4BSEL_PLL3_P_CK +#define STM32_SAI4BCLK STM32_PLL3_P_CK +#elif STM32_SAI4BSEL == STM32_SAI4BSEL_I2S_CKIN +#define STM32_SAI4BCLK 0 /* Unknown, would require a board value */ +#elif STM32_SAI4BSEL == STM32_SAI4BSEL_PER_CK +#define STM32_SAI4BCLK STM32_PER_CK +#else +#error "invalid source selected for STM32_SAI4BSEL clock" +#endif + +#if (STM32_USBSEL == STM32_USBSEL_DISABLE) || defined(__DOXYGEN__) +/** + * @brief USB clock. + */ +#define STM32_USBCLK 0 + +#elif STM32_USBSEL == STM32_USBSEL_PLL1_Q_CK +#define STM32_USBCLK STM32_PLL1_Q_CK +#elif STM32_USBSEL == STM32_USBSEL_PLL3_Q_CK +#define STM32_USBCLK STM32_PLL3_Q_CK +#elif STM32_USBSEL == STM32_USBSEL_HSI48_CK +#define STM32_USBCLK STM32_HSI48_CK +#else +#error "invalid source selected for STM32_USBSEL clock" +#endif + +#if (STM32_SDMMCSEL == STM32_SDMMCSEL_PLL1_Q_CK) || defined(__DOXYGEN__) +/** + * @brief SDMMC1 frequency. + */ +#define STM32_SDMMC1CLK STM32_PLL1_Q_CK + +/** + * @brief SDMMC2 frequency. + */ +#define STM32_SDMMC2CLK STM32_PLL1_Q_CK + +#elif STM32_SDMMCSEL == STM32_SDMMCSEL_PLL2_R_CK +#define STM32_SDMMC1CLK STM32_PLL2_R_CK +#define STM32_SDMMC2CLK STM32_PLL2_R_CK +#else +#error "invalid source selected for STM32_SDMMCxSEL clock" +#endif + +#if !defined(STM32H723xx) +#if (STM32_QSPISEL == STM32_QSPISEL_HCLK) || defined(__DOXYGEN__) +/** + * @brief QSPI frequency. + */ +#define STM32_QSPICLK STM32_HCLK + +#elif STM32_QSPISEL == STM32_QSPISEL_PLL1_Q_CK +#define STM32_QSPICLK STM32_PLL1_Q_CK +#elif STM32_QSPISEL == STM32_QSPISEL_PLL2_R_CK +#define STM32_QSPICLK STM32_PLL2_R_CK +#elif STM32_QSPISEL == STM32_QSPISEL_PER_CK +#define STM32_QSPICLK STM32_PER_CK +#else +#error "invalid source selected for STM32_QSPISEL clock" +#endif + +#if (STM32_FMCSEL == STM32_FMCSEL_HCLK) || defined(__DOXYGEN__) +/** + * @brief FMC frequency. + */ +#define STM32_FMCCLK STM32_HCLK + +#elif STM32_FMCSEL == STM32_FMCSEL_PLL1_Q_CK +#define STM32_FMCCLK STM32_PLL1_Q_CK +#elif STM32_FMCSEL == STM32_FMCSEL_PLL2_R_CK +#define STM32_FMCCLK STM32_PLL2_R_CK +#elif STM32_FMCSEL == STM32_FMCSEL_PER_CK +#define STM32_FMCCLK STM32_PER_CK +#else +#error "invalid source selected for STM32_FMCSEL clock" +#endif +#endif // !defined(STM32H723xx) + +#if (STM32_SWPSEL == STM32_SWPSEL_PCLK1) || defined(__DOXYGEN__) +/** + * @brief SDMMC frequency. + */ +#define STM32_SWPCLK STM32_PCLK1 + +#elif STM32_SWPSEL == STM32_SWPSEL_HSI_KER_CK +#define STM32_SWPCLK STM32_HSI_CK +#else +#error "invalid source selected for STM32_SWPSEL clock" +#endif + +#if (STM32_FDCANSEL == STM32_FDCANSEL_HSE_CK) || defined(__DOXYGEN__) +/** + * @brief FDCAN frequency. + */ +#define STM32_FDCANCLK STM32_HSE_CK + +#elif STM32_FDCANSEL == STM32_FDCANSEL_PLL1_Q_CK +#define STM32_FDCANCLK STM32_PLL1_Q_CK +#elif STM32_FDCANSEL == STM32_FDCANSEL_PLL2_Q_CK +#define STM32_FDCANCLK STM32_PLL2_Q_CK +#else +#error "invalid source selected for STM32_FDCANSEL clock" +#endif + +#if (STM32_DFSDM1SEL == STM32_DFSDM1SEL_PCLK2) || defined(__DOXYGEN__) +/** + * @brief SDMMC frequency. + */ +#define STM32_DFSDM1CLK STM32_PCLK2 + +#elif STM32_DFSDM1SEL == STM32_DFSDM1SEL_SYS_CK +#define STM32_DFSDM1CLK STM32_SYS_CK +#else +#error "invalid source selected for STM32_DFSDM1SEL clock" +#endif + +#if (STM32_SPDIFSEL == STM32_SPDIFSEL_PLL1_Q_CK) || defined(__DOXYGEN__) +/** + * @brief SPDIF frequency. + */ +#define STM32_SPDIFCLK STM32_PLL1_Q_CK + +#elif STM32_SPDIFSEL == STM32_SPDIFSEL_PLL2_R_CK +#define STM32_SPDIFCLK STM32_PLL2_R_CK +#elif STM32_SPDIFSEL == STM32_SPDIFSEL_PLL3_R_CK +#define STM32_SPDIFCLK STM32_PLL3_R_CK +#elif STM32_SPDIFSEL == STM32_SPDIFSEL_HSI_KET_CLK +#define STM32_SPDIFCLK STM32_HSI_CK +#else +#error "invalid source selected for STM32_SPDIFSEL clock" +#endif + +#if (STM32_CECSEL == STM32_CECSEL_LSE_CK) || defined(__DOXYGEN__) +/** + * @brief CEC frequency. + */ +#define STM32_CECCLK STM32_LSE_CK + +#elif STM32_CECSEL == STM32_CECSEL_LSI_CK +#define STM32_CECCLK STM32_LSI_CK +#elif STM32_CECSEL == STM32_CECSEL_CSI_KER_CK +#define STM32_CECCLK STM32_CSI_CK +#elif STM32_CECSEL == STM32_CECSEL_DISABLE +#define STM32_CECCLK 0 +#else +#error "invalid source selected for STM32_CECSEL clock" +#endif + +#if (STM32_RNGSEL == STM32_RNGSEL_HSI48_CK) || defined(__DOXYGEN__) +/** + * @brief RNG frequency. + */ +#define STM32_RNGCLK STM32_HSI48_CK + +#elif STM32_RNGSEL == STM32_RNGSEL_PLL1_Q_CK +#define STM32_RNGCLK STM32_PLL1_Q_CK +#elif STM32_RNGSEL == STM32_RNGSEL_LSE_CK +#define STM32_RNGCLK STM32_LSE_CK +#elif STM32_RNGSEL == STM32_RNGSEL_LSI_CK +#define STM32_RNGCLK STM32_LSI_CK +#else +#error "invalid source selected for STM32_RNGSEL clock" +#endif + +#if (STM32_ADCSEL == STM32_ADCSEL_PLL2_P_CK) || defined(__DOXYGEN__) +/** + * @brief ADC frequency. + */ +#define STM32_ADCCLK STM32_PLL2_P_CK + +#elif STM32_ADCSEL == STM32_ADCSEL_PLL3_R_CK +#define STM32_ADCCLK STM32_PLL3_R_CK +#elif STM32_ADCSEL == STM32_ADCSEL_PER_CK +#define STM32_ADCCLK STM32_PER_CK +#elif STM32_ADCSEL == STM32_ADCSEL_DISABLE +#define STM32_ADCCLK 0 +#else +#error "invalid source selected for STM32_ADCSEL clock" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/* Various helpers.*/ +#include "nvic.h" +#include "cache.h" +#include "mpu_v7m.h" +#include "stm32_isr.h" +#include "stm32_mdma.h" +#include "stm32_dma.h" +#include "stm32_bdma.h" +#include "stm32_exti.h" +#include "stm32_rcc.h" +#include "stm32_tim.h" + +#ifdef __cplusplus +extern "C" { +#endif + void hal_lld_init(void); + void stm32_clock_init(void); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_LLD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/platform.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/platform.mk new file mode 100644 index 0000000..05c12ef --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/platform.mk @@ -0,0 +1,50 @@ +# Required platform files. +PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32H7xx/stm32_isr.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32H7xx/hal_lld.c + +# Required include directories. +PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ + $(CHIBIOS)/os/hal/ports/STM32/STM32H7xx + +# Optional platform files. +ifeq ($(USE_SMART_BUILD),yes) + +# Configuration files directory +ifeq ($(HALCONFDIR),) + ifeq ($(CONFDIR),) + HALCONFDIR = . + else + HALCONFDIR := $(CONFDIR) + endif +endif + +HALCONF := $(strip $(shell cat $(HALCONFDIR)/halconf.h | egrep -e "\#define")) + +else +endif + +# Drivers compatible with the platform. +include $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv4/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/BDMAv1/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/CRYPv1/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv2/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/FDCANv1/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv3/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/MDMAv1/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/RNGv1/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/xWDGv1/driver.mk + +# Shared variables +ALLCSRC += $(PLATFORMSRC) +ALLINC += $(PLATFORMINC) diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_dmamux.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_dmamux.h new file mode 100644 index 0000000..c4bace0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_dmamux.h @@ -0,0 +1,206 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file STM32H7xx/stm32_dmamux.h + * @brief STM32H7xx DMAMUX handler header. + * + * @addtogroup STM32H7xx_DMAMUX + * @{ + */ + +#ifndef STM32_DMAMUX_H +#define STM32_DMAMUX_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name DMAMUX1 request sources + * @{ + */ +#define STM32_DMAMUX1_REQ_GEN0 1 +#define STM32_DMAMUX1_REQ_GEN1 2 +#define STM32_DMAMUX1_REQ_GEN2 3 +#define STM32_DMAMUX1_REQ_GEN3 4 +#define STM32_DMAMUX1_REQ_GEN4 5 +#define STM32_DMAMUX1_REQ_GEN5 6 +#define STM32_DMAMUX1_REQ_GEN6 7 +#define STM32_DMAMUX1_REQ_GEN7 8 +#define STM32_DMAMUX1_ADC1 9 +#define STM32_DMAMUX1_ADC2 10 +#define STM32_DMAMUX1_TIM1_CH1 11 +#define STM32_DMAMUX1_TIM1_CH2 12 +#define STM32_DMAMUX1_TIM1_CH3 13 +#define STM32_DMAMUX1_TIM1_CH4 14 +#define STM32_DMAMUX1_TIM1_UP 15 +#define STM32_DMAMUX1_TIM1_TRIG 16 +#define STM32_DMAMUX1_TIM1_COM 17 +#define STM32_DMAMUX1_TIM2_CH1 18 +#define STM32_DMAMUX1_TIM2_CH2 19 +#define STM32_DMAMUX1_TIM2_CH3 20 +#define STM32_DMAMUX1_TIM2_CH4 21 +#define STM32_DMAMUX1_TIM2_UP 22 +#define STM32_DMAMUX1_TIM3_CH1 23 +#define STM32_DMAMUX1_TIM3_CH2 24 +#define STM32_DMAMUX1_TIM3_CH3 25 +#define STM32_DMAMUX1_TIM3_CH4 26 +#define STM32_DMAMUX1_TIM3_UP 27 +#define STM32_DMAMUX1_TIM3_TRIG 28 +#define STM32_DMAMUX1_TIM4_CH1 29 +#define STM32_DMAMUX1_TIM4_CH2 30 +#define STM32_DMAMUX1_TIM4_CH3 31 +#define STM32_DMAMUX1_TIM4_UP 32 +#define STM32_DMAMUX1_I2C1_RX 33 +#define STM32_DMAMUX1_I2C1_TX 34 +#define STM32_DMAMUX1_I2C2_RX 35 +#define STM32_DMAMUX1_I2C2_TX 36 +#define STM32_DMAMUX1_SPI1_RX 37 +#define STM32_DMAMUX1_SPI1_TX 38 +#define STM32_DMAMUX1_SPI2_RX 39 +#define STM32_DMAMUX1_SPI2_TX 40 +#define STM32_DMAMUX1_USART1_RX 41 +#define STM32_DMAMUX1_USART1_TX 42 +#define STM32_DMAMUX1_USART2_RX 43 +#define STM32_DMAMUX1_USART2_TX 44 +#define STM32_DMAMUX1_USART3_RX 45 +#define STM32_DMAMUX1_USART3_TX 46 +#define STM32_DMAMUX1_TIM8_CH1 47 +#define STM32_DMAMUX1_TIM8_CH2 48 +#define STM32_DMAMUX1_TIM8_CH3 49 +#define STM32_DMAMUX1_TIM8_CH4 50 +#define STM32_DMAMUX1_TIM8_UP 51 +#define STM32_DMAMUX1_TIM8_TRIG 52 +#define STM32_DMAMUX1_TIM8_COM 53 +#define STM32_DMAMUX1_RESERVED54 54 +#define STM32_DMAMUX1_TIM5_CH1 55 +#define STM32_DMAMUX1_TIM5_CH2 56 +#define STM32_DMAMUX1_TIM5_CH3 57 +#define STM32_DMAMUX1_TIM5_CH4 58 +#define STM32_DMAMUX1_TIM5_UP 59 +#define STM32_DMAMUX1_TIM5_TRIG 60 +#define STM32_DMAMUX1_SPI3_RX 61 +#define STM32_DMAMUX1_SPI3_TX 62 +#define STM32_DMAMUX1_UART4_RX 63 +#define STM32_DMAMUX1_UART4_TX 64 +#define STM32_DMAMUX1_UART5_RX 65 +#define STM32_DMAMUX1_UART5_TX 66 +#define STM32_DMAMUX1_DAC1_CH1 67 /* Renamed to L4 name.*/ +#define STM32_DMAMUX1_DAC1_CH2 68 /* Renamed to L4 name.*/ +#define STM32_DMAMUX1_TIM6_UP 69 +#define STM32_DMAMUX1_TIM7_UP 70 +#define STM32_DMAMUX1_USART6_RX 71 +#define STM32_DMAMUX1_USART6_TX 72 +#define STM32_DMAMUX1_I2C3_RX 73 +#define STM32_DMAMUX1_I2C3_TX 74 +#define STM32_DMAMUX1_DCMI 75 +#define STM32_DMAMUX1_CRYP_IN 76 +#define STM32_DMAMUX1_CRYP_OUT 77 +#define STM32_DMAMUX1_HASH_IN 78 +#define STM32_DMAMUX1_UART7_RX 79 +#define STM32_DMAMUX1_UART7_TX 80 +#define STM32_DMAMUX1_UART8_RX 81 +#define STM32_DMAMUX1_UART8_TX 82 +#define STM32_DMAMUX1_SPI4_RX 83 +#define STM32_DMAMUX1_SPI4_TX 84 +#define STM32_DMAMUX1_SPI5_RX 85 +#define STM32_DMAMUX1_SPI5_TX 86 +#define STM32_DMAMUX1_SAI1_A 87 +#define STM32_DMAMUX1_SAI1_B 88 +#define STM32_DMAMUX1_SAI2_A 89 +#define STM32_DMAMUX1_SAI2_B 90 +#define STM32_DMAMUX1_SWPMI_RX 91 +#define STM32_DMAMUX1_SQPMI_TX 92 +#define STM32_DMAMUX1_SPDIFRX_DT 93 +#define STM32_DMAMUX1_SPDIFRX_CS 94 +#define STM32_DMAMUX1_HR_REQ1 95 +#define STM32_DMAMUX1_HR_REQ2 96 +#define STM32_DMAMUX1_HR_REQ3 97 +#define STM32_DMAMUX1_HR_REQ4 98 +#define STM32_DMAMUX1_HR_REQ5 99 +#define STM32_DMAMUX1_HR_REQ6 100 +#define STM32_DMAMUX1_DFSDM1_DMA0 101 +#define STM32_DMAMUX1_DFSDM1_DMA1 102 +#define STM32_DMAMUX1_DFSDM1_DMA2 103 +#define STM32_DMAMUX1_DFSDM1_DMA3 104 +#define STM32_DMAMUX1_TIM15_CH1 105 +#define STM32_DMAMUX1_TIM15_UP 106 +#define STM32_DMAMUX1_TIM15_TRIG 107 +#define STM32_DMAMUX1_TIM15_COM 108 +#define STM32_DMAMUX1_TIM16_CH1 109 +#define STM32_DMAMUX1_TIM16_UP 110 +#define STM32_DMAMUX1_TIM17_CH1 111 +#define STM32_DMAMUX1_TIM17_UP 112 +#define STM32_DMAMUX1_SAI3A 113 +#define STM32_DMAMUX1_SAI3B 114 +#define STM32_DMAMUX1_ADC3 115 +/** @} */ + +/** + * @name DMAMUX2 request sources + * @{ + */ +#define STM32_DMAMUX2_REQ_GEN0 1 +#define STM32_DMAMUX2_REQ_GEN1 2 +#define STM32_DMAMUX2_REQ_GEN2 3 +#define STM32_DMAMUX2_REQ_GEN3 4 +#define STM32_DMAMUX2_REQ_GEN4 5 +#define STM32_DMAMUX2_REQ_GEN5 6 +#define STM32_DMAMUX2_REQ_GEN6 7 +#define STM32_DMAMUX2_REQ_GEN7 8 +#define STM32_DMAMUX2_LP_UART1_RX 9 +#define STM32_DMAMUX2_LP_UART1_TX 10 +#define STM32_DMAMUX2_SPI6_RX 11 +#define STM32_DMAMUX2_SPI6_TX 12 +#define STM32_DMAMUX2_I2C4_RX 13 +#define STM32_DMAMUX2_I2C4_TX 14 +#define STM32_DMAMUX2_SAI4A 15 +#define STM32_DMAMUX2_SAI4B 16 +#define STM32_DMAMUX2_ADC3_REQ 17 +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* STM32_DMAMUX_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.c b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.c new file mode 100644 index 0000000..8ed4d72 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.c @@ -0,0 +1,198 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file STM32H7xx/stm32_isr.c + * @brief STM32H7xx ISR handler code. + * + * @addtogroup STM32H7xx_ISR + * @{ + */ + +#include "hal.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define exti_serve_irq(pr, channel) { \ + \ + if ((pr) & (1U << (channel))) { \ + _pal_isr_code(channel); \ + } \ +} + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#include "stm32_exti0.inc" +#include "stm32_exti1.inc" +#include "stm32_exti2.inc" +#include "stm32_exti3.inc" +#include "stm32_exti4.inc" +#include "stm32_exti5_9.inc" +#include "stm32_exti10_15.inc" +#include "stm32_exti16.inc" +#include "stm32_exti17.inc" +#include "stm32_exti18.inc" +#include "stm32_exti19.inc" +#include "stm32_exti20_21.inc" + +#include "stm32_fdcan1.inc" +#include "stm32_fdcan2.inc" + +#include "stm32_quadspi1.inc" + +#include "stm32_sdmmc1.inc" +#include "stm32_sdmmc2.inc" + +#include +#include "stm32_usart2.inc" +#include "stm32_usart3.inc" +#include "stm32_uart4.inc" +#include "stm32_uart5.inc" +#include "stm32_usart6.inc" +#include "stm32_uart7.inc" +#include "stm32_uart8.inc" +#include "stm32_lpuart1.inc" + +#include "stm32_tim1.inc" +#include "stm32_tim2.inc" +#include "stm32_tim3.inc" +#include "stm32_tim4.inc" +#include "stm32_tim5.inc" +#include "stm32_tim6.inc" +#include "stm32_tim7.inc" +#include "stm32_tim8_12_13_14.inc" + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Enables IRQ sources. + * + * @notapi + */ +void irqInit(void) { + + exti0_irq_init(); + exti1_irq_init(); + exti2_irq_init(); + exti3_irq_init(); + exti4_irq_init(); + exti5_9_irq_init(); + exti10_15_irq_init(); + exti16_irq_init(); + exti17_irq_init(); + exti18_irq_init(); + exti19_irq_init(); + exti20_exti21_irq_init(); + + fdcan1_irq_init(); + fdcan2_irq_init(); + + mdma_irq_init(); + + quadspi1_irq_init(); + + sdmmc1_irq_init(); + sdmmc2_irq_init(); + + tim1_irq_init(); + tim2_irq_init(); + tim3_irq_init(); + tim4_irq_init(); + tim5_irq_init(); + tim6_irq_init(); + tim7_irq_init(); + tim8_tim12_tim13_tim14_irq_init(); + + usart1_irq_init(); + usart2_irq_init(); + usart3_irq_init(); + uart4_irq_init(); + uart5_irq_init(); + usart6_irq_init(); + uart7_irq_init(); + uart8_irq_init(); + lpuart1_irq_init(); +} + +/** + * @brief Disables IRQ sources. + * + * @notapi + */ +void irqDeinit(void) { + + exti0_irq_deinit(); + exti1_irq_deinit(); + exti2_irq_deinit(); + exti3_irq_deinit(); + exti4_irq_deinit(); + exti5_9_irq_deinit(); + exti10_15_irq_deinit(); + exti16_irq_deinit(); + exti17_irq_deinit(); + exti18_irq_deinit(); + exti19_irq_deinit(); + exti20_exti21_irq_deinit(); + + fdcan1_irq_deinit(); + fdcan2_irq_deinit(); + + mdma_irq_deinit(); + + quadspi1_irq_deinit(); + + sdmmc1_irq_deinit(); + sdmmc2_irq_deinit(); + + tim1_irq_deinit(); + tim2_irq_deinit(); + tim3_irq_deinit(); + tim4_irq_deinit(); + tim5_irq_deinit(); + tim6_irq_deinit(); + tim7_irq_deinit(); + tim8_tim12_tim13_tim14_irq_deinit(); + + usart1_irq_deinit(); + usart2_irq_deinit(); + usart3_irq_deinit(); + uart4_irq_deinit(); + uart5_irq_deinit(); + usart6_irq_deinit(); + uart7_irq_deinit(); + uart8_irq_deinit(); + lpuart1_irq_deinit(); +} + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.h new file mode 100644 index 0000000..e9b776a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.h @@ -0,0 +1,384 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file STM32H7xx/stm32_isr.h + * @brief STM32H7xx ISR handler header. + * + * @addtogroup STM32H7xx_ISR + * @{ + */ + +#ifndef STM32_ISR_H +#define STM32_ISR_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name ISRs suppressed in standard drivers + * @{ + */ +#define STM32_TIM1_SUPPRESS_ISR +#define STM32_TIM2_SUPPRESS_ISR +#define STM32_TIM3_SUPPRESS_ISR +#define STM32_TIM4_SUPPRESS_ISR +#define STM32_TIM5_SUPPRESS_ISR +#define STM32_TIM6_SUPPRESS_ISR +#define STM32_TIM7_SUPPRESS_ISR +#define STM32_TIM8_SUPPRESS_ISR +#define STM32_TIM12_SUPPRESS_ISR +#define STM32_TIM13_SUPPRESS_ISR +#define STM32_TIM14_SUPPRESS_ISR +#define STM32_TIM15_SUPPRESS_ISR +#define STM32_TIM16_SUPPRESS_ISR +#define STM32_TIM17_SUPPRESS_ISR + +#define STM32_USART1_SUPPRESS_ISR +#define STM32_USART2_SUPPRESS_ISR +#define STM32_USART3_SUPPRESS_ISR +#define STM32_UART4_SUPPRESS_ISR +#define STM32_UART5_SUPPRESS_ISR +#define STM32_USART6_SUPPRESS_ISR +#define STM32_UART7_SUPPRESS_ISR +#define STM32_UART8_SUPPRESS_ISR +#define STM32_LPUART1_SUPPRESS_ISR +/** @} */ + +/** + * @name ISR names and numbers + * @{ + */ +/* + * ADC units. + */ +#define STM32_ADC12_HANDLER Vector88 +#define STM32_ADC3_HANDLER Vector23C + +#define STM32_ADC12_NUMBER 18 +#define STM32_ADC3_NUMBER 127 + +/* + * BDMA units. + */ +#define STM32_BDMA1_CH0_HANDLER Vector244 +#define STM32_BDMA1_CH1_HANDLER Vector248 +#define STM32_BDMA1_CH2_HANDLER Vector24C +#define STM32_BDMA1_CH3_HANDLER Vector250 +#define STM32_BDMA1_CH4_HANDLER Vector254 +#define STM32_BDMA1_CH5_HANDLER Vector258 +#define STM32_BDMA1_CH6_HANDLER Vector25C +#define STM32_BDMA1_CH7_HANDLER Vector260 + +#define STM32_BDMA1_CH0_NUMBER 129 +#define STM32_BDMA1_CH1_NUMBER 130 +#define STM32_BDMA1_CH2_NUMBER 131 +#define STM32_BDMA1_CH3_NUMBER 132 +#define STM32_BDMA1_CH4_NUMBER 133 +#define STM32_BDMA1_CH5_NUMBER 134 +#define STM32_BDMA1_CH6_NUMBER 135 +#define STM32_BDMA1_CH7_NUMBER 136 + +/* + * DMA units. + */ +#define STM32_DMA1_CH0_HANDLER Vector6C +#define STM32_DMA1_CH1_HANDLER Vector70 +#define STM32_DMA1_CH2_HANDLER Vector74 +#define STM32_DMA1_CH3_HANDLER Vector78 +#define STM32_DMA1_CH4_HANDLER Vector7C +#define STM32_DMA1_CH5_HANDLER Vector80 +#define STM32_DMA1_CH6_HANDLER Vector84 +#define STM32_DMA1_CH7_HANDLER VectorFC +#define STM32_DMA2_CH0_HANDLER Vector120 +#define STM32_DMA2_CH1_HANDLER Vector124 +#define STM32_DMA2_CH2_HANDLER Vector128 +#define STM32_DMA2_CH3_HANDLER Vector12C +#define STM32_DMA2_CH4_HANDLER Vector130 +#define STM32_DMA2_CH5_HANDLER Vector150 +#define STM32_DMA2_CH6_HANDLER Vector154 +#define STM32_DMA2_CH7_HANDLER Vector158 + +#define STM32_DMA1_CH0_NUMBER 11 +#define STM32_DMA1_CH1_NUMBER 12 +#define STM32_DMA1_CH2_NUMBER 13 +#define STM32_DMA1_CH3_NUMBER 14 +#define STM32_DMA1_CH4_NUMBER 15 +#define STM32_DMA1_CH5_NUMBER 16 +#define STM32_DMA1_CH6_NUMBER 17 +#define STM32_DMA1_CH7_NUMBER 47 +#define STM32_DMA2_CH0_NUMBER 56 +#define STM32_DMA2_CH1_NUMBER 57 +#define STM32_DMA2_CH2_NUMBER 58 +#define STM32_DMA2_CH3_NUMBER 59 +#define STM32_DMA2_CH4_NUMBER 60 +#define STM32_DMA2_CH5_NUMBER 68 +#define STM32_DMA2_CH6_NUMBER 69 +#define STM32_DMA2_CH7_NUMBER 70 + +/* + * MDMA units. + */ +#define STM32_MDMA_HANDLER Vector228 + +#define STM32_MDMA_NUMBER 122 + +/* + * ETH units. + */ +#define STM32_ETH_HANDLER Vector134 + +#define STM32_ETH_NUMBER 61 + +/* + * EXTI units. + */ +#define STM32_EXTI0_HANDLER Vector58 +#define STM32_EXTI1_HANDLER Vector5C +#define STM32_EXTI2_HANDLER Vector60 +#define STM32_EXTI3_HANDLER Vector64 +#define STM32_EXTI4_HANDLER Vector68 +#define STM32_EXTI5_9_HANDLER Vector9C +#define STM32_EXTI10_15_HANDLER VectorE0 +#define STM32_EXTI16_HANDLER Vector44 /* PVD */ +#define STM32_EXTI17_HANDLER VectorE4 /* RTC ALARM */ +#define STM32_EXTI18_HANDLER Vector48 /* RTC TAMP CSS */ +#define STM32_EXTI19_HANDLER Vector4C /* RTC WAKEUP */ +#define STM32_EXTI2021_HANDLER Vector264 /* COMP1 COMP2 */ + +#define STM32_EXTI0_NUMBER 6 +#define STM32_EXTI1_NUMBER 7 +#define STM32_EXTI2_NUMBER 8 +#define STM32_EXTI3_NUMBER 9 +#define STM32_EXTI4_NUMBER 10 +#define STM32_EXTI5_9_NUMBER 23 +#define STM32_EXTI10_15_NUMBER 40 +#define STM32_EXTI16_NUMBER 1 +#define STM32_EXTI17_NUMBER 41 +#define STM32_EXTI18_NUMBER 42 +#define STM32_EXTI19_NUMBER 3 +#define STM32_EXTI2021_NUMBER 137 + +/* + * FDCAN units. + */ +#define STM32_FDCAN1_IT0_HANDLER Vector8C +#define STM32_FDCAN1_IT1_HANDLER Vector94 +#define STM32_FDCAN2_IT0_HANDLER Vector90 +#define STM32_FDCAN2_IT1_HANDLER Vector98 + +#define STM32_FDCAN1_IT0_NUMBER 19 +#define STM32_FDCAN1_IT1_NUMBER 21 +#define STM32_FDCAN2_IT0_NUMBER 20 +#define STM32_FDCAN2_IT1_NUMBER 22 + +/* + * I2C units. + */ +#define STM32_I2C1_EVENT_HANDLER VectorBC +#define STM32_I2C1_ERROR_HANDLER VectorC0 +#define STM32_I2C2_EVENT_HANDLER VectorC4 +#define STM32_I2C2_ERROR_HANDLER VectorC8 +#define STM32_I2C3_EVENT_HANDLER Vector160 +#define STM32_I2C3_ERROR_HANDLER Vector164 +#define STM32_I2C4_EVENT_HANDLER Vector1BC +#define STM32_I2C4_ERROR_HANDLER Vector1C0 + +#define STM32_I2C1_EVENT_NUMBER 31 +#define STM32_I2C1_ERROR_NUMBER 32 +#define STM32_I2C2_EVENT_NUMBER 33 +#define STM32_I2C2_ERROR_NUMBER 34 +#define STM32_I2C3_EVENT_NUMBER 72 +#define STM32_I2C3_ERROR_NUMBER 73 +#define STM32_I2C4_EVENT_NUMBER 95 +#define STM32_I2C4_ERROR_NUMBER 96 + +/* + * QUADSPI units. + */ +#define STM32_QUADSPI1_HANDLER Vector1B0 + +#define STM32_QUADSPI1_NUMBER 92 + +/* + * SDMMC units. + */ +#define STM32_SDMMC1_HANDLER Vector104 +#define STM32_SDMMC2_HANDLER Vector230 + +#define STM32_SDMMC1_NUMBER 49 +#define STM32_SDMMC2_NUMBER 131 + +/* + * SPI units. + */ +#define STM32_SPI1_HANDLER VectorCC +#define STM32_SPI2_HANDLER VectorD0 +#define STM32_SPI3_HANDLER Vector10C +#define STM32_SPI4_HANDLER Vector190 +#define STM32_SPI5_HANDLER Vector194 +#define STM32_SPI6_HANDLER Vector198 + +#define STM32_SPI1_NUMBER 35 +#define STM32_SPI2_NUMBER 36 +#define STM32_SPI3_NUMBER 51 +#define STM32_SPI4_NUMBER 84 +#define STM32_SPI5_NUMBER 85 +#define STM32_SPI6_NUMBER 86 + +/* + * TIM units. + */ +#define STM32_TIM1_BRK_HANDLER VectorA0 +#define STM32_TIM1_UP_HANDLER VectorA4 +#define STM32_TIM1_TRGCO_HANDLER VectorA8 +#define STM32_TIM1_CC_HANDLER VectorAC +#define STM32_TIM2_HANDLER VectorB0 +#define STM32_TIM3_HANDLER VectorB4 +#define STM32_TIM4_HANDLER VectorB8 +#define STM32_TIM5_HANDLER Vector108 +#define STM32_TIM6_HANDLER Vector118 +#define STM32_TIM7_HANDLER Vector11C +#define STM32_TIM8_BRK_TIM12_HANDLER VectorEC +#define STM32_TIM8_UP_TIM13_HANDLER VectorF0 +#define STM32_TIM8_TRGCO_TIM14_HANDLER VectorF4 +#define STM32_TIM8_CC_HANDLER VectorF8 +#define STM32_TIM15_HANDLER Vector210 +#define STM32_TIM16_HANDLER Vector214 +#define STM32_TIM17_HANDLER Vector218 + +#define STM32_TIM1_BRK_NUMBER 24 +#define STM32_TIM1_UP_NUMBER 25 +#define STM32_TIM1_TRGCO_NUMBER 26 +#define STM32_TIM1_CC_NUMBER 27 +#define STM32_TIM2_NUMBER 28 +#define STM32_TIM3_NUMBER 29 +#define STM32_TIM4_NUMBER 30 +#define STM32_TIM5_NUMBER 50 +#define STM32_TIM6_NUMBER 54 +#define STM32_TIM7_NUMBER 55 +#define STM32_TIM8_BRK_TIM12_NUMBER 43 +#define STM32_TIM8_UP_TIM13_NUMBER 44 +#define STM32_TIM8_TRGCO_TIM14_NUMBER 45 +#define STM32_TIM8_CC_NUMBER 46 +#define STM32_TIM15_NUMBER 116 +#define STM32_TIM16_NUMBER 117 +#define STM32_TIM17_NUMBER 118 + +/* + * USART/UART units. + */ +#define STM32_USART1_HANDLER VectorD4 +#define STM32_USART2_HANDLER VectorD8 +#define STM32_USART3_HANDLER VectorDC +#define STM32_UART4_HANDLER Vector110 +#define STM32_UART5_HANDLER Vector114 +#define STM32_USART6_HANDLER Vector15C +#define STM32_UART7_HANDLER Vector188 +#define STM32_UART8_HANDLER Vector18C +#define STM32_LPUART1_HANDLER Vector278 + +#define STM32_USART1_NUMBER 37 +#define STM32_USART2_NUMBER 38 +#define STM32_USART3_NUMBER 39 +#define STM32_UART4_NUMBER 52 +#define STM32_UART5_NUMBER 53 +#define STM32_USART6_NUMBER 71 +#define STM32_UART7_NUMBER 82 +#define STM32_UART8_NUMBER 83 +#define STM32_LPUART1_NUMBER 142 + +/* + * USB/OTG units. + */ +#define STM32_OTG1_HANDLER Vector1D4 +#define STM32_OTG1_EP1OUT_HANDLER Vector1C8 +#define STM32_OTG1_EP1IN_HANDLER Vector1CC +#define STM32_OTG2_HANDLER Vector174 +#define STM32_OTG2_EP1OUT_HANDLER Vector168 +#define STM32_OTG2_EP1IN_HANDLER Vector16C + +#define STM32_OTG1_NUMBER 101 +#define STM32_OTG1_EP1OUT_NUMBER 98 +#define STM32_OTG1_EP1IN_NUMBER 99 +#define STM32_OTG2_NUMBER 77 +#define STM32_OTG2_EP1OUT_NUMBER 74 +#define STM32_OTG2_EP1IN_NUMBER 75 + +/* + * LTDC units. + */ +#define STM32_LTDC_EV_HANDLER Vector1A0 +#define STM32_LTDC_ER_HANDLER Vector1A4 + +#define STM32_LTDC_EV_NUMBER 88 +#define STM32_LTDC_ER_NUMBER 89 + +/* + * DMA2D units. + */ +#define STM32_DMA2D_HANDLER Vector1A8 + +#define STM32_DMA2D_NUMBER 90 + +/* + * FSMC units. + */ +#define STM32_FSMC_HANDLER Vector100 + +#define STM32_FSMC_NUMBER 48 + +/* + * DCMI units. + */ +#define STM32_DCMI_HANDLER Vector178 + +#define STM32_DCMI_NUMBER 78 +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void irqInit(void); + void irqDeinit(void); +#ifdef __cplusplus +} +#endif + +#endif /* STM32_ISR_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_rcc.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_rcc.h new file mode 100644 index 0000000..91d1086 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_rcc.h @@ -0,0 +1,1834 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file STM32F7xx/stm32_rcc.h + * @brief RCC helper driver header. + * @note This file requires definitions from the ST header file + * @p stm32f7xx.h. + * + * @addtogroup STM32F7xx_RCC + * @{ + */ +#ifndef STM32_RCC_H +#define STM32_RCC_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @name Generic RCC operations + * @{ + */ +/** + * @brief Enables the clock of one or more peripheral on the APB1 bus. + * + * @param[in] mask APB1 peripherals mask, low set + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableAPB1L(mask, lp) { \ + RCC->APB1LENR |= (mask); \ + if (lp) \ + RCC->APB1LLPENR |= (mask); \ + else \ + RCC->APB1LLPENR &= ~(mask); \ + (void)RCC->APB1LLPENR; \ +} + +/** + * @brief Enables the clock of one or more peripheral on the APB1 bus. + * + * @param[in] mask APB1 peripherals mask, high set + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableAPB1H(mask, lp) { \ + RCC->APB1HENR |= (mask); \ + if (lp) \ + RCC->APB1HLPENR |= (mask); \ + else \ + RCC->APB1HLPENR &= ~(mask); \ + (void)RCC->APB1HLPENR; \ +} + +/** + * @brief Disables the clock of one or more peripheral on the APB1 bus. + * + * @param[in] mask APB1 peripherals mask, low set + * + * @api + */ +#define rccDisableAPB1L(mask) { \ + RCC->APB1LENR &= ~(mask); \ + RCC->APB1LLPENR &= ~(mask); \ + (void)RCC->APB1LLPENR; \ +} + +/** + * @brief Disables the clock of one or more peripheral on the APB1 bus. + * + * @param[in] mask APB1 peripherals mask, high set + * + * @api + */ +#define rccDisableAPB1H(mask) { \ + RCC->APB1HENR &= ~(mask); \ + RCC->APB1HLPENR &= ~(mask); \ + (void)RCC->APB1HLPENR; \ +} + +/** + * @brief Resets one or more peripheral on the APB1 bus. + * + * @param[in] mask APB1 peripherals mask, low set + * + * @api + */ +#define rccResetAPB1L(mask) { \ + RCC->APB1LRSTR |= (mask); \ + RCC->APB1LRSTR &= ~(mask); \ + (void)RCC->APB1LRSTR; \ +} + +/** + * @brief Resets one or more peripheral on the APB1 bus. + * + * @param[in] mask APB1 peripherals mask, high set + * + * @api + */ +#define rccResetAPB1H(mask) { \ + RCC->APB1HRSTR |= (mask); \ + RCC->APB1HRSTR &= ~(mask); \ + (void)RCC->APB1HRSTR; \ +} + +/** + * @brief Enables the clock of one or more peripheral on the APB2 bus. + * + * @param[in] mask APB2 peripherals mask + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableAPB2(mask, lp) { \ + RCC->APB2ENR |= (mask); \ + if (lp) \ + RCC->APB2LPENR |= (mask); \ + else \ + RCC->APB2LPENR &= ~(mask); \ + (void)RCC->APB2LPENR; \ +} + +/** + * @brief Disables the clock of one or more peripheral on the APB2 bus. + * + * @param[in] mask APB2 peripherals mask + * + * @api + */ +#define rccDisableAPB2(mask) { \ + RCC->APB2ENR &= ~(mask); \ + RCC->APB2LPENR &= ~(mask); \ + (void)RCC->APB2LPENR; \ +} + +/** + * @brief Resets one or more peripheral on the APB2 bus. + * + * @param[in] mask APB2 peripherals mask + * + * @api + */ +#define rccResetAPB2(mask) { \ + RCC->APB2RSTR |= (mask); \ + RCC->APB2RSTR &= ~(mask); \ + (void)RCC->APB2RSTR; \ +} + +/** + * @brief Enables the clock of one or more peripheral on the APB3 bus. + * + * @param[in] mask APB3 peripherals mask + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableAPB3(mask, lp) { \ + RCC->APB3ENR |= (mask); \ + if (lp) \ + RCC->APB3LPENR |= (mask); \ + else \ + RCC->APB3LPENR &= ~(mask); \ + (void)RCC->APB3LPENR; \ +} + +/** + * @brief Disables the clock of one or more peripheral on the APB3 bus. + * + * @param[in] mask APB3 peripherals mask + * + * @api + */ +#define rccDisableAPB3(mask) { \ + RCC->APB3ENR &= ~(mask); \ + RCC->APB3LPENR &= ~(mask); \ + (void)RCC->APB3LPENR; \ +} + +/** + * @brief Resets one or more peripheral on the APB3 bus. + * + * @param[in] mask APB2 peripherals mask + * + * @api + */ +#define rccResetAPB3(mask) { \ + RCC->APB3RSTR |= (mask); \ + RCC->APB3RSTR &= ~(mask); \ + (void)RCC->APB3RSTR; \ +} + +/** + * @brief Enables the clock of one or more peripheral on the APB4 bus. + * + * @param[in] mask APB4 peripherals mask + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableAPB4(mask, lp) { \ + RCC->APB4ENR |= (mask); \ + if (lp) \ + RCC->APB4LPENR |= (mask); \ + else \ + RCC->APB4LPENR &= ~(mask); \ + (void)RCC->APB4LPENR; \ +} + +/** + * @brief Disables the clock of one or more peripheral on the APB4 bus. + * + * @param[in] mask APB4 peripherals mask + * + * @api + */ +#define rccDisableAPB4(mask) { \ + RCC->APB4ENR &= ~(mask); \ + RCC->APB4LPENR &= ~(mask); \ + (void)RCC->APB4LPENR; \ +} + +/** + * @brief Resets one or more peripheral on the APB4 bus. + * + * @param[in] mask APB4 peripherals mask + * + * @api + */ +#define rccResetAPB4(mask) { \ + RCC->APB4RSTR |= (mask); \ + RCC->APB4RSTR &= ~(mask); \ + (void)RCC->APB4RSTR; \ +} + +/** + * @brief Enables the clock of one or more peripheral on the AHB1 bus. + * + * @param[in] mask AHB1 peripherals mask + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableAHB1(mask, lp) { \ + RCC->AHB1ENR |= (mask); \ + if (lp) \ + RCC->AHB1LPENR |= (mask); \ + else \ + RCC->AHB1LPENR &= ~(mask); \ + (void)RCC->AHB1LPENR; \ +} + +/** + * @brief Disables the clock of one or more peripheral on the AHB1 bus. + * + * @param[in] mask AHB1 peripherals mask + * + * @api + */ +#define rccDisableAHB1(mask) { \ + RCC->AHB1ENR &= ~(mask); \ + RCC->AHB1LPENR &= ~(mask); \ + (void)RCC->AHB1LPENR; \ +} + +/** + * @brief Resets one or more peripheral on the AHB1 bus. + * + * @param[in] mask AHB1 peripherals mask + * + * @api + */ +#define rccResetAHB1(mask) { \ + RCC->AHB1RSTR |= (mask); \ + RCC->AHB1RSTR &= ~(mask); \ + (void)RCC->AHB1RSTR; \ +} + +/** + * @brief Enables the clock of one or more peripheral on the AHB2 bus. + * + * @param[in] mask AHB2 peripherals mask + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableAHB2(mask, lp) { \ + RCC->AHB2ENR |= (mask); \ + if (lp) \ + RCC->AHB2LPENR |= (mask); \ + else \ + RCC->AHB2LPENR &= ~(mask); \ + (void)RCC->AHB2LPENR; \ +} + +/** + * @brief Disables the clock of one or more peripheral on the AHB2 bus. + * + * @param[in] mask AHB2 peripherals mask + * + * @api + */ +#define rccDisableAHB2(mask) { \ + RCC->AHB2ENR &= ~(mask); \ + RCC->AHB2LPENR &= ~(mask); \ + (void)RCC->AHB2LPENR; \ +} + +/** + * @brief Resets one or more peripheral on the AHB2 bus. + * + * @param[in] mask AHB2 peripherals mask + * + * @api + */ +#define rccResetAHB2(mask) { \ + RCC->AHB2RSTR |= (mask); \ + RCC->AHB2RSTR &= ~(mask); \ + (void)RCC->AHB2RSTR; \ +} + +/** + * @brief Enables the clock of one or more peripheral on the AHB3 bus. + * + * @param[in] mask AHB3 peripherals mask + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableAHB3(mask, lp) { \ + RCC->AHB3ENR |= (mask); \ + if (lp) \ + RCC->AHB3LPENR |= (mask); \ + else \ + RCC->AHB3LPENR &= ~(mask); \ + (void)RCC->AHB3LPENR; \ +} + +/** + * @brief Disables the clock of one or more peripheral on the AHB3 bus. + * + * @param[in] mask AHB3 peripherals mask + * + * @api + */ +#define rccDisableAHB3(mask) { \ + RCC->AHB3ENR &= ~(mask); \ + RCC->AHB3LPENR &= ~(mask); \ + (void)RCC->AHB3LPENR; \ +} + +/** + * @brief Resets one or more peripheral on the AHB3 bus. + * + * @param[in] mask AHB3 peripherals mask + * + * @api + */ +#define rccResetAHB3(mask) { \ + RCC->AHB3RSTR |= (mask); \ + RCC->AHB3RSTR &= ~(mask); \ + (void)RCC->AHB3RSTR; \ +} + +/** + * @brief Enables the clock of one or more peripheral on the AHB4 bus. + * + * @param[in] mask AHB4 peripherals mask + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableAHB4(mask, lp) { \ + RCC->AHB4ENR |= (mask); \ + if (lp) \ + RCC->AHB4LPENR |= (mask); \ + else \ + RCC->AHB4LPENR &= ~(mask); \ + (void)RCC->AHB4LPENR; \ +} + +/** + * @brief Disables the clock of one or more peripheral on the AHB4 bus. + * + * @param[in] mask AHB4 peripherals mask + * + * @api + */ +#define rccDisableAHB4(mask) { \ + RCC->AHB4ENR &= ~(mask); \ + RCC->AHB4LPENR &= ~(mask); \ + (void)RCC->AHB4LPENR; \ +} + +/** + * @brief Resets one or more peripheral on the AHB4 bus. + * + * @param[in] mask AHB4 peripherals mask + * + * @api + */ +#define rccResetAHB4(mask) { \ + RCC->AHB4RSTR |= (mask); \ + RCC->AHB4RSTR &= ~(mask); \ + (void)RCC->AHB4RSTR; \ +} +/** @} */ + +/** + * @name ADC peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the ADC1/ADC2 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableADC12(lp) rccEnableAHB1(RCC_AHB1ENR_ADC12EN, lp) + +/** + * @brief Disables the ADC1/ADC2 peripheral clock. + * + * @api + */ +#define rccDisableADC12() rccDisableAHB1(RCC_AHB1ENR_ADC12EN) + +/** + * @brief Resets the ADC1/ADC2 peripheral. + * + * @api + */ +#define rccResetADC12() rccResetAHB1(RCC_AHB1RSTR_ADC12RST) + +/** + * @brief Enables the ADC3 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableADC3(lp) rccEnableAHB4(RCC_AHB4ENR_ADC3EN, lp) + +/** + * @brief Disables the ADC3 peripheral clock. + * + * @api + */ +#define rccDisableADC3() rccDisableAHB4(RCC_AHB4ENR_ADC3EN) + +/** + * @brief Resets the ADC3 peripheral. + * + * @api + */ +#define rccResetADC3() rccResetAHB4(RCC_AHB4RSTR_ADC3RST) +/** @} */ + +/** + * @name DAC peripheral specific RCC operations + * @{ + */ +/** + * @brief Enables the DAC1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableDAC1(lp) rccEnableAPB1L(RCC_APB1LENR_DAC12EN, lp) + +/** + * @brief Disables the DAC1 peripheral clock. + * + * @api + */ +#define rccDisableDAC1() rccDisableAPB1L(RCC_APB1LENR_DAC12EN) + +/** + * @brief Resets the DAC1 peripheral. + * + * @api + */ +#define rccResetDAC1() rccResetAPB1L(RCC_APB1LRSTR_DAC12RST) +/** @} */ + +/** + * @name DMA peripheral specific RCC operations + * @{ + */ +/** + * @brief Enables the BDMA1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableBDMA1(lp) rccEnableAHB4(RCC_AHB4ENR_BDMAEN, lp) + +/** + * @brief Disables the BDMA1 peripheral clock. + * + * @api + */ +#define rccDisableBDMA1() rccDisableAHB4(RCC_AHB4ENR_BDMAEN) + +/** + * @brief Resets the BDMA1 peripheral. + * + * @api + */ +#define rccResetBDMA1() rccResetAHB4(RCC_AHB4RSTR_BDMARST) + +/** + * @brief Enables the DMA1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableDMA1(lp) rccEnableAHB1(RCC_AHB1ENR_DMA1EN, lp) + +/** + * @brief Disables the DMA1 peripheral clock. + * + * @api + */ +#define rccDisableDMA1() rccDisableAHB1(RCC_AHB1ENR_DMA1EN) + +/** + * @brief Resets the DMA1 peripheral. + * + * @api + */ +#define rccResetDMA1() rccResetAHB1(RCC_AHB1RSTR_DMA1RST) + +/** + * @brief Enables the DMA2 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableDMA2(lp) rccEnableAHB1(RCC_AHB1ENR_DMA2EN, lp) + +/** + * @brief Disables the DMA2 peripheral clock. + * + * @api + */ +#define rccDisableDMA2() rccDisableAHB1(RCC_AHB1ENR_DMA2EN) + +/** + * @brief Resets the DMA2 peripheral. + * + * @api + */ +#define rccResetDMA2() rccResetAHB1(RCC_AHB1RSTR_DMA2RST) + +/** + * @brief Enables the MDMA peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableMDMA(lp) rccEnableAHB3(RCC_AHB3ENR_MDMAEN, lp) + +/** + * @brief Disables the MDMA peripheral clock. + * + * @api + */ +#define rccDisableMDMA() rccDisableAHB3(RCC_AHB3ENR_MDMAEN) + +/** + * @brief Resets the MDMA peripheral. + * + * @api + */ +#define rccResetMDMA() rccResetAHB3(RCC_AHB3ENR_MDMARST) +/** @} */ + +/** + * @name RAM specific RCC operations + * @{ + */ +/** + * @brief Enables the BKPRAM clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableBKPRAM(lp) rccEnableAHB4(RCC_AHB4ENR_BKPRAMEN, lp) + +/** + * @brief Disables the BKPRAM clock. + * + * @api + */ +#define rccDisableBKPRAM() rccDisableAHB4(RCC_AHB4ENR_BKPRAMEN) + +/** + * @brief Enables the SRAM1 clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSRAM1(lp) rccEnableAHB2(RCC_AHB2ENR_D2SRAM1EN, lp) + +/** + * @brief Disables the SRAM1 clock. + * + * @api + */ +#define rccDisableSRAM1() rccDisableAHB2(RCC_AHB2ENR_D2SRAM1EN) + +/** + * @brief Enables the SRAM2 clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSRAM2(lp) rccEnableAHB2(RCC_AHB2ENR_D2SRAM2EN, lp) + +/** + * @brief Disables the SRAM2 clock. + * + * @api + */ +#define rccDisableSRAM2() rccDisableAHB2(RCC_AHB2ENR_D2SRAM2EN) + +#if !defined(STM32H723xx) +/** + * @brief Enables the SRAM3 clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSRAM3(lp) rccEnableAHB2(RCC_AHB2ENR_D2SRAM3EN, lp) + +/** + * @brief Disables the SRAM3 clock. + * + * @api + */ +#define rccDisableSRAM3() rccDisableAHB2(RCC_AHB2ENR_D2SRAM3EN) +#endif // !defined(STM32H723xx) +/** @} */ + +/** + * @name ETH peripheral specific RCC operations + * @{ + */ +/** + * @brief Enables the ETH peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableETH(lp) rccEnableAHB1(RCC_AHB1ENR_ETHMACEN | \ + RCC_AHB1ENR_ETHMACTXEN | \ + RCC_AHB1ENR_ETHMACRXEN, lp) + +/** + * @brief Disables the ETH peripheral clock. + * + * @api + */ +#define rccDisableETH() rccDisableAHB1(RCC_AHB1ENR_ETHMACEN | \ + RCC_AHB1ENR_ETHMACTXEN | \ + RCC_AHB1ENR_ETHMACRXEN) + +/** + * @brief Resets the ETH peripheral. + * + * @api + */ +#define rccResetETH() rccResetAHB1(RCC_AHB1RSTR_ETHMACRST) +/** @} */ + +/** + * @name FDCAN peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the FDCAN peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableFDCAN(lp) rccEnableAPB1H(RCC_APB1HENR_FDCANEN, lp) + +/** + * @brief Disables the FDCAN peripheral clock. + * + * @api + */ +#define rccDisableFDCAN() rccDisableAPB1H(RCC_APB1HENR_FDCANEN) + +/** + * @brief Resets the FDCAN peripheral. + * + * @api + */ +#define rccResetFDCAN() rccResetAPB1H(RCC_APB1HRSTR_FDCANRST) +/** @} */ + +/** + * @name I2C peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the I2C1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableI2C1(lp) rccEnableAPB1L(RCC_APB1LENR_I2C1EN, lp) + +/** + * @brief Disables the I2C1 peripheral clock. + * + * @api + */ +#define rccDisableI2C1() rccDisableAPB1L(RCC_APB1LENR_I2C1EN) + +/** + * @brief Resets the I2C1 peripheral. + * + * @api + */ +#define rccResetI2C1() rccResetAPB1L(RCC_APB1LRSTR_I2C1RST) + +/** + * @brief Enables the I2C2 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableI2C2(lp) rccEnableAPB1L(RCC_APB1LENR_I2C2EN, lp) + +/** + * @brief Disables the I2C2 peripheral clock. + * + * @api + */ +#define rccDisableI2C2() rccDisableAPB1L(RCC_APB1LENR_I2C2EN) + +/** + * @brief Resets the I2C2 peripheral. + * + * @api + */ +#define rccResetI2C2() rccResetAPB1L(RCC_APB1LRSTR_I2C2RST) + +/** + * @brief Enables the I2C3 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableI2C3(lp) rccEnableAPB1L(RCC_APB1LENR_I2C3EN, lp) + +/** + * @brief Disables the I2C3 peripheral clock. + * + * @api + */ +#define rccDisableI2C3() rccDisableAPB1L(RCC_APB1LENR_I2C3EN) + +/** + * @brief Resets the I2C3 peripheral. + * + * @api + */ +#define rccResetI2C3() rccResetAPB1L(RCC_APB1LRSTR_I2C3RST) + +/** + * @brief Enables the I2C4 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableI2C4(lp) rccEnableAPB4(RCC_APB4ENR_I2C4EN, lp) + +/** + * @brief Disables the I2C4 peripheral clock. + * + * @api + */ +#define rccDisableI2C4() rccDisableAPB4(RCC_APB4ENR_I2C4EN) + +/** + * @brief Resets the I2C4 peripheral. + * + * @api + */ +#define rccResetI2C4() rccResetAPB4(RCC_APB4RSTR_I2C4RST) +/** @} */ + +/** + * @name OTG peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the USB1_OTG_HS peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUSB1_OTG_HS(lp) rccEnableAHB1(RCC_AHB1ENR_USB1OTGHSEN, lp) + +/** + * @brief Disables the USB1_OTG_HS peripheral clock. + * + * @api + */ +#define rccDisableUSB1_OTG_HS() rccDisableAHB1(RCC_AHB1ENR_USB1OTGHSEN) + +/** + * @brief Resets the USB1_OTG_HS peripheral. + * + * @api + */ +#define rccResetUSB1_OTG_HS() rccResetAHB1(RCC_AHB1RSTR_USB1OTGHSRST) + +#if !defined(STM32H723xx) + +/** + * @brief Enables the USB2_OTG_HS peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUSB2_OTG_HS(lp) rccEnableAHB1(RCC_AHB1ENR_USB2OTGHSEN, lp) + +/** + * @brief Disables the USB2_OTG_HS peripheral clock. + * + * @api + */ +#define rccDisableUSB2_OTG_HS() rccDisableAHB1(RCC_AHB1ENR_USB2OTGHSEN) + +/** + * @brief Resets the USB2_OTG_HS peripheral. + * + * @api + */ +#define rccResetUSB2_OTG_HS() rccResetAHB1(RCC_AHB1RSTR_USB2OTGHSRST) + +#endif // !defined(STM32H723xx) + +/** + * @brief Enables the USB1_OTG_HS ULPI peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUSB1_HSULPI(lp) rccEnableAHB1(RCC_AHB1ENR_USB1OTGHSULPIEN, lp) + +/** + * @brief Disables the USB1_OTG_HS peripheral clock. + * + * @api + */ +#define rccDisableUSB1_HSULPI() rccDisableAHB1(RCC_AHB1ENR_USB1OTGHSULPIEN) + +#if !defined(STM32H723xx) + +/** + * @brief Enables the USB2_OTG_HS ULPI peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUSB2_HSULPI(lp) rccEnableAHB1(RCC_AHB1ENR_USB2OTGHSULPIEN, lp) + +/** + * @brief Disables the USB2_OTG_HS peripheral clock. + * + * @api + */ +#define rccDisableUSB2_HSULPI() rccDisableAHB1(RCC_AHB1ENR_USB2OTGHSULPIEN) + +#endif // !defined(STM32H723xx) +/** @} */ + +/** + * @name QUADSPI peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the QUADSPI1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableQUADSPI1(lp) rccEnableAHB3(RCC_AHB3ENR_QSPIEN, lp) + +/** + * @brief Disables the QUADSPI1 peripheral clock. + * + * @api + */ +#define rccDisableQUADSPI1() rccDisableAHB3(RCC_AHB3ENR_QSPIEN) + +/** + * @brief Resets the QUADSPI1 peripheral. + * + * @api + */ +#define rccResetQUADSPI1() rccResetAHB3(RCC_AHB3RSTR_QSPIRST) +/** @} */ + +/** + * @name RNG peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the RNG peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableRNG(lp) rccEnableAHB2(RCC_AHB2ENR_RNGEN, lp) + +/** + * @brief Disables the RNG peripheral clock. + * + * @api + */ +#define rccDisableRNG() rccDisableAHB2(RCC_AHB2ENR_RNGEN) + +/** + * @brief Resets the RNG peripheral. + * + * @api + */ +#define rccResetRNG() rccResetAHB2(RCC_AHB2RSTR_RNGRST) +/** @} */ + +/** + * @name SDMMC peripheral specific RCC operations + * @{ + */ +/** + * @brief Enables the SDMMC1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSDMMC1(lp) rccEnableAHB3(RCC_AHB3ENR_SDMMC1EN, lp) + +/** + * @brief Disables the SDMMC1 peripheral clock. + * + * @api + */ +#define rccDisableSDMMC1() rccDisableAHB3(RCC_AHB3ENR_SDMMC1EN) + +/** + * @brief Resets the SDMMC1 peripheral. + * + * @api + */ +#define rccResetSDMMC1() rccResetAHB3(RCC_AHB3RSTR_SDMMC1RST) + +/** + * @brief Enables the SDMMC2 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSDMMC2(lp) rccEnableAHB3(RCC_AHB3ENR_SDMMC2EN, lp) + +/** + * @brief Disables the SDMMC2 peripheral clock. + * + * @api + */ +#define rccDisableSDMMC2() rccDisableAHB3(RCC_AHB3ENR_SDMMC2EN) + +/** + * @brief Resets the SDMMC2 peripheral. + * + * @api + */ +#define rccResetSDMMC2() rccResetAHB3(RCC_AHB3RSTR_SDMMC2RST) +/** @} */ + +/** + * @name SPI peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the SPI1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSPI1(lp) rccEnableAPB2(RCC_APB2ENR_SPI1EN, lp) + +/** + * @brief Disables the SPI1 peripheral clock. + * + * @api + */ +#define rccDisableSPI1() rccDisableAPB2(RCC_APB2ENR_SPI1EN) + +/** + * @brief Resets the SPI1 peripheral. + * + * @api + */ +#define rccResetSPI1() rccResetAPB2(RCC_APB2RSTR_SPI1RST) + +/** + * @brief Enables the SPI2 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSPI2(lp) rccEnableAPB1L(RCC_APB1LENR_SPI2EN, lp) + +/** + * @brief Disables the SPI2 peripheral clock. + * + * @api + */ +#define rccDisableSPI2() rccDisableAPB1L(RCC_APB1LENR_SPI2EN) + +/** + * @brief Resets the SPI2 peripheral. + * + * @api + */ +#define rccResetSPI2() rccResetAPB1L(RCC_APB1LRSTR_SPI2RST) + +/** + * @brief Enables the SPI3 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSPI3(lp) rccEnableAPB1L(RCC_APB1LENR_SPI3EN, lp) + +/** + * @brief Disables the SPI3 peripheral clock. + * + * @api + */ +#define rccDisableSPI3() rccDisableAPB1L(RCC_APB1LENR_SPI3EN) + +/** + * @brief Resets the SPI3 peripheral. + * + * @api + */ +#define rccResetSPI3() rccResetAPB1L(RCC_APB1LRSTR_SPI3RST) + +/** + * @brief Enables the SPI4 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSPI4(lp) rccEnableAPB2(RCC_APB2ENR_SPI4EN, lp) + +/** + * @brief Disables the SPI4 peripheral clock. + * + * @api + */ +#define rccDisableSPI4() rccDisableAPB2(RCC_APB2ENR_SPI4EN) + +/** + * @brief Resets the SPI4 peripheral. + * + * @api + */ +#define rccResetSPI4() rccResetAPB2(RCC_APB2RSTR_SPI4RST) + +/** + * @brief Enables the SPI5 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSPI5(lp) rccEnableAPB2(RCC_APB2ENR_SPI5EN, lp) + +/** + * @brief Disables the SPI5 peripheral clock. + * + * @api + */ +#define rccDisableSPI5() rccDisableAPB2(RCC_APB2ENR_SPI5EN) + +/** + * @brief Resets the SPI5 peripheral. + * + * @api + */ +#define rccResetSPI5() rccResetAPB2(RCC_APB2RSTR_SPI5RST) + +/** + * @brief Enables the SPI6 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableSPI6(lp) rccEnableAPB4(RCC_APB4ENR_SPI6EN, lp) + +/** + * @brief Disables the SPI6 peripheral clock. + * + * @api + */ +#define rccDisableSPI6() rccDisableAPB4(RCC_APB4ENR_SPI6EN) + +/** + * @brief Resets the SPI6 peripheral. + * + * @api + */ +#define rccResetSPI6() rccResetAPB4(RCC_APB4RSTR_SPI6RST) +/** @} */ + +/** + * @name TIM peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the TIM1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM1(lp) rccEnableAPB2(RCC_APB2ENR_TIM1EN, lp) + +/** + * @brief Disables the TIM1 peripheral clock. + * + * @api + */ +#define rccDisableTIM1() rccDisableAPB2(RCC_APB2ENR_TIM1EN) + +/** + * @brief Resets the TIM1 peripheral. + * + * @api + */ +#define rccResetTIM1() rccResetAPB2(RCC_APB2RSTR_TIM1RST) + +/** + * @brief Enables the TIM2 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM2(lp) rccEnableAPB1L(RCC_APB1LENR_TIM2EN, lp) + +/** + * @brief Disables the TIM2 peripheral clock. + * + * @api + */ +#define rccDisableTIM2() rccDisableAPB1L(RCC_APB1LENR_TIM2EN) + +/** + * @brief Resets the TIM2 peripheral. + * + * @api + */ +#define rccResetTIM2() rccResetAPB1L(RCC_APB1LRSTR_TIM2RST) + +/** + * @brief Enables the TIM3 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM3(lp) rccEnableAPB1L(RCC_APB1LENR_TIM3EN, lp) + +/** + * @brief Disables the TIM3 peripheral clock. + * + * @api + */ +#define rccDisableTIM3() rccDisableAPB1L(RCC_APB1LENR_TIM3EN) + +/** + * @brief Resets the TIM3 peripheral. + * + * @api + */ +#define rccResetTIM3() rccResetAPB1L(RCC_APB1LRSTR_TIM3RST) + +/** + * @brief Enables the TIM4 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM4(lp) rccEnableAPB1L(RCC_APB1LENR_TIM4EN, lp) + +/** + * @brief Disables the TIM4 peripheral clock. + * + * @api + */ +#define rccDisableTIM4() rccDisableAPB1L(RCC_APB1LENR_TIM4EN) + +/** + * @brief Resets the TIM4 peripheral. + * + * @api + */ +#define rccResetTIM4() rccResetAPB1L(RCC_APB1LRSTR_TIM4RST) + +/** + * @brief Enables the TIM5 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM5(lp) rccEnableAPB1L(RCC_APB1LENR_TIM5EN, lp) + +/** + * @brief Disables the TIM5 peripheral clock. + * + * @api + */ +#define rccDisableTIM5() rccDisableAPB1L(RCC_APB1LENR_TIM5EN) + +/** + * @brief Resets the TIM5 peripheral. + * + * @api + */ +#define rccResetTIM5() rccResetAPB1L(RCC_APB1LRSTR_TIM5RST) + +/** + * @brief Enables the TIM6 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM6(lp) rccEnableAPB1L(RCC_APB1LENR_TIM6EN, lp) + +/** + * @brief Disables the TIM6 peripheral clock. + * + * @api + */ +#define rccDisableTIM6() rccDisableAPB1L(RCC_APB1LENR_TIM6EN) + +/** + * @brief Resets the TIM6 peripheral. + * + * @api + */ +#define rccResetTIM6() rccResetAPB1L(RCC_APB1LRSTR_TIM6RST) + +/** + * @brief Enables the TIM7 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM7(lp) rccEnableAPB1L(RCC_APB1LENR_TIM7EN, lp) + +/** + * @brief Disables the TIM7 peripheral clock. + * + * @api + */ +#define rccDisableTIM7() rccDisableAPB1L(RCC_APB1LENR_TIM7EN) + +/** + * @brief Resets the TIM7 peripheral. + * + * @api + */ +#define rccResetTIM7() rccResetAPB1L(RCC_APB1LRSTR_TIM7RST) + +/** + * @brief Enables the TIM8 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM8(lp) rccEnableAPB2(RCC_APB2ENR_TIM8EN, lp) + +/** + * @brief Disables the TIM8 peripheral clock. + * + * @api + */ +#define rccDisableTIM8() rccDisableAPB2(RCC_APB2ENR_TIM8EN) + +/** + * @brief Resets the TIM8 peripheral. + * + * @api + */ +#define rccResetTIM8() rccResetAPB2(RCC_APB2RSTR_TIM8RST) + +/** + * @brief Enables the TIM12 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM12(lp) rccEnableAPB1L(RCC_APB1LENR_TIM12EN, lp) + +/** + * @brief Disables the TIM12 peripheral clock. + * + * @api + */ +#define rccDisableTIM12() rccDisableAPB1L(RCC_APB1LENR_TIM12EN) + +/** + * @brief Resets the TIM12 peripheral. + * + * @api + */ +#define rccResetTIM12() rccResetAPB1L(RCC_APB1LRSTR_TIM12RST) + +/** + * @brief Enables the TIM13 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM13(lp) rccEnableAPB1L(RCC_APB1LENR_TIM13EN, lp) + +/** + * @brief Disables the TIM13 peripheral clock. + * + * @api + */ +#define rccDisableTIM13() rccDisableAPB1L(RCC_APB1LENR_TIM13EN) + +/** + * @brief Resets the TIM13 peripheral. + * + * @api + */ +#define rccResetTIM13() rccResetAPB1L(RCC_APB1LRSTR_TIM13RST) + +/** + * @brief Enables the TIM14 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM14(lp) rccEnableAPB1L(RCC_APB1LENR_TIM14EN, lp) + +/** + * @brief Disables the TIM14 peripheral clock. + * + * @api + */ +#define rccDisableTIM14() rccDisableAPB1L(RCC_APB1LENR_TIM14EN) + +/** + * @brief Resets the TIM14 peripheral. + * + * @api + */ +#define rccResetTIM14() rccResetAPB1L(RCC_APB1LRSTR_TIM14RST) + +/** + * @brief Enables the TIM15 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM15(lp) rccEnableAPB2(RCC_APB2ENR_TIM15EN, lp) + +/** + * @brief Disables the TIM15 peripheral clock. + * + * @api + */ +#define rccDisableTIM15() rccDisableAPB2(RCC_APB2ENR_TIM15EN) + +/** + * @brief Resets the TIM15 peripheral. + * + * @api + */ +#define rccResetTIM15() rccResetAPB2(RCC_APB2RSTR_TIM15RST) + +/** + * @brief Enables the TIM16 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM16(lp) rccEnableAPB2(RCC_APB2ENR_TIM16EN, lp) + +/** + * @brief Disables the TIM16 peripheral clock. + * + * @api + */ +#define rccDisableTIM16() rccDisableAPB2(RCC_APB2ENR_TIM16EN) + +/** + * @brief Resets the TIM16 peripheral. + * + * @api + */ +#define rccResetTIM16() rccResetAPB2(RCC_APB2RSTR_TIM16RST) + +/** + * @brief Enables the TIM17 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableTIM17(lp) rccEnableAPB2(RCC_APB2ENR_TIM17EN, lp) + +/** + * @brief Disables the TIM17 peripheral clock. + * + * @api + */ +#define rccDisableTIM17() rccDisableAPB2(RCC_APB2ENR_TIM17EN) + +/** + * @brief Resets the TIM17 peripheral. + * + * @api + */ +#define rccResetTIM17() rccResetAPB2(RCC_APB2RSTR_TIM17RST) +/** @} */ + +/** + * @name USART/UART peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the USART1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUSART1(lp) rccEnableAPB2(RCC_APB2ENR_USART1EN, lp) + +/** + * @brief Disables the USART1 peripheral clock. + * + * @api + */ +#define rccDisableUSART1() rccDisableAPB2(RCC_APB2ENR_USART1EN) + +/** + * @brief Resets the USART1 peripheral. + * + * @api + */ +#define rccResetUSART1() rccResetAPB2(RCC_APB2RSTR_USART1RST) + +/** + * @brief Enables the USART2 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUSART2(lp) rccEnableAPB1L(RCC_APB1LENR_USART2EN, lp) + +/** + * @brief Disables the USART2 peripheral clock. + * + * @api + */ +#define rccDisableUSART2() rccDisableAPB1L(RCC_APB1LENR_USART2EN) + +/** + * @brief Resets the USART2 peripheral. + * + * @api + */ +#define rccResetUSART2() rccResetAPB1L(RCC_APB1LRSTR_USART2RST) + +/** + * @brief Enables the USART3 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUSART3(lp) rccEnableAPB1L(RCC_APB1LENR_USART3EN, lp) + +/** + * @brief Disables the USART3 peripheral clock. + * + * @api + */ +#define rccDisableUSART3() rccDisableAPB1L(RCC_APB1LENR_USART3EN) + +/** + * @brief Resets the USART3 peripheral. + * + * @api + */ +#define rccResetUSART3() rccResetAPB1L(RCC_APB1LRSTR_USART3RST) + +/** + * @brief Enables the UART4 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUART4(lp) rccEnableAPB1L(RCC_APB1LENR_UART4EN, lp) + +/** + * @brief Disables the UART4 peripheral clock. + * + * @api + */ +#define rccDisableUART4() rccDisableAPB1L(RCC_APB1LENR_UART4EN) + +/** + * @brief Resets the UART4 peripheral. + * + * @api + */ +#define rccResetUART4() rccResetAPB1L(RCC_APB1LRSTR_UART4RST) + +/** + * @brief Enables the UART5 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUART5(lp) rccEnableAPB1L(RCC_APB1LENR_UART5EN, lp) + +/** + * @brief Disables the UART5 peripheral clock. + * + * @api + */ +#define rccDisableUART5() rccDisableAPB1L(RCC_APB1LENR_UART5EN) + +/** + * @brief Resets the UART5 peripheral. + * + * @api + */ +#define rccResetUART5() rccResetAPB1L(RCC_APB1LRSTR_UART5RST) + +/** + * @brief Enables the USART6 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUSART6(lp) rccEnableAPB2(RCC_APB2ENR_USART6EN, lp) + +/** + * @brief Disables the USART6 peripheral clock. + * + * @api + */ +#define rccDisableUSART6() rccDisableAPB2(RCC_APB2ENR_USART6EN) + +/** + * @brief Resets the USART6 peripheral. + * + * @api + */ +#define rccResetUSART6() rccResetAPB2(RCC_APB2RSTR_USART6RST) + +/** + * @brief Enables the UART7 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUART7(lp) rccEnableAPB1L(RCC_APB1LENR_UART7EN, lp) + +/** + * @brief Disables the UART7 peripheral clock. + * + * @api + */ +#define rccDisableUART7() rccDisableAPB1L(RCC_APB1LENR_UART7EN) + +/** + * @brief Resets the UART7 peripheral. + * + * @api + */ +#define rccResetUART7() rccResetAPB1L(RCC_APB1LRSTR_UART7RST) + +/** + * @brief Enables the UART8 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableUART8(lp) rccEnableAPB1L(RCC_APB1LENR_UART8EN, lp) + +/** + * @brief Disables the UART8 peripheral clock. + * + * @api + */ +#define rccDisableUART8() rccDisableAPB1L(RCC_APB1LENR_UART8EN) + +/** + * @brief Resets the UART8 peripheral. + * + * @api + */ +#define rccResetUART8() rccResetAPB1L(RCC_APB1LRSTR_UART8RST) +/** @} */ + +/** + * @brief Enables the LPUART1 peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableLPUART1(lp) rccEnableAPB4(RCC_APB4ENR_LPUART1EN, lp) + +/** + * @brief Disables the LPUART1 peripheral clock. + * + * @api + */ +#define rccDisableLPUART1() rccDisableAPB4(RCC_APB4ENR_LPUART1EN) + +/** + * @brief Resets the LPUART1 peripheral. + * + * @api + */ +#define rccResetLPUART1() rccResetAPB4(RCC_APB4RSTR_LPUART1RST) +/** @} */ + +/** + * @name LTDC peripheral specific RCC operations + * @{ + */ +/** + * @brief Enables the LTDC peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableLTDC(lp) rccEnableAPB3(RCC_APB3ENR_LTDCEN, lp) + +/** + * @brief Disables the LTDC peripheral clock. +. * + * @api + */ +#define rccDisableLTDC() rccDisableAPB3(RCC_APB3ENR_LTDCEN) + +/** + * @brief Resets the LTDC peripheral. + * + * @api + */ +#define rccResetLTDC() rccResetAPB3(RCC_APB3RSTR_LTDCRST) + +/** + * @name DMA2D peripheral specific RCC operations + * @{ + */ +/** + * @brief Enables the DMA2D peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#define rccEnableDMA2D(lp) rccEnableAHB3(RCC_AHB3ENR_DMA2DEN, lp) + +/** + * @brief Disables the DMA2D peripheral clock. + * + * @api + */ +#define rccDisableDMA2D() rccDisableAHB3(RCC_AHB3ENR_DMA2DEN) + +/** + * @brief Resets the DMA2D peripheral. + * + * @api + */ +#define rccResetDMA2D() rccResetAHB3(RCC_AHB3RSTR_DMA2DRST) +/** @} */ + +/** + * @name FSMC peripherals specific RCC operations + * @{ + */ +/** + * @brief Enables the FSMC peripheral clock. + * + * @param[in] lp low power enable flag + * + * @api + */ +#if defined(STM32_FSMC_IS_FMC) + #define rccEnableFSMC(lp) rccEnableAHB3(RCC_AHB3ENR_FMCEN, lp) +#else + #define rccEnableFSMC(lp) rccEnableAHB3(RCC_AHB3ENR_FSMCEN, lp) +#endif + +/** + * @brief Disables the FSMC peripheral clock. + * + * @api + */ +#if defined(STM32_FSMC_IS_FMC) + #define rccDisableFSMC() rccDisableAHB3(RCC_AHB3ENR_FMCEN) +#else + #define rccDisableFSMC() rccDisableAHB3(RCC_AHB3ENR_FSMCEN) +#endif + +/** + * @brief Resets the FSMC peripheral. + * + * @api + */ +#if defined(STM32_FSMC_IS_FMC) + #define rccResetFSMC() rccResetAHB3(RCC_AHB3RSTR_FMCRST) +#else + #define rccResetFSMC() rccResetAHB3(RCC_AHB3RSTR_FSMCRST) +#endif +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif + +#endif /* STM32_RCC_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_registry.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_registry.h new file mode 100644 index 0000000..51e88e5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_registry.h @@ -0,0 +1,778 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file STM32H7xx/stm32_registry.h + * @brief STM32H7xx capabilities registry. + * + * @addtogroup HAL + * @{ + */ + +#ifndef STM32_REGISTRY_H +#define STM32_REGISTRY_H + +/*===========================================================================*/ +/* Platform capabilities. */ +/*===========================================================================*/ + +/* Cores.*/ +#if defined(STM32H750xx) || defined(STM32H742xx) || \ + defined(STM32H743xx) || defined(STM32H753xx) || \ + defined(STM32H723xx) +#define STM32_HAS_M7 TRUE +#define STM32_HAS_M4 FALSE +#else +#define STM32_HAS_M7 TRUE +#define STM32_HAS_M4 TRUE +#endif + +/** + * @name STM32H7xx capabilities + * @{ + */ + +/*===========================================================================*/ +/* Common. */ +/*===========================================================================*/ + +/* RNG attributes.*/ +#define STM32_HAS_RNG1 TRUE + +/* I2C attributes.*/ +#define STM32_I2C4_USE_BDMA TRUE + +/*===========================================================================*/ +/* STM32H743xx, STM32H753xx, STM32H745xx, STM32H755xx, STM32H747xx, */ +/* STM32H757xx. */ +/*===========================================================================*/ +#if defined(STM32H743xx) || defined(STM32H753xx) || \ + defined(STM32H745xx) || defined(STM32H755xx) || \ + defined(STM32H747xx) || defined(STM32H757xx) || \ + defined(__DOXYGEN__) + +/* ADC attributes.*/ +#define STM32_HAS_ADC1 TRUE +#define STM32_HAS_ADC2 TRUE +#define STM32_HAS_ADC3 TRUE +#define STM32_HAS_ADC4 FALSE + +#define STM32_HAS_SDADC1 FALSE +#define STM32_HAS_SDADC2 FALSE +#define STM32_HAS_SDADC3 FALSE + +/* CAN attributes.*/ +#define STM32_HAS_FDCAN1 TRUE +#define STM32_HAS_FDCAN2 TRUE +#define STM32_HAS_FDCAN3 FALSE +#define STM32_FDCAN_FLS_NBR 128U +#define STM32_FDCAN_FLE_NBR 128U +#define STM32_FDCAN_RF0_NBR 64U +#define STM32_FDCAN_RF1_NBR 64U +#define STM32_FDCAN_RB_NBR 64U +#define STM32_FDCAN_TEF_NBR 32U +#define STM32_FDCAN_TB_NBR 32U +#define STM32_FDCAN_TM_NBR 64U + +/* DAC attributes.*/ +#define STM32_HAS_DAC1_CH1 TRUE +#define STM32_HAS_DAC1_CH2 TRUE +#define STM32_HAS_DAC2_CH1 FALSE +#define STM32_HAS_DAC2_CH2 FALSE + +/* BDMA attributes.*/ +#define STM32_HAS_BDMA1 TRUE + +/* DMA attributes.*/ +#define STM32_ADVANCED_DMA TRUE +#define STM32_DMA_SUPPORTS_DMAMUX TRUE + +#define STM32_HAS_DMA1 TRUE +#define STM32_HAS_DMA2 TRUE + +/* MDMA attributes.*/ +#define STM32_HAS_MDMA1 TRUE + +/* ETH attributes.*/ +#define STM32_HAS_ETH TRUE + +/* EXTI attributes.*/ +#define STM32_EXTI_ENHANCED +#define STM32_EXTI_NUM_LINES 34 +#define STM32_EXTI_IMR1_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU + +/* GPIO attributes.*/ +#define STM32_HAS_GPIOA TRUE +#define STM32_HAS_GPIOB TRUE +#define STM32_HAS_GPIOC TRUE +#define STM32_HAS_GPIOD TRUE +#define STM32_HAS_GPIOE TRUE +#define STM32_HAS_GPIOH TRUE +#define STM32_HAS_GPIOF TRUE +#define STM32_HAS_GPIOG TRUE +#define STM32_HAS_GPIOI TRUE +#define STM32_HAS_GPIOJ TRUE +#define STM32_HAS_GPIOK TRUE +#define STM32_GPIO_EN_MASK (RCC_AHB4ENR_GPIOAEN | \ + RCC_AHB4ENR_GPIOBEN | \ + RCC_AHB4ENR_GPIOCEN | \ + RCC_AHB4ENR_GPIODEN | \ + RCC_AHB4ENR_GPIOEEN | \ + RCC_AHB4ENR_GPIOFEN | \ + RCC_AHB4ENR_GPIOGEN | \ + RCC_AHB4ENR_GPIOHEN | \ + RCC_AHB4ENR_GPIOIEN | \ + RCC_AHB4ENR_GPIOJEN | \ + RCC_AHB4ENR_GPIOKEN) + +/* I2C attributes.*/ +#define STM32_HAS_I2C1 TRUE +#define STM32_HAS_I2C2 TRUE +#define STM32_HAS_I2C3 TRUE +#define STM32_HAS_I2C4 TRUE + +/* QUADSPI attributes.*/ +#define STM32_HAS_QUADSPI1 TRUE +#define STM32_HAS_QUADSPI2 FALSE + +/* RTC attributes.*/ +#define STM32_HAS_RTC TRUE +#define STM32_RTC_HAS_SUBSECONDS TRUE +#define STM32_RTC_HAS_PERIODIC_WAKEUPS TRUE +#define STM32_RTC_NUM_ALARMS 2 +#define STM32_RTC_HAS_INTERRUPTS FALSE + +/* SDMMC attributes.*/ +#define STM32_HAS_SDMMC1 TRUE +#define STM32_HAS_SDMMC2 TRUE + +/* SPI attributes.*/ +#define STM32_HAS_SPI1 TRUE +#define STM32_SPI1_SUPPORTS_I2S TRUE +#define STM32_SPI1_I2S_FULLDUPLEX TRUE + +#define STM32_HAS_SPI2 TRUE +#define STM32_SPI2_SUPPORTS_I2S TRUE +#define STM32_SPI2_I2S_FULLDUPLEX TRUE + +#define STM32_HAS_SPI3 TRUE +#define STM32_SPI3_SUPPORTS_I2S TRUE +#define STM32_SPI3_I2S_FULLDUPLEX TRUE + +#define STM32_HAS_SPI4 TRUE +#define STM32_SPI4_SUPPORTS_I2S FALSE + +#define STM32_HAS_SPI5 TRUE +#define STM32_SPI5_SUPPORTS_I2S FALSE + +#define STM32_HAS_SPI6 TRUE +#define STM32_SPI6_SUPPORTS_I2S FALSE + +/* TIM attributes.*/ +#define STM32_TIM_MAX_CHANNELS 6 + +#define STM32_HAS_TIM1 TRUE +#define STM32_TIM1_IS_32BITS FALSE +#define STM32_TIM1_CHANNELS 6 + +#define STM32_HAS_TIM2 TRUE +#define STM32_TIM2_IS_32BITS TRUE +#define STM32_TIM2_CHANNELS 4 + +#define STM32_HAS_TIM3 TRUE +#define STM32_TIM3_IS_32BITS FALSE +#define STM32_TIM3_CHANNELS 4 + +#define STM32_HAS_TIM4 TRUE +#define STM32_TIM4_IS_32BITS FALSE +#define STM32_TIM4_CHANNELS 4 + +#define STM32_HAS_TIM5 TRUE +#define STM32_TIM5_IS_32BITS TRUE +#define STM32_TIM5_CHANNELS 4 + +#define STM32_HAS_TIM6 TRUE +#define STM32_TIM6_IS_32BITS FALSE +#define STM32_TIM6_CHANNELS 0 + +#define STM32_HAS_TIM7 TRUE +#define STM32_TIM7_IS_32BITS FALSE +#define STM32_TIM7_CHANNELS 0 + +#define STM32_HAS_TIM8 TRUE +#define STM32_TIM8_IS_32BITS FALSE +#define STM32_TIM8_CHANNELS 6 + +#define STM32_HAS_TIM12 TRUE +#define STM32_TIM12_IS_32BITS FALSE +#define STM32_TIM12_CHANNELS 2 + +#define STM32_HAS_TIM13 TRUE +#define STM32_TIM13_IS_32BITS FALSE +#define STM32_TIM13_CHANNELS 1 + +#define STM32_HAS_TIM14 TRUE +#define STM32_TIM14_IS_32BITS FALSE +#define STM32_TIM14_CHANNELS 1 + +#define STM32_HAS_TIM15 FALSE +#define STM32_TIM15_IS_32BITS FALSE +#define STM32_TIM15_CHANNELS 2 + +#define STM32_HAS_TIM16 FALSE +#define STM32_TIM16_IS_32BITS FALSE +#define STM32_TIM16_CHANNELS 1 + +#define STM32_HAS_TIM17 FALSE +#define STM32_TIM17_IS_32BITS FALSE +#define STM32_TIM17_CHANNELS 1 + +#define STM32_HAS_TIM9 FALSE +#define STM32_HAS_TIM10 FALSE +#define STM32_HAS_TIM11 FALSE +#define STM32_HAS_TIM18 FALSE +#define STM32_HAS_TIM19 FALSE +#define STM32_HAS_TIM20 FALSE +#define STM32_HAS_TIM21 FALSE +#define STM32_HAS_TIM22 FALSE + +/* USART attributes.*/ +#define STM32_HAS_USART1 TRUE +#define STM32_HAS_USART2 TRUE +#define STM32_HAS_USART3 TRUE +#define STM32_HAS_UART4 TRUE +#define STM32_HAS_UART5 TRUE +#define STM32_HAS_USART6 TRUE +#define STM32_HAS_UART7 TRUE +#define STM32_HAS_UART8 TRUE +#define STM32_HAS_LPUART1 TRUE + +/* USB attributes.*/ +#define STM32_OTG_STEPPING 2 +#define STM32_HAS_OTG1 TRUE +#define STM32_OTG1_ENDPOINTS 8 + +#define STM32_HAS_OTG2 TRUE +#define STM32_OTG2_ENDPOINTS 8 + +#define STM32_HAS_USB FALSE + +/* IWDG attributes.*/ +#define STM32_HAS_IWDG TRUE +#define STM32_IWDG_IS_WINDOWED TRUE + +/* LTDC attributes.*/ +#define STM32_HAS_LTDC TRUE + +/* DMA2D attributes.*/ +#define STM32_HAS_DMA2D TRUE + +/* FSMC attributes.*/ +#define STM32_HAS_FSMC TRUE +#define STM32_FSMC_IS_FMC TRUE + +/* CRC attributes.*/ +#define STM32_HAS_CRC TRUE +#define STM32_CRC_PROGRAMMABLE TRUE + +/* DCMI attributes.*/ +#define STM32_HAS_DCMI TRUE + +#endif /* defined(STM32H743xx) || defined(STM32H753xx) */ +/** @} */ + +/*===========================================================================*/ +/* STM32H750xx. */ +/*===========================================================================*/ +#if defined(STM32H750xx) || \ + defined(__DOXYGEN__) + +/* ADC attributes.*/ +#define STM32_HAS_ADC1 TRUE +#define STM32_HAS_ADC2 TRUE +#define STM32_HAS_ADC3 FALSE +#define STM32_HAS_ADC4 FALSE + +#define STM32_HAS_SDADC1 FALSE +#define STM32_HAS_SDADC2 FALSE +#define STM32_HAS_SDADC3 FALSE + +/* CAN attributes.*/ +#define STM32_HAS_FDCAN1 TRUE +#define STM32_HAS_FDCAN2 TRUE + +/* DAC attributes.*/ +#define STM32_HAS_DAC1_CH1 TRUE +#define STM32_HAS_DAC1_CH2 TRUE +#define STM32_HAS_DAC2_CH1 FALSE +#define STM32_HAS_DAC2_CH2 FALSE + +/* BDMA attributes.*/ +#define STM32_HAS_BDMA1 TRUE + +/* DMA attributes.*/ +#define STM32_ADVANCED_DMA TRUE +#define STM32_DMA_SUPPORTS_DMAMUX TRUE + +#define STM32_HAS_DMA1 TRUE +#define STM32_HAS_DMA2 TRUE + +/* MDMA attributes.*/ +#define STM32_HAS_MDMA1 TRUE + +/* ETH attributes.*/ +#define STM32_HAS_ETH TRUE + +/* EXTI attributes.*/ +#define STM32_EXTI_ENHANCED +#define STM32_EXTI_NUM_LINES 34 +#define STM32_EXTI_IMR1_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU + +/* GPIO attributes.*/ +#define STM32_HAS_GPIOA TRUE +#define STM32_HAS_GPIOB TRUE +#define STM32_HAS_GPIOC TRUE +#define STM32_HAS_GPIOD TRUE +#define STM32_HAS_GPIOE TRUE +#define STM32_HAS_GPIOH TRUE +#define STM32_HAS_GPIOF TRUE +#define STM32_HAS_GPIOG TRUE +#define STM32_HAS_GPIOI TRUE +#define STM32_HAS_GPIOJ TRUE +#define STM32_HAS_GPIOK TRUE +#define STM32_GPIO_EN_MASK (RCC_AHB4ENR_GPIOAEN | \ + RCC_AHB4ENR_GPIOBEN | \ + RCC_AHB4ENR_GPIOCEN | \ + RCC_AHB4ENR_GPIODEN | \ + RCC_AHB4ENR_GPIOEEN | \ + RCC_AHB4ENR_GPIOFEN | \ + RCC_AHB4ENR_GPIOGEN | \ + RCC_AHB4ENR_GPIOHEN | \ + RCC_AHB4ENR_GPIOIEN | \ + RCC_AHB4ENR_GPIOJEN | \ + RCC_AHB4ENR_GPIOKEN) + +/* I2C attributes.*/ +#define STM32_HAS_I2C1 TRUE +#define STM32_HAS_I2C2 TRUE +#define STM32_HAS_I2C3 TRUE +#define STM32_HAS_I2C4 TRUE + +/* QUADSPI attributes.*/ +#define STM32_HAS_QUADSPI1 TRUE +#define STM32_HAS_QUADSPI2 FALSE + +/* RTC attributes.*/ +#define STM32_HAS_RTC TRUE +#define STM32_RTC_HAS_SUBSECONDS TRUE +#define STM32_RTC_HAS_PERIODIC_WAKEUPS TRUE +#define STM32_RTC_NUM_ALARMS 2 +#define STM32_RTC_HAS_INTERRUPTS FALSE + +/* SDMMC attributes.*/ +#define STM32_HAS_SDMMC1 TRUE +#define STM32_HAS_SDMMC2 TRUE + +/* SPI attributes.*/ +#define STM32_HAS_SPI1 TRUE +#define STM32_SPI1_SUPPORTS_I2S TRUE +#define STM32_SPI1_I2S_FULLDUPLEX TRUE + +#define STM32_HAS_SPI2 TRUE +#define STM32_SPI2_SUPPORTS_I2S TRUE +#define STM32_SPI2_I2S_FULLDUPLEX TRUE + +#define STM32_HAS_SPI3 TRUE +#define STM32_SPI3_SUPPORTS_I2S TRUE +#define STM32_SPI3_I2S_FULLDUPLEX TRUE + +#define STM32_HAS_SPI4 TRUE +#define STM32_SPI4_SUPPORTS_I2S FALSE + +#define STM32_HAS_SPI5 TRUE +#define STM32_SPI5_SUPPORTS_I2S FALSE + +#define STM32_HAS_SPI6 TRUE +#define STM32_SPI6_SUPPORTS_I2S FALSE + +/* TIM attributes.*/ +#define STM32_TIM_MAX_CHANNELS 6 + +#define STM32_HAS_TIM1 TRUE +#define STM32_TIM1_IS_32BITS FALSE +#define STM32_TIM1_CHANNELS 6 + +#define STM32_HAS_TIM2 TRUE +#define STM32_TIM2_IS_32BITS TRUE +#define STM32_TIM2_CHANNELS 4 + +#define STM32_HAS_TIM3 TRUE +#define STM32_TIM3_IS_32BITS FALSE +#define STM32_TIM3_CHANNELS 4 + +#define STM32_HAS_TIM4 TRUE +#define STM32_TIM4_IS_32BITS FALSE +#define STM32_TIM4_CHANNELS 4 + +#define STM32_HAS_TIM5 TRUE +#define STM32_TIM5_IS_32BITS TRUE +#define STM32_TIM5_CHANNELS 4 + +#define STM32_HAS_TIM6 TRUE +#define STM32_TIM6_IS_32BITS FALSE +#define STM32_TIM6_CHANNELS 0 + +#define STM32_HAS_TIM7 TRUE +#define STM32_TIM7_IS_32BITS FALSE +#define STM32_TIM7_CHANNELS 0 + +#define STM32_HAS_TIM8 TRUE +#define STM32_TIM8_IS_32BITS FALSE +#define STM32_TIM8_CHANNELS 6 + +#define STM32_HAS_TIM12 TRUE +#define STM32_TIM12_IS_32BITS FALSE +#define STM32_TIM12_CHANNELS 2 + +#define STM32_HAS_TIM13 TRUE +#define STM32_TIM13_IS_32BITS FALSE +#define STM32_TIM13_CHANNELS 1 + +#define STM32_HAS_TIM14 TRUE +#define STM32_TIM14_IS_32BITS FALSE +#define STM32_TIM14_CHANNELS 1 + +#define STM32_HAS_TIM15 FALSE +#define STM32_TIM15_IS_32BITS FALSE +#define STM32_TIM15_CHANNELS 2 + +#define STM32_HAS_TIM16 FALSE +#define STM32_TIM16_IS_32BITS FALSE +#define STM32_TIM16_CHANNELS 1 + +#define STM32_HAS_TIM17 FALSE +#define STM32_TIM17_IS_32BITS FALSE +#define STM32_TIM17_CHANNELS 1 + +#define STM32_HAS_TIM9 FALSE +#define STM32_HAS_TIM10 FALSE +#define STM32_HAS_TIM11 FALSE +#define STM32_HAS_TIM18 FALSE +#define STM32_HAS_TIM19 FALSE +#define STM32_HAS_TIM20 FALSE +#define STM32_HAS_TIM21 FALSE +#define STM32_HAS_TIM22 FALSE + +/* USART attributes.*/ +#define STM32_HAS_USART1 TRUE +#define STM32_HAS_USART2 TRUE +#define STM32_HAS_USART3 TRUE +#define STM32_HAS_UART4 TRUE +#define STM32_HAS_UART5 TRUE +#define STM32_HAS_USART6 TRUE +#define STM32_HAS_UART7 TRUE +#define STM32_HAS_UART8 TRUE +#define STM32_HAS_LPUART1 TRUE + +/* USB attributes.*/ +#define STM32_OTG_STEPPING 2 +#define STM32_HAS_OTG1 TRUE +#define STM32_OTG1_ENDPOINTS 8 + +#define STM32_HAS_OTG2 TRUE +#define STM32_OTG2_ENDPOINTS 8 + +#define STM32_HAS_USB FALSE + +/* IWDG attributes.*/ +#define STM32_HAS_IWDG TRUE +#define STM32_IWDG_IS_WINDOWED TRUE + +/* LTDC attributes.*/ +#define STM32_HAS_LTDC TRUE + +/* DMA2D attributes.*/ +#define STM32_HAS_DMA2D TRUE + +/* FSMC attributes.*/ +#define STM32_HAS_FSMC TRUE +#define STM32_FSMC_IS_FMC TRUE + +/* CRC attributes.*/ +#define STM32_HAS_CRC TRUE +#define STM32_CRC_PROGRAMMABLE TRUE + +/* DCMI attributes.*/ +#define STM32_HAS_DCMI TRUE + +#endif /* defined(STM32H750xx) */ + +/*===========================================================================*/ +/* STM32H723xx. */ +/*===========================================================================*/ +#if defined(STM32H723xx) || defined(__DOXYGEN__) + +/* ADC attributes.*/ +#define STM32_HAS_ADC1 TRUE +#define STM32_HAS_ADC2 TRUE +#define STM32_HAS_ADC3 TRUE +#define STM32_HAS_ADC4 FALSE + +#define STM32_HAS_SDADC1 FALSE +#define STM32_HAS_SDADC2 FALSE +#define STM32_HAS_SDADC3 FALSE + +/* CAN attributes.*/ +#define STM32_HAS_FDCAN1 TRUE +#define STM32_HAS_FDCAN2 TRUE +#define STM32_HAS_FDCAN3 FALSE +#define STM32_FDCAN_FLS_NBR 128U +#define STM32_FDCAN_FLE_NBR 128U +#define STM32_FDCAN_RF0_NBR 64U +#define STM32_FDCAN_RF1_NBR 64U +#define STM32_FDCAN_RB_NBR 64U +#define STM32_FDCAN_TEF_NBR 32U +#define STM32_FDCAN_TB_NBR 32U +#define STM32_FDCAN_TM_NBR 64U + +/* DAC attributes.*/ +#define STM32_HAS_DAC1_CH1 TRUE +#define STM32_HAS_DAC1_CH2 TRUE +#define STM32_HAS_DAC2_CH1 FALSE +#define STM32_HAS_DAC2_CH2 FALSE + +/* BDMA attributes.*/ +#define STM32_HAS_BDMA1 TRUE + +/* DMA attributes.*/ +#define STM32_ADVANCED_DMA TRUE +#define STM32_DMA_SUPPORTS_DMAMUX TRUE + +#define STM32_HAS_DMA1 TRUE +#define STM32_HAS_DMA2 TRUE + +/* MDMA attributes.*/ +#define STM32_HAS_MDMA1 TRUE + +/* ETH attributes.*/ +#define STM32_HAS_ETH TRUE + +/* EXTI attributes.*/ +#define STM32_EXTI_ENHANCED +#define STM32_EXTI_NUM_LINES 34 +#define STM32_EXTI_IMR1_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU + +/* GPIO attributes.*/ +#define STM32_HAS_GPIOA TRUE +#define STM32_HAS_GPIOB TRUE +#define STM32_HAS_GPIOC TRUE +#define STM32_HAS_GPIOD TRUE +#define STM32_HAS_GPIOE TRUE +#define STM32_HAS_GPIOH TRUE +#define STM32_HAS_GPIOF TRUE +#define STM32_HAS_GPIOG TRUE +#define STM32_HAS_GPIOI FALSE +#define STM32_HAS_GPIOJ TRUE +#define STM32_HAS_GPIOK TRUE +#define STM32_GPIO_EN_MASK (RCC_AHB4ENR_GPIOAEN | \ + RCC_AHB4ENR_GPIOBEN | \ + RCC_AHB4ENR_GPIOCEN | \ + RCC_AHB4ENR_GPIODEN | \ + RCC_AHB4ENR_GPIOEEN | \ + RCC_AHB4ENR_GPIOFEN | \ + RCC_AHB4ENR_GPIOGEN | \ + RCC_AHB4ENR_GPIOHEN | \ + RCC_AHB4ENR_GPIOJEN | \ + RCC_AHB4ENR_GPIOKEN) + +/* I2C attributes.*/ +#define STM32_HAS_I2C1 TRUE +#define STM32_HAS_I2C2 TRUE +#define STM32_HAS_I2C3 TRUE +#define STM32_HAS_I2C4 TRUE +#define STM32_HAS_I2C5 TRUE + +/* QUADSPI attributes.*/ +#define STM32_HAS_QUADSPI1 FALSE +#define STM32_HAS_QUADSPI2 FALSE + +/* OCTOSPI attributes.*/ +#define STM32_HAS_OCTOSPI1 TRUE +#define STM32_HAS_OCTOSPI2 TRUE + +/* RTC attributes.*/ +#define STM32_HAS_RTC TRUE +#define STM32_RTC_HAS_SUBSECONDS TRUE +#define STM32_RTC_HAS_PERIODIC_WAKEUPS TRUE +#define STM32_RTC_NUM_ALARMS 2 +#define STM32_RTC_HAS_INTERRUPTS FALSE + +/* SDMMC attributes.*/ +#define STM32_HAS_SDMMC1 TRUE +#define STM32_HAS_SDMMC2 TRUE + +/* SPI attributes.*/ +#define STM32_HAS_SPI1 TRUE +#define STM32_SPI1_SUPPORTS_I2S TRUE +#define STM32_SPI1_I2S_FULLDUPLEX TRUE + +#define STM32_HAS_SPI2 TRUE +#define STM32_SPI2_SUPPORTS_I2S TRUE +#define STM32_SPI2_I2S_FULLDUPLEX TRUE + +#define STM32_HAS_SPI3 TRUE +#define STM32_SPI3_SUPPORTS_I2S TRUE +#define STM32_SPI3_I2S_FULLDUPLEX TRUE + +#define STM32_HAS_SPI4 TRUE +#define STM32_SPI4_SUPPORTS_I2S FALSE + +#define STM32_HAS_SPI5 TRUE +#define STM32_SPI5_SUPPORTS_I2S FALSE + +#define STM32_HAS_SPI6 TRUE +#define STM32_SPI6_SUPPORTS_I2S TRUE +#define STM32_SPI6_I2S_FULLDUPLEX TRUE + +/* TIM attributes.*/ +#define STM32_TIM_MAX_CHANNELS 6 + +#define STM32_HAS_TIM1 TRUE +#define STM32_TIM1_IS_32BITS FALSE +#define STM32_TIM1_CHANNELS 6 + +#define STM32_HAS_TIM2 TRUE +#define STM32_TIM2_IS_32BITS TRUE +#define STM32_TIM2_CHANNELS 4 + +#define STM32_HAS_TIM3 TRUE +#define STM32_TIM3_IS_32BITS FALSE +#define STM32_TIM3_CHANNELS 4 + +#define STM32_HAS_TIM4 TRUE +#define STM32_TIM4_IS_32BITS FALSE +#define STM32_TIM4_CHANNELS 4 + +#define STM32_HAS_TIM5 TRUE +#define STM32_TIM5_IS_32BITS TRUE +#define STM32_TIM5_CHANNELS 4 + +#define STM32_HAS_TIM6 TRUE +#define STM32_TIM6_IS_32BITS FALSE +#define STM32_TIM6_CHANNELS 0 + +#define STM32_HAS_TIM7 TRUE +#define STM32_TIM7_IS_32BITS FALSE +#define STM32_TIM7_CHANNELS 0 + +#define STM32_HAS_TIM8 TRUE +#define STM32_TIM8_IS_32BITS FALSE +#define STM32_TIM8_CHANNELS 6 + +#define STM32_HAS_TIM12 TRUE +#define STM32_TIM12_IS_32BITS FALSE +#define STM32_TIM12_CHANNELS 2 + +#define STM32_HAS_TIM13 TRUE +#define STM32_TIM13_IS_32BITS FALSE +#define STM32_TIM13_CHANNELS 1 + +#define STM32_HAS_TIM14 TRUE +#define STM32_TIM14_IS_32BITS FALSE +#define STM32_TIM14_CHANNELS 1 + +#define STM32_HAS_TIM15 TRUE +#define STM32_TIM15_IS_32BITS FALSE +#define STM32_TIM15_CHANNELS 2 + +#define STM32_HAS_TIM16 TRUE +#define STM32_TIM16_IS_32BITS FALSE +#define STM32_TIM16_CHANNELS 1 + +#define STM32_HAS_TIM17 TRUE +#define STM32_TIM17_IS_32BITS FALSE +#define STM32_TIM17_CHANNELS 1 + +#define STM32_HAS_TIM23 TRUE +#define STM32_TIM23_IS_32BITS TRUE +#define STM32_TIM23_CHANNELS 4 + +#define STM32_HAS_TIM24 TRUE +#define STM32_TIM24_IS_32BITS TRUE +#define STM32_TIM24_CHANNELS 4 + +#define STM32_HAS_TIM9 FALSE +#define STM32_HAS_TIM10 FALSE +#define STM32_HAS_TIM11 FALSE +#define STM32_HAS_TIM18 FALSE +#define STM32_HAS_TIM19 FALSE +#define STM32_HAS_TIM20 FALSE +#define STM32_HAS_TIM21 FALSE +#define STM32_HAS_TIM22 FALSE + +/* USART attributes.*/ +#define STM32_HAS_USART1 TRUE +#define STM32_HAS_USART2 TRUE +#define STM32_HAS_USART3 TRUE +#define STM32_HAS_UART4 TRUE +#define STM32_HAS_UART5 TRUE +#define STM32_HAS_USART6 TRUE +#define STM32_HAS_UART7 TRUE +#define STM32_HAS_UART8 TRUE +#define STM32_HAS_UART9 TRUE +#define STM32_HAS_USART10 TRUE +#define STM32_HAS_LPUART1 TRUE + +/* USB attributes.*/ +#define STM32_OTG_STEPPING 2 +#define STM32_HAS_OTG1 TRUE +#define STM32_OTG1_ENDPOINTS 8 + +#define STM32_HAS_OTG2 TRUE +#define STM32_OTG2_ENDPOINTS 8 + +#define STM32_HAS_USB FALSE + +/* IWDG attributes.*/ +#define STM32_HAS_IWDG TRUE +#define STM32_IWDG_IS_WINDOWED TRUE + +/* LTDC attributes.*/ +#define STM32_HAS_LTDC TRUE + +/* DMA2D attributes.*/ +#define STM32_HAS_DMA2D TRUE + +/* FSMC attributes.*/ +#define STM32_HAS_FSMC TRUE +#define STM32_FSMC_IS_FMC TRUE + +/* CRC attributes.*/ +#define STM32_HAS_CRC TRUE +#define STM32_CRC_PROGRAMMABLE TRUE + +/* DCMI attributes.*/ +#define STM32_HAS_DCMI TRUE + +#endif /* defined(STM32H723xx) */ +/** @} */ + +#endif /* STM32_REGISTRY_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/todo.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/todo.txt new file mode 100644 index 0000000..c30cafc --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/todo.txt @@ -0,0 +1,4 @@ +- BOFF handling in DACv1. +- Oversampling support for ADCv1 and ADCv3. +- Implement missing ICU/PWM/GPT/ST units using shared IRQ handlers. +- Implement I2S driver over SAI interfaces. -- cgit v1.2.3