[APM32F0] 遇到一个很扎心的问题,APM32F030C8初始化SPI2失败,而且不知道是哪儿出了问题...

[复制链接]
 楼主| bks882 发表于 2025-2-6 23:52 | 显示全部楼层 |阅读模式
各位大佬晚上好,如题所说,我自己画的板子,打算使用SPI2连接FM25V01铁电来记录数据,可是初始化SPI2后,用逻辑分析仪测SPI2各个引脚电平变化,发现除了CS脚之外,其它3个脚全都没电平转变;我的例程是按照官方 SDK 的 SPI1 的栗子改过来的,查了两个晚上,每个该改的改了,到今晚上还是没反应,数据手册和用户手册我都看过了,也没说过有什么SPI2有关的,真的有点怀疑人生了~~~
附件有4个文件,分别是main与SPI2的C文件和H文件,

SPI2有问题的地方.zip

3.19 KB, 下载次数: 6

kai迪皮 发表于 2025-2-7 10:57 | 显示全部楼层
hi,我在官方例程SPI_TwoBoards修改过来了一份SPI2的初始化通信测试,发现测试可以通过的。使用的引脚如下:
板卡1 APM32F030R8 Master 板卡2 APM32F030R8 Slave
程序 SPI_TwoBoards_Master SPI2 SPI_TwoBoards_Slave
NSS PA8 PA4
SCK PB13 PA5
MISO PB14 PA6
MOSI PB15 PA7



