在工作中第一次遇到可以将串口当做SPI使用的情况,下面是我在ATSAM4SD16B芯片中书写的将USART配置成SPI使用的代码。
// Include files
#include "component_usart.h"
#include "sam4sd16b.h"
#include "assert.h"
#include "sam_gpio.h"
#include "sysclk.h"
#define USART_SPI USART1
#define CONFIG_USART_SPI_DUMMY 0xFF
// Define USART SPI port
#define SPI_NSS_IDX PIO_PA24_IDX
#define SPI_NSS_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
#define SPI_SPCK_IDX PIO_PA23_IDX
#define SPI_SPCK_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
#define SPI_MOSI_IDX PIO_PA22_IDX
#define SPI_MOSI_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
#define SPI_MISO_IDX PIO_PA21_IDX
#define SPI_MISO_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
typedef enum UsartSpiMode
{
USART_SPI_MODE_0,
USART_SPI_MODE_1,
USART_SPI_MODE_2,
USART_SPI_MODE_3,
}UsartSpiMode_t;
// Functions prototype
void v_usartSpiEnable(void);
void v_usartSpiDisable(void);
void v_usartSpiGPIOConfigure(void);
void v_usartSpiInit(void);
void v_usartSpiWriteByte(uint8_t uc_Data);
void v_usartSpiReadByte(uint32_t* puc_Data);
void v_usartSpiWrite(uint8_t* puc_Data, uint32_t ui_DataLength);
void v_usartSpiRead(uint8_t* puc_Data, uint32_t ui_DataLength);
/*
* Brief: Configure USART SPI pins
* Input: None
* Output: None
* Return: None
*/
void v_usartSpiGPIOConfigure(void)
{
// Configure IO port
gpio_configure_pin(SPI_NSS_IDX, SPI_NSS_FLAGS);
gpio_configure_pin(SPI_SPCK_IDX, SPI_SPCK_FLAGS);
gpio_configure_pin(SPI_MOSI_IDX, SPI_MOSI_FLAGS);
gpio_configure_pin(SPI_MISO_IDX, SPI_MISO_FLAGS);
// Enable peripheral clock
PMC->PMC_PCER0 = 1 <<ID_USART1;
}
/*
Brief: Enable USART SPI
Input: None
Output: None
Return: None
*/
void v_usartSpiEnable(void)
{
USART_SPI->US_CR = US_CR_RXEN;
USART_SPI->US_CR = US_CR_TXEN;
}
/*
Brief: Disable USART SPI
Input: None
Output: None
Return: None
*/
void v_usartSpiDisable(void)
{
USART_SPI->US_CR = US_CR_TXDIS;
USART_SPI->US_CR = US_CR_RXDIS;
}
/*
*Brief: Synchronous mode enable
*Input: None
*Output: None
*Return: None
*/
void v_usartSpiSynchronousModeEnable(void)
{
USART_SPI->US_MR |= US_MR_SYNC;
}
/*
*Brief: Asynchronous mode enable
*Input: None
*Output: None
*Return: None
*/
void v_usartSpiAsynchronousModeEnable(void)
{
USART_SPI->US_MR &= ~US_MR_SYNC;
}
/*
*Brief: Set SPI transmit mode
*Input: t_UsartSpiMode, USART SPI transmit mode
*Output: None
*Return: None
*/
void v_usartSpiTransmitMode(UsartSpiMode_t t_SpiMode)
{
switch(t_SpiMode)
{
case USART_SPI_MODE_0:
USART_SPI->US_MR &= ~US_MR_CPHA;
USART_SPI->US_MR &= ~US_MR_CPOL;
break;
case USART_SPI_MODE_1:
USART_SPI->US_MR &= ~US_MR_CPHA;
USART_SPI->US_MR |= US_MR_CPOL;
break;
case USART_SPI_MODE_2:
USART_SPI->US_MR |= US_MR_CPHA;
USART_SPI->US_MR &= ~US_MR_CPOL;
break;
case USART_SPI_MODE_3:
USART_SPI->US_MR |= US_MR_CPHA;
USART_SPI->US_MR |= US_MR_CPOL;
break;
}
}
/*
* Brief: Reset USART and disable TX and RX
* Input: None
* Output: None
* Return: None
*/
void v_usartSpiReset(void)
{
/* Disable write protect of USART registers. */
USART_SPI->US_WPMR = US_WPMR_WPKEY_PASSWD;
/* Reset registers that could cause unpredictable behavior after reset. */
USART_SPI->US_MR = 0;
USART_SPI->US_RTOR = 0;
USART_SPI->US_TTGR = 0;
/* Reset transmitter */
USART_SPI->US_CR = US_CR_RSTTX | US_CR_TXDIS;
/* Reset Receiver */
USART_SPI->US_CR = US_CR_RSTRX | US_CR_RXDIS;
/* Reset status bits (PARE, OVER, MANERR, UNRE and PXBRK in US_CSR). */
USART_SPI->US_CR = US_CR_RSTSTA;
/* Drive the pin RTS to 1. */
USART_SPI->US_CR = US_CR_RTSDIS;
/* Drive the pin DTR to 1. */
USART_SPI->US_CR = US_CR_DTRDIS;
}
/*
* Brief: Configure USART1 as SPI mode
* Input: None
* Output: None
* Return: None
*/
void v_usartSpiInit(void)
{
/* Configure GPIO port */
v_usartSpiGPIOConfigure();
/* Reset USART */
v_usartSpiReset();
/* Set SPI master mode and channel mode. */
USART_SPI->US_MR |= US_MR_USART_MODE_SPI_MASTER;
/* Peripheral clock divided(DIV=8) is selected */
USART_SPI->US_MR |= US_MR_USCLKS_DIV;
/* Set transmit character length */
USART_SPI->US_MR |= US_MR_CHRL_8_BIT;
/* Set SPI transmit mode */
v_usartSpiTransmitMode(USART_SPI_MODE_0);
/* The USART drives the SCK pin if USCLKS does not select the external clock SCK */
USART_SPI->US_MR |= US_MR_CLKO;
/* Set synchronous mode */
v_usartSpiSynchronousModeEnable();
/* Set clock frequency */
uint32_t ui_ClockFrequency = sysclk_get_cpu_hz(); // 1 2000 0000
ui_ClockFrequency /= 6;
/* Set baudrate */
uint32_t ui_BaudRate = 115200;
/* Calculate the clock divider according to the formula in SPI mode. */
uint32_t ui_ClockDivider = (ui_ClockFrequency + ui_BaudRate / 2) / ui_BaudRate; /* 174 */
/* Generator baudrate */
USART_SPI->US_BRGR = ui_ClockDivider << US_BRGR_CD_Pos;
/* Enable SPI */
v_usartSpiEnable();
}
/*
Brief: Write one byte to USART SPI
Input: uc_Data, need to write data
Output: None
Return: None
*/
void v_usartSpiWriteByte(uint8_t uc_Data)
{
/* Check if transmit is ready */
while (!(USART_SPI->US_CSR & US_CSR_TXRDY));
USART_SPI->US_THR = US_THR_TXCHR(uc_Data);
}
/*
Brief: Read one byte from USART SPI
Input: None
Output: puc_Data
Return: None
*/
void v_usartSpiReadByte(uint32_t* pui_Data)
{
/* Dummy write one data to slave in order to read data. */
while (!(USART_SPI->US_CSR & US_CSR_TXRDY));
USART_SPI->US_THR = US_THR_TXCHR(CONFIG_USART_SPI_DUMMY);
/* Wait until it's not empty or timeout has reached. */
while (!(USART_SPI->US_CSR & US_CSR_RXRDY));
/* Read character */
*pui_Data = USART_SPI->US_RHR & US_RHR_RXCHR_Msk;
}
/*
Brief: Write data to USART SPI
Input: 1) puc_Data, write data
2) ui_DataLength, write data length
Output: None
Return: None
*/
void v_usartSpiWrite(uint8_t* puc_Data, uint32_t ui_DataLength)
{
uint32_t ui_Index = 0;
uint32_t ui_DummyData = 0;
assert(puc_Data != NULL);
assert(ui_DataLength > 0);
/* Drive the slave select line NSS (RTS pin) to 0 */
USART_SPI->US_CR = US_CR_FCS;
for(ui_Index = 0; ui_Index < ui_DataLength; ui_Index++)
{
v_usartSpiWriteByte(puc_Data[ui_Index]);
/* Wait until it's not empty or timeout has reached. */
while (!(USART_SPI->US_CSR & US_CSR_RXRDY));
/* Read character */
ui_DummyData = USART_SPI->US_RHR & US_RHR_RXCHR_Msk;
}
/* Drive the slave select line NSS (RTS pin) to 1 */
USART_SPI->US_CR = US_CR_RCS;
}
/*
Brief: Read data from USART SPI
Input: ui_DataLength, read data length
Output: puc_Data, read data
Return: None
*/
void v_usartSpiRead(uint8_t* puc_Data, uint32_t ui_DataLength)
{
uint32_t ui_Index = 0;
uint32_t ui_TempData = 0;
assert(ui_DataLength > 0);
/* Drive the slave select line NSS (RTS pin) to 0 */
USART_SPI->US_CR = US_CR_FCS;
for(ui_Index = 0; ui_Index < ui_DataLength; ui_Index++)
{
v_usartSpiReadByte(&ui_TempData);
puc_Data[ui_Index] = (uint8_t)(ui_TempData & 0xFF);
ui_TempData = 0;
}
/* Drive the slave select line NSS (RTS pin) to 1 */
USART_SPI->US_CR = US_CR_RCS;
}