本帖最后由 xhackerustc 于 2024-5-19 13:28 编辑
这一贴测评SPI。根据官方datasheet,芯片有3个spi控制器,都支持spi master和spi slave,帧大小支持4bits - 16bits,详细可参见datasheet。本帖就以SPI1为对象测试。外设的测试一般都会接上对应设备,比如i2c slave等等,但SPI比较特别,可以用杜邦线把MISO和MSOI针脚连接起来,形成external loop,然后自发自收,这有点像linux下的spidev_test测试程序。根据笔者经验一般过了spidev_test,基本spi控制器没啥大问题了。
创建spidev_test工程
STM官方代码里有很多SPI样例,都在Projects/NUCLEO-U083RC/Examples/SPI/目录和Projects/NUCLEO-U083RC/Examples_LL/SPI/目录里,。笔者浏览以后挑了SPI_FullDuplex_ComPolling_Master为模板创建spidev_test工程。本来这个SPI_FullDuplex_ComPolling_Master需要两块板子,一块运行SPI_FullDuplex_ComPolling_Master,另一块运行SPI_FullDuplex_ComPolling_aSlave,咱们现在就改造它使用external loop方式。
- cp -a Projects/NUCLEO-U083RC/Examples/SPI/SPI_FullDuplex_ComPolling_Master/ Projects/NUCLEO-U083RC/Examples/spidev_test/
串口printf打印
spidev_test测试结果是把收到的数据全打印出来,因为SPI_FullDuplex_ComPolling_Master传的是字符串,可以当字符串打印。所以现在还需要把Projects/NUCLEO-U083RC/Examples/UART/UART_Print的一些code拿过来。
第一个是stm32u0xx_hal_msp.c中的HAL_UART_MspInit()和HAL_UART_MspDeInit()函数,不过需要注意我们未使能HSI,所以需要把UART的时钟源改成ssysclk:
- PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_SYSCLK;
第二拿过来的是MX_USART2_UART_Init函数以及PUTCHAR_PROTOTYPE
main函数中调用一次MX_USART2_UART_Init()后printf就可以用了
发起spi传输
照着SPI_FullDuplex_ComPolling_Master例子调用HAL_SPI_TransmitReceive()函数即可
接线datasheet里SPI1的MISO和MOSI针脚可选PB4与PB5,根据板子原理图这两根针脚接到了CN10的pin27和pin29, 用杜邦线连接它们即可
测试结果
完整main.c代码附上
- #include <stdio.h>
- #include <string.h>
- #include "main.h"
- SPI_HandleTypeDef hspi1;
- UART_HandleTypeDef huart2;
- /* Buffer used for transmission */
- static uint8_t aTxBuffer[] = "****SPI - external loop communication based on Polling **** SPI Message ******** SPI Message ******** SPI Message ****";
- static uint8_t aRxBuffer[BUFFERSIZE];
- #if defined(__ICCARM__)
- /* New definition from EWARM V9, compatible with EWARM8 */
- int iar_fputc(int ch);
- #define PUTCHAR_PROTOTYPE int iar_fputc(int ch)
- #elif defined ( __CC_ARM ) || defined(__ARMCC_VERSION)
- /* ARM Compiler 5/6*/
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
- #elif defined(__GNUC__)
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
- #endif
- PUTCHAR_PROTOTYPE
- {
- /* Place your implementation of fputc here */
- /* e.g. write a character to the USART2 and Loop until the end of transmission */
- HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
- return ch;
- }
- static void MX_USART2_UART_Init(void)
- {
- /* USER CODE BEGIN USART2_Init 0 */
- /* USER CODE END USART2_Init 0 */
- /* USER CODE BEGIN USART2_Init 1 */
- /* USER CODE END USART2_Init 1 */
- huart2.Instance = USART2;
- huart2.Init.BaudRate = 115200;
- huart2.Init.WordLength = UART_WORDLENGTH_8B;
- huart2.Init.StopBits = UART_STOPBITS_1;
- huart2.Init.Parity = UART_PARITY_NONE;
- huart2.Init.Mode = UART_MODE_TX_RX;
- huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
- huart2.Init.OverSampling = UART_OVERSAMPLING_16;
- huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
- huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
- huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
- if (HAL_UART_Init(&huart2) != HAL_OK)
- {
- Error_Handler();
- }
- if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
- {
- Error_Handler();
- }
- if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
- {
- Error_Handler();
- }
- if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN USART2_Init 2 */
- /* USER CODE END USART2_Init 2 */
- }
- void Error_Handler(void)
- {
- while (1)
- {
- printf("error\n");
- HAL_Delay(1000);
- }
- }
- static void SystemClock_Config(void)
- {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- /** Configure the main internal regulator output voltage
- */
- HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
- /** Initializes the RCC Oscillators according to the specified parameters
- * in the RCC_OscInitTypeDef structure.
- */
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
- RCC_OscInitStruct.MSIState = RCC_MSI_ON;
- RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
- RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
- /** Initializes the CPU, AHB and APB buses clocks
- */
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
- |RCC_CLOCKTYPE_PCLK1;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
- {
- Error_Handler();
- }
- }
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] SPI1 Initialization Function
- * @param None
- * @retval None
- */
- static void MX_SPI1_Init(void)
- {
- hspi1.Instance = SPI1;
- hspi1.Init.Mode = SPI_MODE_MASTER;
- hspi1.Init.Direction = SPI_DIRECTION_2LINES;
- hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
- hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
- hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
- hspi1.Init.NSS = SPI_NSS_SOFT;
- hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
- hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
- hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
- hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
- hspi1.Init.CRCPolynomial = 7;
- hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
- hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
- if (HAL_SPI_Init(&hspi1) != HAL_OK)
- {
- Error_Handler();
- }
- }
- int main(void)
- {
- HAL_Init();
- SystemClock_Config();
- MX_USART2_UART_Init();
- MX_SPI1_Init();
- printf("** spi external loop test ** \n\r");
- printf("SysClockFreq:%ld\n", HAL_RCC_GetSysClockFreq());
- /* While the SPI in TransmitReceive process, user can transmit data through
- "aTxBuffer" buffer & receive data through "aRxBuffer" */
- /* Timeout is set to 5S */
- switch (HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE, 5000))
- {
- case HAL_OK:
- /* Communication is completed ___________________________________________ */
- /* Compare the sent and received buffers */
- printf("RX:\n%s\n", aRxBuffer);
- if (memcmp((uint8_t *)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE))
- {
- /* Transfer error in transmission process */
- Error_Handler();
- }
- /* Turn LED4 on: Transfer in transmission/Reception process is correct */
- break;
- case HAL_TIMEOUT:
- /* An Error Occur ______________________________________________________ */
- case HAL_ERROR:
- /* Call Timeout Handler */
- Error_Handler();
- break;
- default:
- break;
- }
- for (;;)
- HAL_Delay(100000);
- }
|