代码:
  1. /*!
  2. * [url=home.php?mod=space&uid=288409]@file[/url]        main.c
  3. *
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]       Main program body
  5. *
  6. * [url=home.php?mod=space&uid=895143]@version[/url]     V1.0.3
  7. *
  8. * [url=home.php?mod=space&uid=212281]@date[/url]        2022-09-20
  9. *
  10. * @attention
  11. *
  12. *  Copyright (C) 2020-2022 Geehy Semiconductor
  13. *
  14. *  You may not use this file except in compliance with the
  15. *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
  16. *
  17. *  The program is only for reference, which is distributed in the hope
  18. *  that it will be useful and instructional for customers to develop
  19. *  their software. Unless required by applicable law or agreed to in
  20. *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
  21. *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
  22. *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
  23. *  and limitations under the License.
  24. */

  25. /* Includes */
  26. #include "Board.h"
  27. #include "stdio.h"
  28. #include "apm32f0xx_gpio.h"
  29. #include "apm32f0xx_misc.h"
  30. #include "apm32f0xx_eint.h"
  31. #include "apm32f0xx_spi.h"

  32. /** @addtogroup Examples
  33.   @{
  34.   */

  35. /** @addtogroup SPI_TwoBoards_Master
  36.   @{
  37.   */

  38. /** @defgroup SPI_TwoBoards_Master_Macros Macros
  39.   @{
  40. */

  41. /* printf function configs to USART2 */
  42. #define DEBUG_USART  USART2

  43. /* Buffsize */
  44. #define BuffSize 56

  45. /**@} end of group SPI_TwoBoards_Master_Macros */

  46. /** @defgroup SPI_TwoBoards_Master_Enumerations Enumerations
  47.   @{
  48. */

  49. /**@} end of group SPI_TwoBoards_Master_Enumerations */

  50. /** @defgroup SPI_TwoBoards_Master_Structures Structures
  51.   @{
  52. */

  53. /**@} end of group SPI_TwoBoards_Master_Structures */

  54. /** @defgroup SPI_TwoBoards_Master_Variables Variables
  55.   @{
  56. */

  57. /* SPI TX Buffer*/
  58. uint8_t SPI_Buffer_TX[BuffSize] =
  59. {
  60.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  61.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  62.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  63.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  64.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  65.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  66.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  67.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  68. };

  69. /**@} end of group SPI_TwoBoards_Master_Variables */

  70. /** @defgroup SPI_TwoBoards_Master_Functions Functions
  71.   @{
  72.   */

  73. /* Delay */
  74. void Delay(uint16_t count);
  75. /* SPI Init */
  76. void APM_MINI_SPIInit(void);
  77. /* Buffer Compare*/
  78. BOOL BufferCompare(uint8_t* buf1, uint8_t* buf2, uint8_t size);


  79. /*!
  80. * @brief       Main program
  81. *
  82. * @param       None
  83. *
  84. * @retval      None
  85. *
  86. * @note
  87. */
  88. int main(void)
  89. {
  90.     /* index of TxData*/
  91.     volatile uint8_t TxIdx = 0;
  92.     /* index of RxData*/
  93.     volatile uint8_t RxIdx = 0;
  94.     /* SPI Receive Buffer*/
  95.     uint8_t SPI_Buffer_RX[BuffSize] = {0x00};

  96.     APM_MINI_LEDInit(LED2);
  97.     APM_MINI_LEDInit(LED3);
  98.     APM_MINI_COMInit(COM2);
  99.     APM_MINI_SPIInit();

  100.     printf("I am Master\r\n");

  101.     /* Low Down NSS for communication*/
  102.     GPIO_ClearBit(GPIOA, GPIO_PIN_8);

  103.     while (TxIdx < BuffSize)
  104.     {
  105.         while (SPI_ReadStatusFlag(SPI2, SPI_FLAG_TXBE) == RESET);
  106.         SPI_I2S_TxData16(SPI2, SPI_Buffer_TX[TxIdx++]);

  107.         while (SPI_ReadStatusFlag(SPI2, SPI_FLAG_RXBNE) == RESET);
  108.         SPI_Buffer_RX[RxIdx++] = SPI_I2S_RxData16(SPI2);

  109.     }
  110.     for (int i = 0; i < BuffSize; i++)
  111.     {
  112.         if (i % 7 == 0)
  113.         {
  114.             printf("\r\n");
  115.         }
  116.         printf(" %02x ,", SPI_Buffer_RX[i]);

  117.     }
  118.     /* Set NSS high for close communication*/
  119.     GPIO_SetBit(GPIOA, GPIO_PIN_8);

  120.     /* Compare Buffer*/
  121.     if (BufferCompare(SPI_Buffer_TX, SPI_Buffer_RX, BuffSize) == TRUE)
  122.     {
  123.         APM_MINI_LEDOn(LED2);
  124.     }

  125.     for (;;)
  126.     {
  127.         Delay(0x5f5f);
  128.         APM_MINI_LEDToggle(LED3);
  129.     }
  130. }

  131. /*!
  132. * @brief       SPI Init
  133. *
  134. * @param       None
  135. *
  136. * @retval      None
  137. *
  138. * @note
  139. */
  140. void APM_MINI_SPIInit(void)
  141. {

  142.     GPIO_Config_T gpioConfig;
  143.     SPI_Config_T spiConfig;

  144.     /* Enable related clock*/
  145.     RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_SPI2);
  146.     RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA|RCM_AHB_PERIPH_GPIOB);
  147.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);

  148.     /* Config alter function*/
  149. //    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_5, GPIO_AF_PIN0);
  150. //    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_6, GPIO_AF_PIN0);
  151. //    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_PIN0);
  152.    
  153.     GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_13, GPIO_AF_PIN0);
  154.     GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_14, GPIO_AF_PIN0);
  155.     GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_15, GPIO_AF_PIN0);
  156.    

  157.     /* config PIN_13->SCK , PIN_15->MOSI*/
  158.     gpioConfig.pin =  GPIO_PIN_13 | GPIO_PIN_15;
  159.     gpioConfig.mode = GPIO_MODE_AF;
  160.     gpioConfig.outtype = GPIO_OUT_TYPE_PP;
  161.     gpioConfig.speed = GPIO_SPEED_50MHz;
  162.     gpioConfig.pupd = GPIO_PUPD_PU;
  163.     GPIO_Config(GPIOB, &gpioConfig);

  164.     /* config PIN_8->NSS*/
  165.     gpioConfig.pin =  GPIO_PIN_8;
  166.     gpioConfig.outtype = GPIO_OUT_TYPE_PP;
  167.     gpioConfig.speed = GPIO_SPEED_50MHz;
  168.     gpioConfig.pupd = GPIO_PUPD_PU;
  169.     gpioConfig.mode = GPIO_MODE_OUT;
  170.     GPIO_Config(GPIOA, &gpioConfig);
  171.     GPIO_SetBit(GPIOA, GPIO_PIN_8);

  172.     /* config PIN_14  MISO*/
  173.     gpioConfig.pin = GPIO_PIN_14;
  174.     gpioConfig.mode = GPIO_MODE_AF;
  175.     gpioConfig.pupd = GPIO_PUPD_PU;
  176.     gpioConfig.speed = GPIO_SPEED_50MHz;
  177.     GPIO_Config(GPIOB, &gpioConfig);

  178.     /* SPI RESET*/
  179.     SPI_Reset(SPI2);
  180.     SPI_ConfigStructInit(&spiConfig);

  181.     /* SPI configuration*/
  182.     /* Set Clock polarity is Low, but Slave is High*/
  183.     spiConfig.polarity = SPI_CLKPOL_LOW;

  184.     /* select master mode*/
  185.     spiConfig.mode = SPI_MODE_MASTER;

  186.     /* SPI Clock Phase is 1EDGE, but Slave is 1EDGE*/
  187.     spiConfig.phase = SPI_CLKPHA_1EDGE;

  188.     /* Enable Software slave control */
  189.     spiConfig.slaveSelect = SPI_SSC_ENABLE;

  190.     /* Set SPI BaudRate divider*/
  191.     spiConfig.baudrateDiv = SPI_BAUDRATE_DIV_256;

  192.     /* SPI data length*/
  193.     spiConfig.length = SPI_DATA_LENGTH_16B;

  194.     /* Set internal slave*/
  195.     SPI_EnableInternalSlave(SPI2);
  196.     SPI_Config(SPI2, &spiConfig);
  197.     SPI_ConfigFIFOThreshold(SPI2, SPI_RXFIFO_QUARTER);

  198.     SPI_Enable(SPI2);
  199. }

  200. /*!
  201. * @brief       Delay
  202. *
  203. * @param       None
  204. *
  205. * @retval      None
  206. *
  207. * @note
  208. */
  209. void Delay(uint16_t count)
  210. {
  211.     volatile uint32_t delay = count;

  212.     while (delay--);
  213. }

  214. /*!
  215. * @brief       Compares two buffers
  216. *
  217. * @param       buf1:    First buffer to be compared
  218. *
  219. * @param       buf1:    Second buffer to be compared
  220. *
  221. * @param       size:    Buffer size
  222. *
  223. * @retval      Return TRUE if buf1 = buf2. If not then return FALSE
  224. *
  225. * @note
  226. */
  227. BOOL BufferCompare(uint8_t* buf1, uint8_t* buf2, uint8_t size)
  228. {
  229.     uint8_t i;

  230.     for (i = 0; i < size; i++)
  231.     {
  232.         if (buf1[i] != buf2[i])
  233.         {
  234.             return FALSE;
  235.         }
  236.     }

  237.     return TRUE;
  238. }

  239. #if defined (__CC_ARM) || defined (__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))

  240. /*!
  241. * @brief       Redirect C Library function printf to serial port.
  242. *              After Redirection, you can use printf function.
  243. *
  244. * @param       ch:  The characters that need to be send.
  245. *
  246. * @param       *f:  pointer to a FILE that can recording all information
  247. *              needed to control a stream
  248. *
  249. * @retval      The characters that need to be send.
  250. *
  251. * @note
  252. */
  253. int fputc(int ch, FILE* f)
  254. {
  255.     /* send a byte of data to the serial port */
  256.     USART_TxData(DEBUG_USART, (uint8_t)ch);

  257.     /* wait for the data to be send  */
  258.     while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

  259.     return (ch);
  260. }

  261. #elif defined (__GNUC__)

  262. /*!
  263. * @brief       Redirect C Library function printf to serial port.
  264. *              After Redirection, you can use printf function.
  265. *
  266. * @param       ch:  The characters that need to be send.
  267. *
  268. * @retval      The characters that need to be send.
  269. *
  270. * @note
  271. */
  272. int __io_putchar(int ch)
  273. {
  274.     /* send a byte of data to the serial port */
  275.     USART_TxData(DEBUG_USART, ch);

  276.     /* wait for the data to be send  */
  277.     while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

  278.     return ch;
  279. }

  280. /*!
  281. * @brief       Redirect C Library function printf to serial port.
  282. *              After Redirection, you can use printf function.
  283. *
  284. * @param       file:  Meaningless in this function.
  285. *
  286. * @param       *ptr:  Buffer pointer for data to be sent.
  287. *
  288. * @param       len:  Length of data to be sent.
  289. *
  290. * @retval      The characters that need to be send.
  291. *
  292. * @note
  293. */
  294. int _write(int file, char* ptr, int len)
  295. {
  296.     int i;
  297.     for (i = 0; i < len; i++)
  298.     {
  299.         __io_putchar(*ptr++);
  300.     }

  301.     return len;
  302. }

  303. #else
  304. #warning Not supported compiler type
  305. #endif

  306. /**@} end of group SPI_TwoBoards_Master_Functions */
  307. /**@} end of group SPI_TwoBoards_Master */
  308. /**@} end of group Examples */


