fix(h7): common drivers for H7 support (#6149)
Co-authored-by: raphaelcoeffic <1050031+raphaelcoeffic@users.noreply.github.com>
This commit is contained in:
co-authored by
raphaelcoeffic
parent
46f3716995
commit
706a092bc2
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user