[AT32F403/403A] AT32F403A使用全双工SPI做从机+DMA能发送数据,但是无法接收数据

[复制链接]
 楼主| DylanMingan 发表于 2022-10-18 14:09 | 显示全部楼层 |阅读模式
AT32F403A做从机,接收来自Linux的SPI数据,配置为全双工
Linux的主机一直发送0x55,等待AT32F403A接收
配置SPI思路,定义了两个全局变量来给DMA使用
分别是SPI_Slave_Buffer_RxSPI_Slave_Buffer_Tx
还开启了dma_init_struct.loop_mode_enable = TRUE 让每次传输完后计数器重新到设置值
具体代码如下

  1. #define SPI_Slave                   SPI1
  2. #define SPI_Slave_CLK               CRM_SPI1_PERIPH_CLOCK
  3. #define SPI_Slave_GPIO              GPIOA
  4. #define SPI_Slave_GPIO_CLK          CRM_GPIOA_PERIPH_CLOCK
  5. #define SPI_Slave_PIN_NSS           GPIO_PINS_4
  6. #define SPI_Slave_PIN_SCK           GPIO_PINS_5
  7. #define SPI_Slave_PIN_MISO          GPIO_PINS_6
  8. #define SPI_Slave_PIN_MOSI          GPIO_PINS_7
  9. #define SPI_Slave_DMA_CLK            CRM_DMA1_PERIPH_CLOCK
  10. #define SPI_Slave_Rx_DMA_Channel     DMA1_CHANNEL2
  11. #define SPI_Slave_Rx_DMA_FLAG        DMA1_FDT2_FLAG
  12. #define SPI_Slave_Tx_DMA_Channel     DMA1_CHANNEL3
  13. #define SPI_Slave_Tx_DMA_FLAG        DMA1_FDT3_FLAG  

  14. uint8_t SPI_Slave_Buffer_Rx[CMD_LEN]={0};
  15. uint8_t SPI_Slave_Buffer_Tx[CMD_LEN] ={0x47, 0xC3, 0x4F, 0xFF, 0x40, 0x1C, 0x3F, 0xFF,
  16.                 0x56, 0x78, 0x56, 0x78, 0x78, 0x56, 0x78, 0x56,
  17.                 0x56, 0x78, 0x56, 0x78, 0x78, 0x56, 0x78, 0x56,
  18.                 0x56, 0x78, 0x56, 0x78, 0x78, 0x56, 0x78, 0x56,
  19.                 0x56, 0x78, 0x56, 0x78, 0x78, 0x56, 0x78, 0x56,
  20.                 0x56, 0x78, 0x56, 0x78, 0x78, 0x56, 0x78, 0x56,
  21.                 0x56, 0x78, 0x56, 0x78, 0x78, 0x56, 0x78, 0x56,
  22.                 0x56, 0x78, 0x56, 0x78, 0x78, 0x56, 0x78, 0x56,
  23.                 0x56, 0x78, 0x56, 0x78, 0x78, 0x56, 0x78, 0x56,
  24.                 0x56, 0x78, 0x56, 0x78, 0x78, 0x56, 0x78, 0x56,
  25.                 0x40, 0x1C, 0x3F, 0xFF, 0x40, 0x1C, 0x3F, 0xFF,
  26.                 0x40, 0x1C, 0x3F, 0xFF, 0x40, 0x1C, 0x3F, 0xFF};

  27. void spi_gpio_configuration(void)
  28. {
  29.     gpio_init_type gpio_init_struct;

  30.     gpio_default_para_init(&gpio_init_struct);

  31.     /* configure slave pins SCK */
  32.     gpio_init_struct.gpio_pins = SPI_Slave_PIN_SCK;
  33.     gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
  34.     gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  35.     gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  36.     gpio_init(SPI_Slave_GPIO, &gpio_init_struct);

  37.     /* configure slave pin MISO*/
  38.     gpio_init_struct.gpio_pins = SPI_Slave_PIN_MISO;
  39.     gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  40.     gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  41.     gpio_init(SPI_Slave_GPIO, &gpio_init_struct);

  42.     /* configure slave pins MOSI*/
  43.     gpio_init_struct.gpio_pins = SPI_Slave_PIN_MOSI;
  44.     gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  45.     gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  46.     gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  47.     gpio_init(SPI_Slave_GPIO, &gpio_init_struct);

  48.     /* configure slave pin CS*/
  49.     gpio_init_struct.gpio_pins = SPI_Slave_PIN_NSS;
  50.     gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  51.     gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  52.     gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  53.     gpio_init(GPIOD, &gpio_init_struct);
  54. }

  55. void spi_configuration(void)
  56. {
  57.     dma_init_type dma_init_struct;
  58.     spi_init_type spi_init_struct;

  59.     /* SPI_Slave_Tx_DMA_Channel configuration ---------------------------------------------*/
  60.     dma_reset(SPI_Slave_Tx_DMA_Channel);
  61.     dma_default_para_init(&dma_init_struct);
  62.     dma_init_struct.buffer_size = CMD_LEN;
  63.     dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
  64.     dma_init_struct.memory_base_addr = (uint32_t)SPI_Slave_Buffer_Tx;
  65.     dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
  66.     dma_init_struct.memory_inc_enable = TRUE;
  67.     dma_init_struct.peripheral_base_addr = (uint32_t)&SPI_Slave->dt;
  68.     dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
  69.     dma_init_struct.peripheral_inc_enable = FALSE;
  70.     dma_init_struct.priority = DMA_PRIORITY_HIGH;
  71.     dma_init_struct.loop_mode_enable = TRUE;
  72.     dma_init(SPI_Slave_Tx_DMA_Channel, &dma_init_struct);

  73.     /* SPI_Slave_Rx_DMA_Channel configuration ---------------------------------------------*/
  74.     dma_reset(SPI_Slave_Rx_DMA_Channel);
  75.     dma_default_para_init(&dma_init_struct);
  76.     dma_init_struct.buffer_size = CMD_LEN;
  77.     dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
  78.     dma_init_struct.memory_base_addr = (uint32_t)SPI_Slave_Buffer_Rx;
  79.     dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
  80.     dma_init_struct.memory_inc_enable = TRUE;
  81.     dma_init_struct.peripheral_base_addr = (uint32_t)&SPI_Slave->dt;
  82.     dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
  83.     dma_init_struct.peripheral_inc_enable = FALSE;
  84.     dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
  85.     dma_init_struct.loop_mode_enable = TRUE;
  86.     dma_init(SPI_Slave_Rx_DMA_Channel, &dma_init_struct);

  87.     /* SPI_Slave configuration ------------------------------------------------------*/
  88.     spi_default_para_init(&spi_init_struct);
  89.     spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
  90.     spi_init_struct.master_slave_mode = SPI_MODE_SLAVE;
  91.     spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_2;
  92.     spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
  93.     spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
  94.     spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
  95.     spi_init_struct.clock_phase = SPI_CLOCK_PHASE_1EDGE;
  96.     spi_init_struct.cs_mode_selection = SPI_CS_HARDWARE_MODE;
  97.     spi_init(SPI_Slave, &spi_init_struct);

  98.     /* Enable SPI_Slave Tx Rx request */
  99.     spi_i2s_dma_transmitter_enable(SPI_Slave, TRUE);
  100.     spi_i2s_dma_receiver_enable(SPI_Slave, TRUE);


  101.   /* Enable SPI_Slave_Rx_DMA_Channel */
  102.     dma_channel_enable(SPI_Slave_Rx_DMA_Channel, TRUE);
  103.     /* Enable SPI_Slave_Tx_DMA_Channel */
  104.     dma_channel_enable(SPI_Slave_Tx_DMA_Channel, TRUE);
  105.    
  106.        /* Enable SPI_Slave */
  107.     spi_enable(SPI_Slave, TRUE);
  108. }


  109. void SPI_Init(void)
  110. {
  111.     spi_gpio_configuration();
  112.     spi_configuration();
  113. }