仿真情况:



image.png

逻辑分析仪抓取情况:
image2.png


你可以看看你的代码是否有需要改动的地方,建议你在debug窗口查看一下SPI2的寄存器,若初始化成功,SPI2的寄存器应该是相应的内容。
如何查看外设寄存器值:
image3.png
SPI2初始化前:
image4.png
SPI2初始化后:
image5.png

同样的可以检查SPI相关GPIO和RCM的相关寄存器是否设置正确,设置正确时再检查硬件设计是否有误。

xionghaoyun 发表于 2025-2-7 13:56 | 显示全部楼层
楼上回复很仔细
 楼主| bks882 发表于 2025-2-7 20:16 | 显示全部楼层
kai迪皮 发表于 2025-2-7 10:57
hi,我在官方例程SPI_TwoBoards修改过来了一份SPI2的初始化通信测试,发现测试可以通过的。使用的引脚如下 ...

我今天下班回家后能看到大佬这么详细的信息,心里可乐开花。但是事与愿违...
我回到家里立马先对比大佬的代码,到底我写的是缺了那些代码,然后不上那些缺的代码,然后烧录进单片机测试,试过后发现逻辑分析仪式的时钟脚,MISO,MOSI都是没信号,除了CS脚外...接着我把铁电芯片拆了再测试,结果还是一样,最后没办法了,换单片机....测试结果还是一样....
(刚新年开头,还真是出师不利 ‘鸭’ ~~~)
既然硬件不信,那就使用软件处理吧,还好我测试过了,作为普通IO口,还是能正常运作的!
不过还是谢谢大佬帮忙!!!
天意无罪 发表于 2025-2-8 09:19 | 显示全部楼层
bks882 发表于 2025-2-7 20:16
我今天下班回家后能看到大佬这么详细的信息,心里可乐开花。但是事与愿违...
我回到家里立马先对比大佬的 ...

