本文最后更新于23 天前,其中的信息可能已经过时,如有错误请发送邮件到tudougin@163.com
1. 通用串行通信单元
通用串行通信单元的1个单元有4个串行通道,各通道能实现3线串行(SSPI)、UART的通信功能。BAT32G133
功能分配如下:
单元 | 通道 | 用作SSP1功能 | 用作UART功能 |
---|---|---|---|
0 | 0 | SSP100(支持从机选择输入) | UART0 |
0 | 1 | SSP101 | – |
0 | 2 | SSP110 | UART1 |
0 | 3 | SSP111 | – |
1 | 0 | SSP120 | UART2 |
1 | 1 | SSP121 | – |
在单元0的通道0和通道1使用UART0时,不能使用SSPI00和SSPI01,但是能使用通道2和通道3的SSPI10、UART1。
2. UART
当用作UART时,发送方(偶数通道)和接收方(奇数通道)只能用于UART
2.1 UART功能
- 数据的发送和接收
- 7位、8位或者9位的数据长度(注:只有UART0支持9位数据长度。)
- MSB/LSB优先的选择
- 发送和接收数据的电平设置(选择电平是否反相)
- 奇偶校验位的附加、奇偶校验功能
- 停止位的附加、停止位的检测功能
- 中断功能
- 传送结束中断、缓冲器空中断
- 帧错误、奇偶校验错误和溢出错误引起的错误中断
- 错误检测标志
- 帧错误、奇偶校验错误、溢出错
2.2 UART配置
2.2.1 配置串口参数
SystemCoreClockUpdate();
status = UART0_Init(SystemCoreClock, 19200);
库默认配置UART参数为8N1(8位数据位,无奇偶校验,1位停止位)、中断默认开启,可修改SCI0->SCR00
与SCI0->SCR01
配置代码进行参数更改;
MD_STATUS UART0_Init(uint32_t freq, uint32_t baud)
{
MD_STATUS status;
CGC->PER0 |= CGC_PER0_SCI0EN_Msk;
SCI0->SPS0 = (0 << SCI0_SPS0_PRS00_Pos) | (3 << SCI0_SPS0_PRS00_Pos);
/* transmission channel */
SCI0->SMR00 = _0020_SMRMN_DEFAULT_VALUE | _0000_SCI_CLOCK_SELECT_CK00 | _0000_SCI_CLOCK_MODE_CKS |
_0002_SCI_MODE_UART | _0000_SCI_TRANSFER_END;
SCI0->SCR00 = _0004_SCRMN_DEFAULT_VALUE | _8000_SCI_TRANSMISSION | _0000_SCI_TIMING_1 | _0000_SCI_INTSRE_MASK |
_0000_SCI_PARITY_NONE | _0080_SCI_LSB | _0010_SCI_STOP_1 | _0003_SCI_LENGTH_8;//修改此处发送串口参数
SCI0->SDR00 = _CE00_SCI_BAUDRATE_DIVISOR;
/* reception channel */
MISC->NFEN0 |= _01_SCI_RXD0_FILTER_ON;
SCI0->SIR01 = _0004_SCI_SIRMN_FECTMN | _0002_SCI_SIRMN_PECTMN | _0001_SCI_SIRMN_OVCTMN;
SCI0->SMR01 = _0020_SMRMN_DEFAULT_VALUE | _0000_SCI_CLOCK_SELECT_CK00 | _0000_SCI_CLOCK_MODE_CKS |
_0100_SCI_TRIGGER_RXD | _0000_SCI_EDGE_FALL | _0002_SCI_MODE_UART | _0000_SCI_TRANSFER_END;
SCI0->SCR01 = _0004_SCRMN_DEFAULT_VALUE | _4000_SCI_RECEPTION | _0000_SCI_TIMING_1 | _0000_SCI_INTSRE_MASK |
_0000_SCI_PARITY_NONE | _0080_SCI_LSB | _0010_SCI_STOP_1 | _0003_SCI_LENGTH_8;//修改此处接收串口参数
SCI0->SDR01 = _CE00_SCI_BAUDRATE_DIVISOR;
/* output enable */
SCI0->SO0 |= _0001_SCI_CH0_DATA_OUTPUT_1;
SCI0->SOL0 &= (uint16_t)~_0001_SCI_CHANNEL0_INVERTED;
SCI0->SOE0 |= _0001_SCI_CH0_OUTPUT_ENABLE;
/* Set TxD0 pin */
TXD0_PORT_SETTING();
/* Set RxD0 pin */
RXD0_PORT_SETTING();
/* UART0 Start, Setting baud rate */
status = UART0_BaudRate(freq, baud);
return (status);
}
2.2.2 配置串口引脚
/* ToDo: You can allocate the TXD0 to any desired pins with PxxCFG register */
#define TXD0_PORT_SETTING() do{ \
PORT->P24CFG = PTCFG_TXD0; /* allocate TXD0 to P24 */ \
PORT->PM2 &= ~(1 << 4); /* P24 is used as TXD0 output */ \
PORT->POM2 &= ~(1 << 4); /* P24 is normal output mode */ \
PORT->PMC2 &= ~(1 << 4); /* P24 digital function */ \
}while(0)
/* ToDo: You can allocate the RXD0 to any desired pins with PxxCFG register */
#define RXD0_PORT_SETTING() do{ \
PORT->P23CFG = PTCFG_RXD0; /* allocate RXD0 to P23 */ \
PORT->PM2 |= (1 << 3); /* P23 is used as RXD0 input */ \
PORT->PMC2 &= ~(1 << 3); /* P23 digital function */ \
}while(0)
2.2.3 开启/关闭串口中断
UART0_Start();
UART0_Stop();
2.3 中断处理
2.3.1 接收中断
官方提供的库函数完成以下功能:接收串口数据,检查错误,存入缓冲区,并在完成或异常时调用对应的回调函数。但未在程序中发现g_uart0_rx_length 、g_uart0_rx_count
的具体数值,可能仍需完善相关代码。比如实现128字节定长处理、发送数据以”\r\n”结束或者50ms内无数据则接收完成等
void uart0_interrupt_receive(void)
{
volatile uint8_t rx_data;
volatile uint8_t err_type;
INTC_ClearPendingIRQ(SR0_IRQn);
err_type = (uint8_t)(SCI0->SSR01 & 0x0007U);
SCI0->SIR01 = (uint16_t)err_type;
if (err_type != 0U)
{
uart0_callback_error(err_type);
}
rx_data = SCI0->RXD0;
if (g_uart0_rx_length > g_uart0_rx_count)
{
*gp_uart0_rx_address = rx_data;
gp_uart0_rx_address++;
g_uart0_rx_count++;
if (g_uart0_rx_length == g_uart0_rx_count)
{
uart0_callback_receiveend();
}
}
else
{
uart0_callback_softwareoverrun(rx_data);
}
}
2.3.2 发送中断
官方提供的库函数实现用于一个字节一个字节发送数据的功能。但程序仍有缺失部分,即gp_uart0_tx_address、g_uart0_tx_count
相关部分的赋值,需要再编写相关的函数设置:
void uart0_interrupt_send(void)
{
INTC_ClearPendingIRQ(ST0_IRQn);
if (g_uart0_tx_count > 0U)
{
SCI0->TXD0 = *gp_uart0_tx_address;
gp_uart0_tx_address++;
g_uart0_tx_count--;
}
else
{
uart0_callback_sendend();
}
}
3. SPI
与主控设备输出的串行时钟(SCK)同步进行数据的发送和接收。这是使用1条串行时钟(SCK)、1条发送串行数据(SO)和1条接收串行数据(SI)共3条通信线进行通信的时钟同步通信接口。
3.1 SPI功能
- 数据的发送和接收
- 7位或者8位的数据长度
- 发送和接收数据的相位控制
- MSB/LSB优先的选择
- 时钟控制
- 主控或者从属的选择
- 输入/输出时钟的相位控制
- 由预分频器和通道内部计数器产生的传送周期
- 最大传送速率
- 主控通信:最大值Fclk/2
- 从属通信:最大值Fmck/6
- 中断功能
- 传送结束中断、缓冲器空中断
- 错误检测标志
- 溢出错误
3.2 SPI配置(主机)
3.2.1 配置SPI模式
/* @param mode
* - SPI_MODE_0: CPOL = 0, CPHA = 0; i.e. DAP = 1, CKP = 1
* - SPI_MODE_1: CPOL = 0, CPHA = 1; i.e. DAP = 0, CKP = 1
* - SPI_MODE_2: CPOL = 1, CPHA = 0; i.e. DAP = 1, CKP = 0
* - SPI_MODE_3: CPOL = 1, CPHA = 1; i.e. DAP = 0, CKP = 0
*/
SPI10_MasterInit(SPI_MODE_0);
对于SPI的格式,官方默认使用8位、MSB的格式,使用者可以在代码中进行修改
void SPI10_MasterInit(spi_mode_t mode)
{
CGC->PER0 |= CGC_PER0_SCI0EN_Msk;
SCI0->ST0 |= _0004_SCI_CH2_STOP_TRG_ON;
SCI0->SPS0 &= ~SCI0_SPS0_PRS01_Msk;
SCI0->SPS0 |= (0 << SCI0_SPS0_PRS01_Pos);
SCI0->SIR02 = _0004_SCI_SIRMN_FECTMN | _0002_SCI_SIRMN_PECTMN | _0001_SCI_SIRMN_OVCTMN;
SCI0->SMR02 = _0020_SMRMN_DEFAULT_VALUE | _8000_SCI_CLOCK_SELECT_CK01 | _0000_SCI_CLOCK_MODE_CKS |
_0000_SCI_TRIGGER_SOFTWARE | _0000_SCI_MODE_SPI | _0000_SCI_TRANSFER_END;
SCI0->SCR02 = _0004_SCRMN_DEFAULT_VALUE | _C000_SCI_RECEPTION_TRANSMISSION | mode | _0000_SCI_INTSRE_MASK |
_0000_SCI_PARITY_NONE | _0000_SCI_MSB | _0000_SCI_STOP_NONE | _0003_SCI_LENGTH_8;//参数修改这里
#ifdef HIGH_SPEED_SPI
//SCI0->SDR02 = 1 << 9; /* fMCK/(1+n)x2 = fMCK/4 */
//SCI0->SDR02 = 2 << 9; /* fMCK/(1+n)x2 = fMCK/6 */
//SCI0->SDR02 = 3 << 9; /* fMCK/(1+n)x2 = fMCK/8 */
SCI0->SDR02 = 4 << 9; /* fMCK/(1+n)x2 = fMCK/10 */
//SCI0->SDR02 = 5 << 9; /* fMCK/(1+n)x2 = fMCK/12 */
#else
SCI0->SDR02 = _CE00_SCI_BAUDRATE_DIVISOR;
#endif
/* Set output enable */
if ((mode == SPI_MODE_0) || (mode == SPI_MODE_1))
{
SCI0->SO0 &= ~_0400_SCI_CH2_CLOCK_OUTPUT_1;
}
if ((mode == SPI_MODE_2) || (mode == SPI_MODE_3))
{
SCI0->SO0 |= _0400_SCI_CH2_CLOCK_OUTPUT_1;
}
SCI0->SOE0 |= _0004_SCI_CH2_OUTPUT_ENABLE;
/* Set SSn pin */
SS10_PORT_SETTING();
/* Set SCLK10 pin */
SCLKO10_PORT_SETTING();
/* Set SDI10 pin */
SDI10_PORT_SETTING();
/* Set SDO10 pin */
SDO10_PORT_SETTING();
}
3.2.2 配置SPI引脚
/* ToDo: You can allocate the SS10 to any desired pins */
#define SS10_PORT_SETTING() do{ \
PORT->P10CFG = 0x00; /* P10 default GPIO function */ \
PORT->P1 |= (1 << 0); /* P10 output high level */ \
PORT->PM1 &= ~(1 << 0); /* P10 is used as SS01 input */ \
}while(0)
/* ToDo: You can allocate the SS10 to any desired pins */
#define SS10_PORT_SET() do{ \
PORT->P1 |= (1 << 0); /* P10 output high level */ \
}while(0)
/* ToDo: You can allocate the SS10 to any desired pins */
#define SS10_PORT_CLR() do{ \
PORT->P1 &= ~(1 << 0); /* P10 output low level */ \
}while(0)
/* ToDo: You can allocate the SCLKI10 to any desired pins with PxxCFG register */
#define SCLKI10_PORT_SETTING() do{ \
PORT->P35CFG = PTCFG_SCLK10; /* allocate SCLK10 to P35 */ \
PORT->PM3 |= (1 << 5); /* P35 is used as SCLK10 input */ \
PORT->PMC3 &= ~(1 << 5); /* P35 digital function */ \
}while(0)
/* ToDo: You can allocate the SCLKO10 to any desired pins with PxxCFG register */
#define SCLKO10_PORT_SETTING() do{ \
PORT->P35CFG = PTCFG_SCLK10;/* allocate SCLK10 to P35 */ \
PORT->PM3 &= ~(1 << 5); /* P35 is used as SCLK10 output */ \
PORT->POM3 &= ~(1 << 5); /* P35 is normal output mode */ \
PORT->PMC3 &= ~(1 << 5); /* P35 digital function */ \
}while(0)
/* ToDo: You can allocate the SDO10 to any desired pins with PxxCFG register */
#define SDO10_PORT_SETTING() do{ \
PORT->P37CFG = PTCFG_SDO10; /* allocate SDO10 to P37 */ \
PORT->PM3 &= ~(1 << 7); /* P37 is used as SDO10 output */ \
PORT->POM3 &= ~(1 << 7); /* P37 is normal output mode */ \
PORT->PMC3 &= ~(1 << 7); /* P37 digital function */ \
}while(0)
/* ToDo: You can allocate the SDI10 to any desired pins with PxxCFG register */
#define SDI10_PORT_SETTING() do{ \
PORT->P36CFG = PTCFG_SDI10; /* allocate SDI10 to P36 */ \
PORT->PM3 |= (1 << 6); /* P36 is used as SDI10 input */ \
PORT->PMC3 &= ~(1 << 6); /* P36 digital function */ \
}while(0)
3.2.3 SPI中断开启/关闭
SPI10_Start();
SPI10_Stop();
3.3 SPI数据收发
uint8_t mtx_buf[] = {0xA5, 0x5A, 0xCC, 0x33, 0x3C, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
uint8_t mrx3_buf[13];
SPI10_MasterSend(mtx_buf, sizeof(mtx_buf));
SPI10_MasterReceive(mrx3_buf, sizeof(mrx3_buf));