采用轮询方法,没有写DMA中断服务函数,在主程序里面一直查询FDTF标志位看是否数据传输完毕
传输完毕就清除DMA相关的所有标志位,想开启下一次传输
AT32F403A主程序代码如下
  1.   int main(void)
  2. {
  3.   // 240M
  4.   system_clock_config();
  5.   // IRQ priority
  6.   nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  7.   // init board resources
  8.   at32_board_init();
  9. while (1)
  10.   {
  11.     //...省略无关代码...//

  12.         // 如果SPI的DMA接收完了数据,准备开始处理
  13.     if (dma_flag_get(SPI_Slave_Rx_DMA_FLAG) != RESET)
  14.     {
  15.       for(int i=0;i<132;i++)
  16.       {printf("RX:%x\r\n",SPI_Slave_Buffer_Rx[i]);}
  17.       
  18.       // 清DMA标志位
  19.       dma_flag_clear(SPI_Slave_Rx_DMA_FLAG|DMA1_GL2_FLAG|DMA1_HDT2_FLAG|DMA1_DTERR2_FLAG);
  20.       dma_flag_clear(SPI_Slave_Tx_DMA_FLAG|DMA1_GL3_FLAG|DMA1_HDT3_FLAG|DMA1_DTERR3_FLAG);
  21.       /* Enable SPI_Slave_Rx_DMA_Channel */
  22.       dma_channel_enable(SPI_Slave_Rx_DMA_Channel, TRUE);
  23.       /* Enable SPI_Slave_Tx_DMA_Channel */
  24.       dma_channel_enable(SPI_Slave_Tx_DMA_Channel, TRUE);
  25.     }
  26.    
  27.     delay_ms(10);
  28. }
  29. }

