fix(h7): common drivers for H7 support (#6149)

Co-authored-by: raphaelcoeffic <1050031+raphaelcoeffic@users.noreply.github.com>
This commit is contained in:
richardclli
2025-05-03 20:26:10 +10:00
committed by GitHub
co-authored by raphaelcoeffic
parent 46f3716995
commit 706a092bc2
8 changed files with 672 additions and 158 deletions
@@ -100,10 +100,23 @@ if(NOT NATIVE_BUILD)
${STM32_DRIVER_DIR}/stm32_timer.cpp
${STM32_DRIVER_DIR}/stm32_dma.cpp
${STM32_DRIVER_DIR}/stm32_gpio.cpp
${STM32_DRIVER_DIR}/stm32_spi.cpp
${STM32_DRIVER_DIR}/stm32_adc.cpp
)
if(CPU_TYPE STREQUAL STM32F2)
target_sources(stm32_drivers PUBLIC
${STM32_DRIVER_DIR}/stm32_spi.cpp
)
elseif(CPU_TYPE STREQUAL STM32F4)
target_sources(stm32_drivers PUBLIC
${STM32_DRIVER_DIR}/stm32_spi.cpp
)
elseif(CPU_TYPE STREQUAL STM32H7 OR CPU_TYPE STREQUAL STM32H7RS)
target_sources(stm32_drivers PUBLIC
${STM32_DRIVER_DIR}/stm32_spi_h7.cpp
)
endif()
# HAL/LL drivers using TRACE
add_library(stm32_drivers_w_dbg_fw OBJECT EXCLUDE_FROM_ALL
${STM32_DRIVER_DIR}/sdcard_spi.cpp
@@ -29,8 +29,56 @@
#include "edgetx.h"
const AudioBuffer * nextBuffer = nullptr;
#if defined(STM32H5) || defined(STM32H7) || defined(STM32H7RS)
// 16 bit, 1 channels
#define DMA_BUFFER_HALF_LEN AUDIO_BUFFER_SIZE
// 2 buffers
#define DMA_BUFFER_LEN (DMA_BUFFER_HALF_LEN * 2)
static uint16_t _dma_buffer[DMA_BUFFER_LEN] __DMA_NO_CACHE;
static volatile uint32_t _dma_buffer_offset = 0;
static inline uint32_t _calc_offset(uint8_t tc)
{
return tc * DMA_BUFFER_HALF_LEN;
}
// the returned bool is true when there is no more data available
static bool audio_update_dma_buffer(uint8_t tc)
{
_dma_buffer_offset = _calc_offset(tc);
auto buffer = audioQueue.buffersFifo.getNextFilledBuffer();
nextBuffer = buffer;
if (!buffer) {
unsigned idx = 0;
for (; idx < DMA_BUFFER_HALF_LEN; idx++) {
uint32_t offset = _dma_buffer_offset + idx;
_dma_buffer[offset] = AUDIO_DATA_SILENCE;
}
return true;
} else {
unsigned idx = 0;
for (; idx < buffer->size; idx++) {
uint32_t offset = _dma_buffer_offset + idx;
_dma_buffer[offset] = (uint16_t)buffer->data[idx];
}
for (; idx < DMA_BUFFER_HALF_LEN; idx++) {
uint32_t offset = _dma_buffer_offset + idx;
_dma_buffer[offset] = AUDIO_DATA_SILENCE;
}
audioQueue.buffersFifo.freeNextFilledBuffer();
return false;
}
}
#else
#define AUDIO_DAC DAC
#endif
// Init timer that triggers the DAC conversion
// at sampling frequency
@@ -96,6 +144,26 @@ void dacInit()
gpio_init_analog(AUDIO_OUTPUT_GPIO);
stm32_dma_enable_clock(AUDIO_DMA);
#if defined(STM32H5) || defined(STM32H7) || defined(STM32H7RS)
LL_DMA_DeInit(AUDIO_DMA, AUDIO_DMA_Stream);
LL_DMA_InitTypeDef dmaInit;
LL_DMA_StructInit(&dmaInit);
#if defined(STM32H7)
dmaInit.Mode = LL_DMA_MODE_CIRCULAR;
dmaInit.PeriphRequest = AUDIO_DMA_Channel;
dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH;
dmaInit.PeriphOrM2MSrcAddress = LL_DAC_DMA_GetRegAddr(DAC1, LL_DAC_CHANNEL_1, LL_DAC_DMA_REG_DATA_12BITS_LEFT_ALIGNED);
dmaInit.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD;
dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dmaInit.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
#elif defined(STM32H7RS)
#error not implemented
#endif
LL_DMA_Init(AUDIO_DMA, AUDIO_DMA_Stream, &dmaInit);
#else
// Disable DMA stream
AUDIO_DMA_Stream->CR &= ~DMA_SxCR_EN;
@@ -110,23 +178,34 @@ void dacInit()
DMA_SxCR_CIRC;
// write to DAC channel 1 (12 bits, left-aligned)
AUDIO_DMA_Stream->PAR = CONVERT_PTR_UINT(&DAC->DHR12L1);
AUDIO_DMA_Stream->PAR = CONVERT_PTR_UINT(&AUDIO_DAC->DHR12L1);
// disable direct mode and set FIFO threshold to half
AUDIO_DMA_Stream->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0;
#endif
#if defined(LL_APB1_GRP1_PERIPH_DAC12)
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_DAC12);
#else
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_DAC1);
#endif
// set data registre to silence
DAC->DHR12L1 = AUDIO_DATA_SILENCE;
AUDIO_DAC->DHR12L1 = AUDIO_DATA_SILENCE;
#if defined(STM32H5) || defined(STM32H7) || defined(STM32H7RS)
LL_DAC_ClearFlag_DMAUDR1(AUDIO_DAC);
LL_DAC_SetTriggerSource(AUDIO_DAC, LL_DAC_CHANNEL_1, LL_DAC_TRIG_EXT_TIM6_TRGO);
LL_DAC_EnableTrigger(AUDIO_DAC, LL_DAC_CHANNEL_1);
LL_DAC_Enable(AUDIO_DAC, LL_DAC_CHANNEL_1);
#else
// clear underrun flag
DAC->SR = DAC_SR_DMAUDR1;
AUDIO_DAC->SR = DAC_SR_DMAUDR1;
// use TIM6 TRGO as trigger (TSEL1 = TSEL2 = 000)
// enable DAC & channel 1 trigger
DAC->CR = DAC_CR_TEN1 | DAC_CR_EN1;
AUDIO_DAC->CR = DAC_CR_TEN1 | DAC_CR_EN1;
#endif
NVIC_EnableIRQ(AUDIO_DMA_Stream_IRQn);
NVIC_SetPriority(AUDIO_DMA_Stream_IRQn, 7);
}
@@ -175,6 +254,25 @@ void audioUnmute()
void audioConsumeCurrentBuffer()
{
#if defined(STM32H5) || defined(STM32H7) || defined(STM32H7RS)
if (!LL_DMA_IsEnabledStream(AUDIO_DMA, AUDIO_DMA_Stream)) {
if (!audio_update_dma_buffer(0)) {
#if defined(AUDIO_MUTE_GPIO)
audioUnmute();
#endif
LL_DMA_DisableStream(AUDIO_DMA, AUDIO_DMA_Stream);
stm32_dma_check_tc_flag(AUDIO_DMA, AUDIO_DMA_Stream);
stm32_dma_check_ht_flag(AUDIO_DMA, AUDIO_DMA_Stream);
LL_DAC_ClearFlag_DMAUDR1(AUDIO_DAC);
LL_DAC_EnableDMAReq(AUDIO_DAC, LL_DAC_CHANNEL_1);
LL_DAC_Enable(AUDIO_DAC, LL_DAC_CHANNEL_1);
LL_DMA_SetMemoryAddress(AUDIO_DMA, AUDIO_DMA_Stream, (intptr_t)_dma_buffer);
LL_DMA_SetDataLength(AUDIO_DMA, AUDIO_DMA_Stream, DMA_BUFFER_LEN);
LL_DMA_EnableStream(AUDIO_DMA, AUDIO_DMA_Stream);
LL_DMA_EnableIT_HT(AUDIO_DMA, AUDIO_DMA_Stream);
LL_DMA_EnableIT_TC(AUDIO_DMA, AUDIO_DMA_Stream);
#else
if (!nextBuffer) {
nextBuffer = audioQueue.buffersFifo.getNextFilledBuffer();
if (nextBuffer) {
@@ -182,7 +280,6 @@ void audioConsumeCurrentBuffer()
#if defined(AUDIO_MUTE_GPIO)
audioUnmute();
#endif
// Disable DMA stream
AUDIO_DMA_Stream->CR &= ~DMA_SxCR_EN;
@@ -199,11 +296,11 @@ void audioConsumeCurrentBuffer()
AUDIO_DMA_Stream->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE;
// clear underrun flag
DAC->SR = DAC_SR_DMAUDR1;
AUDIO_DAC->SR = DAC_SR_DMAUDR1;
// enable DAC
DAC->CR |= DAC_CR_EN1 | DAC_CR_DMAEN1;
AUDIO_DAC->CR |= DAC_CR_EN1 | DAC_CR_DMAEN1;
#endif
} else {
#if defined(AUDIO_MUTE_GPIO)
audioMute();
@@ -220,7 +317,7 @@ void audioInit()
void audioEnd()
{
DAC->CR = 0;
AUDIO_DAC->CR = 0;
AUDIO_TIMER->CR1 = 0;
// Also need to turn off any possible interrupts
@@ -230,6 +327,23 @@ void audioEnd()
extern "C" void AUDIO_DMA_Stream_IRQHandler()
{
#if defined(STM32H5) || defined(STM32H7) || defined(STM32H7RS)
bool stopDMA = false;
if(stm32_dma_check_ht_flag(AUDIO_DMA, AUDIO_DMA_Stream)) {
stopDMA = audio_update_dma_buffer(0);
}
if(stm32_dma_check_tc_flag(AUDIO_DMA, AUDIO_DMA_Stream)) {
stopDMA |= audio_update_dma_buffer(1);
}
if(stopDMA) {
LL_DMA_DisableIT_TC(AUDIO_DMA, AUDIO_DMA_Stream);
LL_DMA_DisableIT_HT(AUDIO_DMA, AUDIO_DMA_Stream);
LL_DMA_DisableStream(AUDIO_DMA, AUDIO_DMA_Stream);
}
#else
// disable transfer complete interrupt
AUDIO_DMA_Stream->CR &= ~DMA_SxCR_TCIE;
@@ -256,6 +370,7 @@ extern "C" void AUDIO_DMA_Stream_IRQHandler()
AUDIO_DMA_Stream->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE;
// clear underrun flag
DAC->SR = DAC_SR_DMAUDR1;
AUDIO_DAC->SR = DAC_SR_DMAUDR1;
}
#endif
}
@@ -39,7 +39,7 @@
#define ON_DETENT(p) ((p == 3) || (p == 0))
#elif ROTARY_ENCODER_GRANULARITY == 4
#define ON_DETENT(p) (p == 3)
#elif
#else
#error "Unknown ROTARY_ENCODER_GRANULARITY"
#endif
@@ -23,6 +23,9 @@
#include "stm32_spi.h"
#include "timers_driver.h"
#include "delays_driver.h"
#include "stm32_gpio.h"
#include "stm32_hal_ll.h"
#include "debug.h"
#include "crc.h"
@@ -244,6 +247,12 @@ static uint8_t sdcard_spi_send_acmd(const stm32_spi_t* spi, uint8_t sd_cmd_idx,
static sd_rw_response_t _read_cid(const stm32_spi_t* spi, sdcard_info_t* card);
static sd_rw_response_t _read_csd(const stm32_spi_t* spi, sdcard_info_t* card);
static inline void _set_miso_pullup(gpio_t miso)
{
uint32_t pin = 1 << gpio_get_pin(miso);
LL_GPIO_SetPinPull(gpio_get_port(miso), pin, LL_GPIO_PULL_UP);
}
static sd_init_fsm_state_t _init_sd_fsm_step(const stm32_spi_t* spi,
sdcard_info_t* card,
sd_init_fsm_state_t state)
@@ -251,8 +260,9 @@ static sd_init_fsm_state_t _init_sd_fsm_step(const stm32_spi_t* spi,
switch (state) {
case SD_INIT_START:
TRACE("SD_INIT_START");
stm32_spi_init(spi, LL_SPI_DATAWIDTH_8BIT, true);
stm32_spi_init(spi, LL_SPI_DATAWIDTH_8BIT);
stm32_spi_set_max_baudrate(spi, SD_SPI_CLK_400K);
_set_miso_pullup(spi->MISO);
return SD_INIT_SPI_POWER_SEQ;
case SD_INIT_SPI_POWER_SEQ:
@@ -64,6 +64,7 @@ extern "C" {
#include "STM32F2xx_HAL_Driver/Inc/stm32f2xx_ll_usb.h"
#elif defined(STM32H7)
#include "STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_bus.h"
#include "STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_dac.h"
#include "STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_fmc.h"
#include "STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_dma2d.h"
#include "STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_gpio.h"
+12 -137
View File
@@ -75,41 +75,11 @@ static inline uint32_t _get_spi_af(SPI_TypeDef *SPIx)
return LL_GPIO_AF_5;
}
#if defined(STM32H7) || defined(STM32H7RS)
static inline uint32_t _get_spi_clocksource(SPI_TypeDef* SPIx)
{
#if defined(LL_RCC_SPI123_CLKSOURCE)
return LL_RCC_SPI123_CLKSOURCE;
#endif
#if defined(LL_RCC_SPI1_CLKSOURCE)
if (SPIx == SPI1) return LL_RCC_SPI1_CLKSOURCE;
#endif
#if defined(LL_RCC_SPI23_CLKSOURCE)
if (SPIx == SPI2 || SPIx == SPI3) return LL_RCC_SPI23_CLKSOURCE;
#endif
#if defined(LL_RCC_SPI45_CLKSOURCE)
if (SPIx == SPI4 || SPIx == SPI5) return LL_RCC_SPI45_CLKSOURCE;
#endif
#if defined(LL_RCC_SPI6_CLKSOURCE)
if (SPIx == SPI6) return LL_RCC_SPI6_CLKSOURCE;
#endif
return 0;
}
#endif
static uint32_t _get_spi_prescaler(SPI_TypeDef *SPIx, uint32_t max_freq)
{
LL_RCC_ClocksTypeDef RCC_Clocks;
LL_RCC_GetSystemClocksFreq(&RCC_Clocks);
#if defined(STM32H7) || defined(STM32H7RS)
uint32_t pclk = LL_RCC_GetSPIClockFreq(_get_spi_clocksource(SPIx));
#else
uint32_t pclk = RCC_Clocks.PCLK2_Frequency;
#if defined(SPI2)
if (SPIx == SPI2) {
@@ -121,7 +91,6 @@ static uint32_t _get_spi_prescaler(SPI_TypeDef *SPIx, uint32_t max_freq)
pclk = RCC_Clocks.PCLK1_Frequency;
}
#endif
#endif // STM32H7 || STM32H7RS
uint32_t divider = (pclk + max_freq) / max_freq;
uint32_t presc;
if (divider > 128) {
@@ -145,18 +114,11 @@ static uint32_t _get_spi_prescaler(SPI_TypeDef *SPIx, uint32_t max_freq)
return presc;
}
static void _init_gpios(const stm32_spi_t* spi, bool enableMisoPullUp)
static void _init_gpios(const stm32_spi_t* spi)
{
if(enableMisoPullUp)
{
gpio_init(spi->MISO, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(spi->MISO, _get_spi_af(spi->SPIx));
} else {
gpio_init_af(spi->MISO, _get_spi_af(spi->SPIx), GPIO_PIN_SPEED_VERY_HIGH);
}
gpio_init_af(spi->MISO, _get_spi_af(spi->SPIx), GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(spi->SCK, _get_spi_af(spi->SPIx), GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(spi->MOSI, _get_spi_af(spi->SPIx), GPIO_PIN_SPEED_VERY_HIGH);
gpio_init(spi->CS, GPIO_OUT, GPIO_PIN_SPEED_HIGH);
}
@@ -170,55 +132,25 @@ static void _config_dma_streams(const stm32_spi_t* spi)
LL_DMA_InitTypeDef dmaInit;
LL_DMA_StructInit(&dmaInit);
#if defined(STM32F2) || defined(STM32F4)
dmaInit.Channel = spi->DMA_Channel;
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRegAddr(spi->SPIx);
#endif
#if defined(STM32F2) || defined(STM32F4) || defined(STM32H7)
dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH;
dmaInit.FIFOMode = spi->DMA_FIFOMode;
dmaInit.FIFOThreshold = spi->DMA_FIFOThreshold;
dmaInit.MemoryOrM2MDstDataSize = spi->DMA_MemoryOrM2MDstDataSize;
dmaInit.MemBurst = spi->DMA_MemBurst;
#elif defined(STM32H7RS)
dmaInit.Priority = LL_DMA_LOW_PRIORITY_HIGH_WEIGHT;
#endif
#if defined(STM32H7)
dmaInit.PeriphRequest = spi->rxDMA_PeriphRequest;
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
#elif defined(STM32H7RS)
dmaInit.Request = spi->rxDMA_PeriphRequest;
dmaInit.SrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
dmaInit.SrcIncMode = LL_DMA_SRC_FIXED;
dmaInit.DestIncMode = LL_DMA_DEST_INCREMENT;
dmaInit.DestDataWidth = LL_DMA_DEST_DATAWIDTH_HALFWORD; // TODO
#endif
dmaInit.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
LL_DMA_Init(spi->DMA, spi->rxDMA_Stream, &dmaInit);
#if defined(STM32H7)
dmaInit.PeriphRequest = spi->txDMA_PeriphRequest;
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
#elif defined(STM32H7RS)
dmaInit.Request = spi->rxDMA_PeriphRequest;
dmaInit.DestAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
dmaInit.SrcIncMode = LL_DMA_SRC_INCREMENT;
dmaInit.DestIncMode = LL_DMA_DEST_FIXED;
dmaInit.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_HALFWORD; // TODO
#endif
dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
LL_DMA_Init(spi->DMA, spi->txDMA_Stream, &dmaInit);
}
#endif
void stm32_spi_init(const stm32_spi_t* spi, uint32_t data_width, bool misoPullUp)
void stm32_spi_init(const stm32_spi_t* spi, uint32_t data_width)
{
_init_gpios(spi, misoPullUp);
_init_gpios(spi);
auto SPIx = spi->SPIx;
stm32_spi_enable_clock(SPIx);
@@ -234,9 +166,6 @@ void stm32_spi_init(const stm32_spi_t* spi, uint32_t data_width, bool misoPullUp
LL_SPI_Init(SPIx, &spiInit);
LL_SPI_Enable(SPIx);
#if defined(STM32H7) || defined(STM32H7RS)
LL_SPI_StartMasterTransfer(SPIx);
#endif
#if defined(USE_SPI_DMA)
if (spi->DMA) {
@@ -245,8 +174,6 @@ void stm32_spi_init(const stm32_spi_t* spi, uint32_t data_width, bool misoPullUp
#endif
}
// void stm32_spi_deinit(const stm32_spi_t* spi);
void stm32_spi_select(const stm32_spi_t* spi)
{
gpio_clear(spi->CS);
@@ -261,36 +188,22 @@ void stm32_spi_set_max_baudrate(const stm32_spi_t* spi, uint32_t baudrate)
{
auto* SPIx = spi->SPIx;
uint32_t presc = _get_spi_prescaler(SPIx, baudrate);
#if defined(STM32H7) || defined(STM32H7RS)
LL_SPI_Disable(SPIx);
#endif
LL_SPI_SetBaudRatePrescaler(SPIx, presc);
#if defined(STM32H7) || defined(STM32H7RS)
LL_SPI_Enable(SPIx);
LL_SPI_StartMasterTransfer(SPIx);
#endif
}
uint8_t stm32_spi_transfer_byte(const stm32_spi_t* spi, uint8_t out)
{
auto* SPIx = spi->SPIx;
#if defined(STM32H7) || defined(STM32H7RS)
while (!LL_SPI_IsActiveFlag_TXP(SPIx));
#else
while (!LL_SPI_IsActiveFlag_TXE(SPIx));
#endif
LL_SPI_TransmitData8(SPIx, out);
#if defined(STM32H7) || defined(STM32H7RS)
while (!LL_SPI_IsActiveFlag_RXP(SPIx));
#else
while (!LL_SPI_IsActiveFlag_RXNE(SPIx));
#endif
return LL_SPI_ReceiveData8(SPIx);
}
uint16_t stm32_spi_transfer_bytes(const stm32_spi_t* spi, const uint8_t* out,
uint8_t* in, uint16_t length)
uint32_t stm32_spi_transfer_bytes(const stm32_spi_t* spi, const uint8_t* out,
uint8_t* in, uint32_t length)
{
unsigned trans_bytes = 0;
uint8_t in_temp;
@@ -312,18 +225,10 @@ uint16_t stm32_spi_transfer_bytes(const stm32_spi_t* spi, const uint8_t* out,
uint16_t stm32_spi_transfer_word(const stm32_spi_t* spi, uint16_t out)
{
auto* SPIx = spi->SPIx;
#if defined(STM32H7) || defined(STM32H7RS)
while (!LL_SPI_IsActiveFlag_TXP(SPIx));
#else
while (!LL_SPI_IsActiveFlag_TXE(SPIx));
#endif
LL_SPI_TransmitData16(SPIx, out);
#if defined(STM32H7) || defined(STM32H7RS)
while (!LL_SPI_IsActiveFlag_RXP(SPIx));
#else
while (!LL_SPI_IsActiveFlag_RXNE(SPIx));
#endif
return LL_SPI_ReceiveData16(SPIx);
}
@@ -336,12 +241,6 @@ extern uint32_t _sram;
extern uint32_t _eram;
#define _IS_DMA_BUFFER(addr) \
((intptr_t)(addr) >= (intptr_t)&_sram && (intptr_t)(addr) <= (intptr_t)&_eram)
#elif defined(STM32H7) || defined(STM32H7RS)
extern uint32_t _s_dram;
extern uint32_t _e_dram;
#define _IS_DMA_BUFFER(addr) \
((intptr_t)(addr) >= (intptr_t)&_s_dram && \
(intptr_t)(addr) <= (intptr_t)&_e_dram)
#else
#define _IS_DMA_BUFFER(addr) (true)
#endif
@@ -349,19 +248,17 @@ extern uint32_t _e_dram;
#define _IS_ALIGNED(addr) (((intptr_t)(addr) & 3U) == 0U)
static void _dma_enable_stream(DMA_TypeDef* DMAx, uint32_t stream,
const void* data, uint32_t length)
const void* data, uint32_t length)
{
stm32_dma_check_tc_flag(DMAx, stream);
#if !defined(STM32H7RS)
LL_DMA_SetMemoryAddress(DMAx, stream, (uintptr_t)data);
LL_DMA_SetDataLength(DMAx, stream, length);
LL_DMA_EnableStream(DMAx, stream);
#endif
}
#endif
uint16_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi,
uint8_t* data, uint16_t length)
uint32_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi, uint8_t* data,
uint32_t length)
{
#if defined(USE_SPI_DMA)
if (!spi->DMA) {
@@ -377,26 +274,18 @@ uint16_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi,
LL_SPI_EnableDMAReq_RX(spi->SPIx);
_scratch_byte = 0xFFFF;
#if !defined(STM32H7RS)
LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_NOINCREMENT);
#endif
_dma_enable_stream(spi->DMA, spi->txDMA_Stream, &_scratch_byte, length);
LL_SPI_EnableDMAReq_TX(spi->SPIx);
// Wait for end of DMA transfer
while(!stm32_dma_check_tc_flag(spi->DMA, spi->rxDMA_Stream));
#if !defined(STM32H7) && !defined(STM32H7RS)
// Wait for TXE=1
while (!LL_SPI_IsActiveFlag_TXE(spi->SPIx));
// Wait for BSY=0
while(LL_SPI_IsActiveFlag_BSY(spi->SPIx));
#else
// Wait for EOT=1
while (!LL_SPI_IsActiveFlag_EOT(spi->SPIx));
LL_SPI_ClearFlag_EOT(spi->SPIx);
#endif
// Disable SPI TX/RX DMA requests
LL_SPI_DisableDMAReq_TX(spi->SPIx);
@@ -412,8 +301,8 @@ uint16_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi,
#endif
}
uint16_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi,
const uint8_t* data, uint16_t length)
uint32_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi,
const uint8_t* data, uint32_t length)
{
#if defined(USE_SPI_DMA)
if (!spi->DMA) {
@@ -426,17 +315,13 @@ uint16_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi,
data = _scratch_buffer;
}
#if !defined(STM32H7RS)
LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_INCREMENT);
#endif
_dma_enable_stream(spi->DMA, spi->txDMA_Stream, data, length);
LL_SPI_EnableDMAReq_TX(spi->SPIx);
// Wait for end of DMA transfer
while (!stm32_dma_check_tc_flag(spi->DMA, spi->txDMA_Stream));
#if !defined(STM32H7) && !defined(STM32H7RS)
// Wait for TXE=1
while (!LL_SPI_IsActiveFlag_TXE(spi->SPIx));
@@ -447,16 +332,6 @@ uint16_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi,
if (LL_SPI_IsActiveFlag_RXNE(spi->SPIx)) {
(void)LL_SPI_ReceiveData8(spi->SPIx);
}
#else
// Wait for EOT=1
while (!LL_SPI_IsActiveFlag_EOT(spi->SPIx));
LL_SPI_ClearFlag_EOT(spi->SPIx);
// Clear RX FIFO
while (LL_SPI_IsActiveFlag_RXP(spi->SPIx)) {
(void)LL_SPI_ReceiveData8(spi->SPIx);
}
#endif
// Disable SPI TX DMA requests
LL_SPI_DisableDMAReq_TX(spi->SPIx);
+14 -7
View File
@@ -50,22 +50,29 @@ struct stm32_spi_t {
void stm32_spi_enable_clock(SPI_TypeDef *SPIx);
void stm32_spi_init(const stm32_spi_t* spi, uint32_t data_width, bool misoPullUp = false);
void stm32_spi_init(const stm32_spi_t* spi, uint32_t data_width);
void stm32_spi_deinit(const stm32_spi_t* spi);
void stm32_spi_select(const stm32_spi_t* spi);
void stm32_spi_unselect(const stm32_spi_t* spi);
void stm32_spi_set_max_baudrate(const stm32_spi_t* spi, uint32_t baudrate);
void stm32_spi_set_data_width(const stm32_spi_t* spi, uint32_t data_width);
uint8_t stm32_spi_transfer_byte(const stm32_spi_t* spi, uint8_t out);
uint16_t stm32_spi_transfer_word(const stm32_spi_t* spi, uint16_t out);
uint16_t stm32_spi_transfer_bytes(const stm32_spi_t* spi, const uint8_t* out,
uint8_t* in, uint16_t length);
uint32_t stm32_spi_transfer_bytes(const stm32_spi_t* spi, const uint8_t* out,
uint8_t* in, uint32_t length);
uint16_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi, uint8_t* data,
uint16_t length);
uint32_t stm32_spi_transfer_words(const stm32_spi_t* spi, const uint16_t* out,
uint16_t* in, uint32_t length);
uint16_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi, const uint8_t* data,
uint16_t length);
uint32_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi, uint8_t* data,
uint32_t length);
uint32_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi,
const uint8_t* data, uint32_t length);
uint32_t stm32_spi_dma_transmit_words(const stm32_spi_t* spi,
const uint16_t* data, uint32_t length);
@@ -0,0 +1,493 @@
/*
* Copyright (C) EdgeTx
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "stm32_spi.h"
#include "stm32_dma.h"
#include "stm32_gpio.h"
#include "stm32_hal.h"
#include "stm32_hal_ll.h"
#include <string.h>
#if !defined(SPI_DISABLE_DMA)
#define USE_SPI_DMA
#endif
#define SPI_DUMMY_BYTE (0xFF)
#define SPI_MAX_XFER_SIZE (16*1024)
void stm32_spi_enable_clock(SPI_TypeDef *SPIx)
{
if (SPIx == SPI1) {
__HAL_RCC_SPI1_CLK_ENABLE();
}
#if defined(SPI2)
else if (SPIx == SPI2) {
__HAL_RCC_SPI2_CLK_ENABLE();
}
#endif
#if defined(SPI3)
else if (SPIx == SPI3) {
__HAL_RCC_SPI3_CLK_ENABLE();
}
#endif
#if defined(SPI4)
else if (SPIx == SPI4) {
__HAL_RCC_SPI4_CLK_ENABLE();
}
#endif
#if defined(SPI5)
else if (SPIx == SPI5) {
__HAL_RCC_SPI5_CLK_ENABLE();
}
#endif
#if defined(SPI6)
else if (SPIx == SPI6) {
__HAL_RCC_SPI6_CLK_ENABLE();
}
#endif
}
static inline uint32_t _get_spi_af(SPI_TypeDef *SPIx)
{
#if defined(SPI3)
if (SPIx == SPI3) return LL_GPIO_AF_6;
#endif
return LL_GPIO_AF_5;
}
static inline uint32_t _get_spi_clocksource(SPI_TypeDef* SPIx)
{
#if defined(LL_RCC_SPI123_CLKSOURCE)
return LL_RCC_SPI123_CLKSOURCE;
#endif
#if defined(LL_RCC_SPI1_CLKSOURCE)
if (SPIx == SPI1) return LL_RCC_SPI1_CLKSOURCE;
#endif
#if defined(LL_RCC_SPI23_CLKSOURCE)
if (SPIx == SPI2 || SPIx == SPI3) return LL_RCC_SPI23_CLKSOURCE;
#endif
#if defined(LL_RCC_SPI45_CLKSOURCE)
if (SPIx == SPI4 || SPIx == SPI5) return LL_RCC_SPI45_CLKSOURCE;
#endif
#if defined(LL_RCC_SPI6_CLKSOURCE)
if (SPIx == SPI6) return LL_RCC_SPI6_CLKSOURCE;
#endif
return 0;
}
static uint32_t _get_spi_prescaler(SPI_TypeDef *SPIx, uint32_t max_freq)
{
LL_RCC_ClocksTypeDef RCC_Clocks;
LL_RCC_GetSystemClocksFreq(&RCC_Clocks);
uint32_t pclk = LL_RCC_GetSPIClockFreq(_get_spi_clocksource(SPIx));
#if defined(SPI2)
if (SPIx == SPI2) {
pclk = RCC_Clocks.PCLK1_Frequency;
}
#endif
#if defined(SPI3)
if (SPIx == SPI3) {
pclk = RCC_Clocks.PCLK1_Frequency;
}
#endif
uint32_t divider = (pclk + max_freq) / max_freq;
uint32_t presc;
if (divider > 128) {
presc = LL_SPI_BAUDRATEPRESCALER_DIV256;
} else if (divider > 64) {
presc = LL_SPI_BAUDRATEPRESCALER_DIV128;
} else if (divider > 32) {
presc = LL_SPI_BAUDRATEPRESCALER_DIV64;
} else if (divider > 16) {
presc = LL_SPI_BAUDRATEPRESCALER_DIV32;
} else if (divider > 8) {
presc = LL_SPI_BAUDRATEPRESCALER_DIV16;
} else if (divider > 4) {
presc = LL_SPI_BAUDRATEPRESCALER_DIV8;
} else if (divider > 2) {
presc = LL_SPI_BAUDRATEPRESCALER_DIV4;
} else {
presc = LL_SPI_BAUDRATEPRESCALER_DIV2;
}
return presc;
}
static void _init_gpios(const stm32_spi_t* spi)
{
gpio_init_af(spi->MISO, _get_spi_af(spi->SPIx), GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(spi->SCK, _get_spi_af(spi->SPIx), GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(spi->MOSI, _get_spi_af(spi->SPIx), GPIO_PIN_SPEED_VERY_HIGH);
gpio_init(spi->CS, GPIO_OUT, GPIO_PIN_SPEED_HIGH);
}
#if defined(USE_SPI_DMA)
static void _config_dma_streams(const stm32_spi_t* spi)
{
stm32_dma_enable_clock(spi->DMA);
LL_DMA_DeInit(spi->DMA, spi->rxDMA_Stream);
LL_DMA_DeInit(spi->DMA, spi->txDMA_Stream);
LL_DMA_InitTypeDef dmaInit;
LL_DMA_StructInit(&dmaInit);
#if defined(STM32H7)
dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH;
dmaInit.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
dmaInit.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD;
#elif defined(STM32H7RS)
dmaInit.Priority = LL_DMA_LOW_PRIORITY_HIGH_WEIGHT;
#endif
#if defined(STM32H7)
dmaInit.PeriphRequest = spi->rxDMA_PeriphRequest;
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
#elif defined(STM32H7RS)
dmaInit.Request = spi->rxDMA_PeriphRequest;
dmaInit.SrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
dmaInit.SrcIncMode = LL_DMA_SRC_FIXED;
dmaInit.DestIncMode = LL_DMA_DEST_INCREMENT;
dmaInit.SrcDataWidth = LL_DMA_DEST_DATAWIDTH_HALFWORD;
dmaInit.DestDataWidth = LL_DMA_DEST_DATAWIDTH_HALFWORD;
#endif
dmaInit.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
LL_DMA_Init(spi->DMA, spi->rxDMA_Stream, &dmaInit);
#if defined(STM32H7)
dmaInit.PeriphRequest = spi->txDMA_PeriphRequest;
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
#elif defined(STM32H7RS)
dmaInit.Request = spi->rxDMA_PeriphRequest;
dmaInit.DestAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
dmaInit.SrcIncMode = LL_DMA_SRC_INCREMENT;
dmaInit.DestIncMode = LL_DMA_DEST_FIXED;
dmaInit.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_HALFWORD;
dmaInit.DestDataWidth = LL_DMA_SRC_DATAWIDTH_HALFWORD;
#endif
dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
LL_DMA_Init(spi->DMA, spi->txDMA_Stream, &dmaInit);
}
#endif
void stm32_spi_init(const stm32_spi_t* spi, uint32_t data_width)
{
_init_gpios(spi);
auto SPIx = spi->SPIx;
stm32_spi_enable_clock(SPIx);
LL_SPI_DeInit(SPIx);
LL_SPI_InitTypeDef spiInit;
LL_SPI_StructInit(&spiInit);
spiInit.TransferDirection = LL_SPI_FULL_DUPLEX;
spiInit.Mode = LL_SPI_MODE_MASTER;
spiInit.NSS = LL_SPI_NSS_SOFT;
spiInit.DataWidth = data_width;
LL_SPI_Init(SPIx, &spiInit);
#if defined(USE_SPI_DMA)
if (spi->DMA) {
_config_dma_streams(spi);
}
#endif
}
void stm32_spi_select(const stm32_spi_t* spi)
{
gpio_clear(spi->CS);
}
void stm32_spi_unselect(const stm32_spi_t* spi)
{
gpio_set(spi->CS);
}
void stm32_spi_set_max_baudrate(const stm32_spi_t* spi, uint32_t baudrate)
{
auto* SPIx = spi->SPIx;
uint32_t presc = _get_spi_prescaler(SPIx, baudrate);
LL_SPI_SetBaudRatePrescaler(SPIx, presc);
}
void stm32_spi_set_data_width(const stm32_spi_t* spi, uint32_t data_width)
{
auto* SPIx = spi->SPIx;
LL_SPI_SetDataWidth(SPIx, data_width);
}
static inline void spi_close_transfer(SPI_TypeDef* SPIx)
{
while (!LL_SPI_IsActiveFlag_EOT(SPIx)) {
}
LL_SPI_ClearFlag_EOT(SPIx);
LL_SPI_ClearFlag_TXTF(SPIx);
LL_SPI_Disable(SPIx);
CLEAR_BIT(SPIx->CFG1, SPI_CFG1_TXDMAEN | SPI_CFG1_RXDMAEN);
}
static void spi_transfer_8(SPI_TypeDef* SPIx, const uint8_t** tx_data,
unsigned tx_inc, uint8_t** rx_data, unsigned rx_inc,
uint16_t length)
{
unsigned rx_len = length;
unsigned tx_len = length;
LL_SPI_SetTransferSize(SPIx, length);
LL_SPI_Enable(SPIx);
LL_SPI_StartMasterTransfer(SPIx);
while (rx_len > 0 || tx_len > 0) {
if (LL_SPI_IsActiveFlag_TXP(SPIx) && (tx_len > 0)) {
LL_SPI_TransmitData8(SPIx, **tx_data);
*tx_data += tx_inc;
tx_len--;
}
if (LL_SPI_IsActiveFlag_RXP(SPIx) && (rx_len > 0)) {
**rx_data = LL_SPI_ReceiveData8(SPIx);
*rx_data += rx_inc;
rx_len--;
}
}
spi_close_transfer(SPIx);
}
uint32_t stm32_spi_transfer_bytes(const stm32_spi_t* spi, const uint8_t* out,
uint8_t* in, uint32_t length)
{
auto* SPIx = spi->SPIx;
unsigned rx_inc = 1;
unsigned tx_inc = 1;
static uint8_t _scratch_data;
const uint8_t* tx_data = out;
if (!tx_data) {
tx_data = &_scratch_data;
tx_inc = 0;
}
uint8_t* rx_data = in;
if (!rx_data) {
rx_data = &_scratch_data;
rx_inc = 0;
}
uint32_t xfer_len = length;
while (xfer_len > 0) {
uint16_t single_xfer_len =
xfer_len > SPI_MAX_XFER_SIZE ? SPI_MAX_XFER_SIZE : xfer_len;
spi_transfer_8(SPIx, &tx_data, tx_inc, &rx_data, rx_inc, single_xfer_len);
xfer_len -= single_xfer_len;
}
return length;
}
static void spi_transfer_16(SPI_TypeDef* SPIx, const uint16_t** tx_data,
unsigned tx_inc, uint16_t** rx_data, unsigned rx_inc,
uint16_t length)
{
unsigned rx_len = length;
unsigned tx_len = length;
LL_SPI_SetTransferSize(SPIx, length);
LL_SPI_Enable(SPIx);
LL_SPI_StartMasterTransfer(SPIx);
while (rx_len > 0 || tx_len > 0) {
if (LL_SPI_IsActiveFlag_TXP(SPIx) && (tx_len > 0)) {
LL_SPI_TransmitData16(SPIx, **tx_data);
*tx_data += tx_inc;
tx_len--;
}
if (LL_SPI_IsActiveFlag_RXP(SPIx) && (rx_len > 0)) {
**rx_data = LL_SPI_ReceiveData16(SPIx);
*rx_data += rx_inc;
rx_len--;
}
}
spi_close_transfer(SPIx);
}
uint32_t stm32_spi_transfer_words(const stm32_spi_t* spi, const uint16_t* out,
uint16_t* in, uint32_t length)
{
auto* SPIx = spi->SPIx;
unsigned rx_inc = 1;
unsigned tx_inc = 1;
static uint16_t _scratch_data;
const uint16_t* tx_data = out;
if (!tx_data) {
tx_data = &_scratch_data;
tx_inc = 0;
}
uint16_t* rx_data = in;
if (!rx_data) {
rx_data = &_scratch_data;
rx_inc = 0;
}
uint32_t xfer_len = length;
while (xfer_len > 0) {
uint16_t single_xfer_len =
xfer_len > SPI_MAX_XFER_SIZE ? SPI_MAX_XFER_SIZE : xfer_len;
spi_transfer_16(SPIx, &tx_data, tx_inc, &rx_data, rx_inc, single_xfer_len);
xfer_len -= single_xfer_len;
}
return length;
}
uint8_t stm32_spi_transfer_byte(const stm32_spi_t* spi, uint8_t out)
{
uint8_t in;
stm32_spi_transfer_bytes(spi, &out, &in, 1);
return in;
}
uint16_t stm32_spi_transfer_word(const stm32_spi_t* spi, uint16_t out)
{
uint16_t in;
stm32_spi_transfer_words(spi, &out, &in, 1);
return in;
}
#if defined(USE_SPI_DMA)
static void _dma_enable_stream(DMA_TypeDef* DMAx, uint32_t stream,
const void* data, uint32_t length)
{
stm32_dma_check_tc_flag(DMAx, stream);
#if !defined(STM32H7RS)
LL_DMA_SetMemoryAddress(DMAx, stream, (uintptr_t)data);
LL_DMA_SetDataLength(DMAx, stream, length);
LL_DMA_EnableStream(DMAx, stream);
#endif
}
#endif
static void spi_receive_dma(const stm32_spi_t* spi, void* data, uint16_t length)
{
_dma_enable_stream(spi->DMA, spi->rxDMA_Stream, data, length);
LL_SPI_SetTransferSize(spi->SPIx, length);
LL_SPI_EnableDMAReq_RX(spi->SPIx);
LL_SPI_Enable(spi->SPIx);
LL_SPI_StartMasterTransfer(spi->SPIx);
// Wait for end of DMA transfer
while (!stm32_dma_check_tc_flag(spi->DMA, spi->rxDMA_Stream));
spi_close_transfer(spi->SPIx);
}
uint32_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi, uint8_t* data,
uint32_t length)
{
#if !defined(USE_SPI_DMA)
return stm32_spi_transfer_bytes(spi, nullptr, data, length);
#else
uint32_t xfer_len = length / 2;
while (xfer_len > 0) {
uint16_t single_xfer_len =
xfer_len > SPI_MAX_XFER_SIZE ? SPI_MAX_XFER_SIZE : xfer_len;
spi_receive_dma(spi, data, single_xfer_len);
xfer_len -= single_xfer_len;
data += single_xfer_len * 2;
}
return length;
#endif
}
static void spi_transmit_dma(const stm32_spi_t* spi, const void* data, uint16_t length)
{
_dma_enable_stream(spi->DMA, spi->txDMA_Stream, data, length);
LL_SPI_SetTransferSize(spi->SPIx, length);
LL_SPI_EnableDMAReq_TX(spi->SPIx);
LL_SPI_Enable(spi->SPIx);
LL_SPI_StartMasterTransfer(spi->SPIx);
// Wait for end of DMA transfer
while (!stm32_dma_check_tc_flag(spi->DMA, spi->txDMA_Stream));
spi_close_transfer(spi->SPIx);
}
uint32_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi,
const uint8_t* data, uint32_t length)
{
#if !defined(USE_SPI_DMA)
return stm32_spi_transfer_bytes(spi, data, nullptr, length);
#else
uint32_t xfer_len = length / 2;
while (xfer_len > 0) {
uint16_t single_xfer_len =
xfer_len > SPI_MAX_XFER_SIZE ? SPI_MAX_XFER_SIZE : xfer_len;
spi_transmit_dma(spi, data, single_xfer_len);
xfer_len -= single_xfer_len;
data += single_xfer_len * 2;
}
return length;
#endif
}
uint32_t stm32_spi_dma_transmit_words(const stm32_spi_t* spi,
const uint16_t* data, uint32_t length)
{
#if !defined(USE_SPI_DMA)
return stm32_spi_transfer_words(spi, data, nullptr, length);
#else
uint32_t xfer_len = length;
while (xfer_len > 0) {
uint16_t single_xfer_len =
xfer_len > SPI_MAX_XFER_SIZE ? SPI_MAX_XFER_SIZE : xfer_len;
spi_transmit_dma(spi, data, single_xfer_len);
xfer_len -= single_xfer_len;
data += single_xfer_len;
}
return length;
#endif
}