|
spi + dma数据收发偶尔不正常,配置如下:
static void rcu_config(void)
{
/* enable the peripherals clock */
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOG);
rcu_periph_clock_enable(RCU_SPI0);
rcu_periph_clock_enable(RCU_DMA0);
rcu_periph_clock_enable(RCU_DMAMUX);
rcu_spi_clock_config(IDX_SPI0, RCU_SPISRC_PLL0Q);
}
static void gpio_config(void)
{
/* connect port to SPI0_NSS->PA4
SPI0_SCK->PB3
SPI0_MISO->PB4
SPI0_MOSI->PB5 */
//gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_4);
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_4);
SET_SPI0_NSS_HIGH();
gpio_af_set(GPIOB, GPIO_AF_5, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);
}
static void spi0_config(void)
{
spi_parameter_struct spi_init_struct;
/* deinitialize SPI and the parameters */
spi_i2s_deinit(SPI0);
spi_struct_para_init(&spi_init_struct);
/* SPI0 parameter configuration */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.data_size = SPI_DATASIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_128;
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI0, &spi_init_struct);
/* enable SPI byte access */
spi_byte_access_enable(SPI0);
spi_nss_internal_low(SPI0);
spi_nss_output_enable(SPI0);
spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
spi_enable(SPI0);
SET_SPI0_NSS_HIGH();
}
static void dma_config(void)
{
dma_single_data_parameter_struct dma_init_struct;
/* deinitialize DMA registers of a channel */
dma_deinit(DMA0, DMA_CH0);
dma_deinit(DMA0, DMA_CH1);
dma_single_data_para_struct_init(&dma_init_struct);
/* SPI0 transmit DMA config: DMA_CH0 */
dma_init_struct.request = DMA_REQUEST_SPI0_TX;
dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
//dma_init_struct.memory0_addr = (uint32_t)spi0_send_array;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
//dma_init_struct.number = ARRAYSIZE;
dma_init_struct.periph_addr = (uint32_t)&SPI_TDATA(SPI0);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.priority = DMA_PRIORITY_HIGH;
dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct);
/* SPI0 receive DMA config: DMA_CH1 */
dma_init_struct.request = DMA_REQUEST_SPI0_RX;
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
//dma_init_struct.memory0_addr = (uint32_t)spi0_receive_array;
dma_init_struct.periph_addr = (uint32_t)&SPI_RDATA(SPI0);
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(DMA0, DMA_CH1, &dma_init_struct);
dma_interrupt_enable(DMA0, DMA_CH0, DMA_INT_FTF);
dma_interrupt_enable(DMA0, DMA_CH1, DMA_INT_FTF);
nvic_irq_enable(DMA0_Channel0_IRQn, 1, 0);
nvic_irq_enable(DMA0_Channel1_IRQn, 2, 0);
}
void DMA0_Channel0_IRQHandler()
{
if (dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_FEE)) {
dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_FEE);
// 记录错误、复位 DMA 或报警
}
if (dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_FTF)) {
dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_FTF);
// 正常完成传输
dma_channel_disable(DMA0, DMA_CH0);
spi_dma_disable(SPI0, SPI_DMA_TRANSMIT);
spi_tx_done = 1;
}
}
void DMA0_Channel1_IRQHandler()
{
if (dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INT_FLAG_FEE)) {
dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INT_FLAG_FEE);
// 记录错误、复位 DMA 或报警
}
if (RESET != dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INT_FLAG_FTF)) {
dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INT_FLAG_FTF);
// 关闭 DMA 通道和 SPI 接收DMA
dma_channel_disable(DMA0, DMA_CH1);
spi_dma_disable(SPI0, SPI_DMA_RECEIVE);
SET_SPI0_NSS_HIGH();
spi_rx_done = 1;
}
}
/* 注意tx_buf, rx_buf的内存位置需要支持DMA */
void spi0_dma_send_recv(uint8_t *tx_buf, uint8_t *rx_buf, uint32_t length)
{
/* 检查spi是否正在收发 */
while(!(spi_tx_done && spi_rx_done)){};
/* 开始传输,清空spi收发完成标志 */
spi_tx_done = 0;
spi_rx_done = 0;
s_rx_buf = rx_buf;
s_tx_buf = tx_buf;
s_buf_len = length;
SET_SPI0_NSS_LOW();
/* DMA 缓存一致性问题,DMA 访问的是实际内存,但 CPU 修改的可能只是 Cache 中的副本,没有及时写回 */
SCB_CleanDCache_by_Addr((uint32_t *)s_tx_buf, s_buf_len);
dma_channel_disable(DMA0, DMA_CH0);
dma_channel_disable(DMA0, DMA_CH1);
dma_transfer_number_config(DMA0, DMA_CH0, s_buf_len);
dma_memory_address_config(DMA0, DMA_CH0, DMA_MEMORY_0, (uint32_t)s_tx_buf);
dma_transfer_number_config(DMA0, DMA_CH1, s_buf_len);
dma_memory_address_config(DMA0, DMA_CH1, DMA_MEMORY_0, (uint32_t)s_rx_buf);
dma_channel_enable(DMA0, DMA_CH1);
dma_channel_enable(DMA0, DMA_CH0);
spi_current_data_num_config(SPI0, s_buf_len);
spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
spi_master_transfer_start(SPI0, SPI_TRANS_START);
}
main函数中调用
while(1) {
spi0_dma_send_recv((uint8_t*)send_buf, (uint8_t*)recv_buf, 1024);
}
使用逻辑分析仪抓数据看到偶尔会在发送完成一次数据包1024bytes之后,CLK电平不会变为空闲电平(低电平空闲),如下图:

下图是正常的时序:

|
|