现象
打印出SPI_Slave_Buffer_Rx缓存区的数据,发现都是0xFF,但是主机linux一直在发送0x55
86489634e42c70a6c2.png
使用逻辑分析仪抓取数据发现SPI_Slave_Buffer_Tx能够发送给主机,但是主机发送的0x55没有接收到
使用逻辑分析仪抓取如下
e87347b59fb99e620d661578500a31a9
怀疑是DMA使用方法有问题?有大佬能指点一下吗,万分感谢!

 楼主| DylanMingan 发表于 2022-10-21 22:59 | 显示全部楼层
仔细排查后,发现是硬件问题,芯片的SPI的MOSI脚虚焊了。。
timfordlare 发表于 2022-11-1 19:44 | 显示全部楼层
SPI通信,MISO接收不到数据?
burgessmaggie 发表于 2022-11-1 20:05 | 显示全部楼层
spi的配置有问题吗              
pl202 发表于 2022-11-2 17:01 | 显示全部楼层
这个spi的地址是否正常呢?              
elsaflower 发表于 2022-11-2 17:29 | 显示全部楼层
进入在线调试试试看,先建立一个存放SPI数据的变量,看看有没有数据;还可以在DMA中断函数设置一个FLAG,如果进入中断置1否则为0;如果是0的话确实没有进中断,那要看看你的配置了
everyrobin 发表于 2022-11-2 18:11 | 显示全部楼层
使用示波器查看一下是否有数据呢              
belindagraham 发表于 2022-11-2 18:59 | 显示全部楼层
AT32F403A的 SPI 从机模式并没有只接收这种配置吧
abotomson 发表于 2022-11-2 19:57 | 显示全部楼层
SPI从机接收数据错误是怎么回事  
yorkbarney 发表于 2022-11-2 20:47 | 显示全部楼层
SPI1 仅使用发送功能,SPI2 仅使用接收功能,两者均使用 DMA。
gygp 发表于 2022-11-3 20:25 | 显示全部楼层
使用这两个函数时必须得同时使用,若是接收数据时只调用SPI_I2S_ReceiveData()函数,那么spi clk 是不会产生clk的,所以不会收到数据。
iyoum 发表于 2022-11-3 21:15 | 显示全部楼层
设置全双工SPI模式时,需要向发送寄存器里面写数据,这样才能正常全双工通讯。
10299823 发表于 2022-11-5 09:49 | 显示全部楼层
用不用 SPI 从机发送功能,都必须要配置发送。
lzmm 发表于 2022-11-5 10:51 | 显示全部楼层
这个使用中断接收不行吗              
deliahouse887 发表于 2022-11-5 11:47 | 显示全部楼层
对照AT32F403A使用全双工SPI做从机+DMA的例子再仔细看看吧!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

2

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部