USART配置成SPI實例代碼

在工作中第一次遇到可以將串口當做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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章