这都补焊了,芯片也换过了,用作普通IO也是正常的,那说明硬件通路上应该是没有问题的,如果还是不行的话,那大概率和你的配置有关系。
delin17 发表于 2025-2-8 18:22 | 显示全部楼层
直接看寄存器,是不是时钟没开,或者IO口配置不对。
 楼主| bks882 发表于 2025-2-8 19:49 | 显示全部楼层
天意无罪 发表于 2025-2-8 09:19
这都补焊了,芯片也换过了,用作普通IO也是正常的,那说明硬件通路上应该是没有问题的,如果还是不行的话 ...

昨天晚上,我用了2个钟头就把模拟SPI接上FM25V01的驱动调好了。不过我在调模拟SPI前,查看过SPI2寄存器的配置值,跟2楼的发出来的只是一模一样,SPI2的时钟也使能了,GPIO也是配好了,反正我就没配出SPI2出来,现在想,估计是我手上的芯片的问题了。最终我也把驱动调好了,通过模拟SPI方式。只要能使用就可以了!谢谢大家的关注!!!
 楼主| bks882 发表于 2025-2-8 19:50 | 显示全部楼层
delin17 发表于 2025-2-8 18:22
直接看寄存器,是不是时钟没开,或者IO口配置不对。

昨天晚上,我用了2个钟头就把模拟SPI接上FM25V01的驱动调好了。不过我在调模拟SPI前,查看过SPI2寄存器的配置值,跟2楼的发出来的只是一模一样,SPI2的时钟也使能了,GPIO也是配好了,反正我就没配出SPI2出来,现在想,估计是我手上的芯片的问题了。最终我也把驱动调好了,通过模拟SPI方式。只要能使用就可以了!谢谢大家的关注!
ucmic 发表于 2025-3-31 13:29 | 显示全部楼层
kai迪皮 发表于 2025-2-7 10:57
hi,我在官方例程SPI_TwoBoards修改过来了一份SPI2的初始化通信测试,发现测试可以通过的。使用的引脚如下 ...

遇到一样的情况,用SPI2出问题,搞了两天,最好发现把分频系数改成2分频就正常了:SPI_BAUDRATE_DIV_2。不知道是什么原因,除了这个分频外,其他的都无输出。
瞌睡虫本虫 发表于 2025-4-9 09:54 | 显示全部楼层
请确保你的板子上SPI2的线路没有短路或者断路,同时检查FM25V01的连接是否正确。
分形梦想家 发表于 2025-4-28 18:32 | 显示全部楼层
很有可能是分频系数导致的。
SPI2的时钟频率低,在高主频配置下,SPI2需要2分频,或者 4分频才可以
记忆花园 发表于 2025-4-28 19:25 | 显示全部楼层
感觉这个bug在其它家产品也有
使用4分频的速率,因为其有最高速率的限制。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

35

帖子

0

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