本帖最后由 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);
}
|