1.模块简介
ASCLIN模块的主要目的是使用数据输入和数据输出信号与外部设备提供异步串行通信。该模块是一个多功能串行通信接口,它集成了UART(通用异步收发器)、SPI(串行外设接口)和LIN(局域互联网络)总线功能。这种设计允许使用单个模块实现多种通信协议,从而为汽车和其他需要多种通信接口的应用提供了灵活性。
ASCLIN模块的系统框图如下
2.功能介绍
2.1 ASCLIN的模块特性:
•16字节TxFIFO
•16字节RxFIFO
•Tx和Rx FIFO的打包/解包功能
•中断的产生源
--可配置的发送FIFO
--可配置接收FIFO
--错误条件下(帧,奇偶校验,溢出错误)
--各种模块内部事件(ASC/SPI帧结束,LIN事件)
•能够触发CPU或DMA的中断信号
•可编程过采样4至16次每位
•可编程采样点位置
•可编程数字故障滤波器和中值滤波器的传入位流
•内部环回模式
2.1.1 标准ASC功能
•全双工异步工作模式。
•7位、8位或9位(最多16位)数据帧,LSB优先。
•奇偶位生成/校验。
•一个或两个停止位。
•最大波特率fA/16(6.25MBaud100MHzfA模块时钟)。
•最低波特率fA/268435456(0.37 Baud100MHzfA模块时钟)。
•可选的RTS/CTS握手(同步发送)。
2.1.2 扩展ASC功能
•可编程过采样4至16次每位。
--模块能力高达4倍的波特率(fA/4)相对于标准ASC。
--系统考虑因素,如焊盘类型,输入信号质量和累积锁相环抖动会导致可用过采样比的限制(例如fA/8=200MHz/8=25MBaud)。
•可编程采样点位置。
2.1.3 LIN总线的特性
•破坏检测
•同步字段生成
•自动波特检测基于同步领域的测量
•可选的碰撞检测(需要LIN 2.1版本)
•LIN看门狗
--报头超时
--帧或响应超时
•总线空闲时间监控
2.1.3 SPI特性
•SPI主模式(不支持从模式):
--四线制或三线制(带/不带从选输出信号)
•最多16位数据宽度
•全双工和半双工
--最小波特率fA/268435456 MBaud(0.37Baud100MHzfA模块时钟)
--最大波特率fA/4 MBaud(25MBaud100MHzfA模块时钟)
•可编程的前后延迟
2.2 ASCLIN模块提供以下外部信号:
1.串行时钟输出ASCLK
2.接收数据输入ARX(主接收MR输入SPI模式)
3.传输数据输出ATX(主传输MT输出SPI模式)
4.从机选择信号输出ASLSO
5.请求发送握手输出ARTS
2.3 ASCLIN模块的功能模式:
•标准的UART模式
•高速UART模式
•4线SPI模式
•3线SPI模式
•半双工SPI模式
2.4 串口收发功能概述:
上图描述的是ASCLin模块的数据发送和接受的原理框图,先给大家简要的介绍串口UART收发数据的原理,SPI和LIN通信的以后再做专题展开讨论。
UART收发数据原理是比较简单的,如上图所示,RX引脚在接受到数据后经过一个滤波器(可选择是否滤波)后进行过采样设置,过采样位数和采样点设置好以后对接收到的数据进行过采样,然后存储到RX移位寄存器中(数据低位在前,LSB),接着去除掉起始位,停止位和奇偶校验位就得到数据存储在RXFIFO中。
TX引脚发送数据时,先把数据存储到TXFIFO中,然后加上起始位,停止位和奇偶校验位等,接着把数据移动到TX移位寄存器中,然后通过TX引脚把数据发送过去。
3.TxFIFO概述
TxFIFO(发送FIFO,First In First Out)是一种先进先出的缓冲机制,用于存储即将通过通信接口发送的数据。其原理是将CPU要发送的数据预先写入FIFO缓冲区,然后由硬件或者DMA控制器自动从FIFO中读取数据进行发送,这样可以提高数据传输的效率,减少CPU的负担,实现数据的连续发送。
Tx FIFO能够将来自FPI总线的16位写入打包为两个8位帧或一个16位帧。它还具有将来自FPI总线的32位写入打包到四个8位或两个16位帧的能力。
从上图可以看到,TxFIFO进行写操作的时候可以写入8、16、32位,进行读操作的时候只能读取8或者16位。
3.1 标准ASC模式下
ASC模块最标准的用法是传输7或8位值,并用8位宽的FPI总线访问填充FIFO。FPI总线接入为8位宽,只有BS0(字节选择0)信号激活。传输数据被写入地址TXDATA
4. RxFIFO概述
RxFIFO有能力将两个8位以内的帧或一个16位以内的帧打包成一个16位写入到FPI总线。它还具有将4个8位到16位的帧打包成一个32位写入FPI总线的能力。
从上图可以看到,RxFIFO进行读操作的时候可以读取8、16、32位,进行写操作的时候只能写入8或者16位。
4.1 标准ASC模式下
从地址RXDATA可以读取接收到的数据。在数据宽度为7或8位的情况下,读取这个地址会提供一个字节,并清空一个元素的FIFO。
5.时钟系统
时钟系统生成ASCLIN模块正常运行所需的所有时钟:数字滤波器时钟、过采样时钟、波特率和串行SPI时钟。用于时钟系统fA的时钟独立于SPB总线时钟,并且在SPB总线时钟发生变化时保持不变。位字段CSR.CLKSEL为ASCLin模块选择时钟源,它可以是同步的或异步的,高于或低于SPB总线频率。
5.1 波特率生成
波特率发生器:分数阶分频器,n分频器,过采样分频器,采样点是可配置的。
以下位域可用于配置28位波特率分频链:
•BITCON.PRESCALER --预除法器的除法比
•BRG.NUMERATOR --分数除数的分子(分子小于等于分母)
•BRG.DENOMINATOR --分数除数的分母
•BITCON.OVERSAMPLING --波特率后分割器的分割比率
fPD = fA / (BITCON.PRESCALER + 1)
fOVS = fPD * BRG.NUMERATOR / BRG.DENOMINATOR
fSHIFT = fOVS / (BITCON.OVERSAMPLING + 1)
波特率计算公式如下:
5.2 位时序属性
ASCLIN模块提供了位过采样、采样点和输入信号滤波特性的灵活编程。输入位流的过采样因子可配置为每位4到16次信号(或时间量子)。同时,利用过采样频率,可以启用数字中值滤波器对输入的位进行滤波。如果过滤器被禁用,那么每个位只采样一次。采样点也是可配置的,应该与过采样一起使用。一个标准设置是16倍过采样和使用样本7、8、9作为数据。另一种设置是8倍过采样,并使用样本3、4和5作为数据。
以下位段可用于配置位时序属性:
BITCON.PRESCALER:12位整数分频器定义小数分频器用来产生波特率的微刻度,数字滤波器用来去除RX输入信号的毛刺。
BITCON.SAMPLEPOINT:定义采样点位置,以及SPI模式下的占空比。
BITCON.SM:该位启用数字中位数滤波器,每位1或3个采样。
IOCR.DEPTH:定义浮动平均过滤器深度,关闭或1到63刻度。
BITCON.OVERSAMPLING:定义每个位采样次数的位域,范围为4到16
一般来说,采样点应放置在箭头的中间位置。在波特率(振荡器频率)不是非常精确和稳定的情况下,这个位置是最佳的。振荡精度、边缘不对称性和碰撞检测环路延迟的不同组合导致采样点的最佳位置不同。
6.数据帧配置
作为发送端和接收端,奇偶校验方案配置在位域中FRAMECON.ODD。奇数位字段中的数据长度 DATCON.DATLEN和位域中的停止位 FRAMECON.STOP。
7.同步模式
在同步模式下,模块支持先移边后锁存边的SPI设置,如下图所示。该模块通过使用位字段FRAMECONN.MODE设置为同步模式。
7.1波特率和时钟产生
同步模式的波特率和时钟产生与异步模式一般使用相同的计数器和原理。唯一的区别是移位时钟驱动作为输出信号在引脚SCLKO。
7.2 数据帧配置
前置和后置延迟在位字段 FRAMECON.LEAD和FRAMECON.STOP中配置。IDLE相位持续时间通过FRAMECON.IDLE字段配置。DATCON.DATLEN字段定义了2到16位的数据长度。
7.3 从机选择配置
SPI主机自动激活每个数据字的从机选择输出信号。从机选择的极性可以通过使用IOCR.SPOL来配置,也支持环回模式。
8.内核寄存器
寄存器地址空间
寄存器概述
每个寄存器的详细描述见数据手册,这里就不一一赘述了。
9.代码实现
#include "IfxAsclin_Asc.h"
#include "IfxCpu_Irq.h"
#define UART_BAUDRATE 115200 /* UART波特率 bit/s*/
#define UART_PIN_RX IfxAsclin0_RXA_P14_1_IN /* UART接收引脚 */
#define UART_PIN_TX IfxAsclin0_TX_P14_0_OUT /* UART发送引脚 */
#define INTPRIO_ASCLIN0_RX 18 /* 接受中断优先级 */
#define INTPRIO_ASCLIN0_TX 19 /* 发送中断优先级 */
#define ISR_INTPRIO_ASCLIN_ER 22 /* 中断ISR错误的优先级 */
#define UART_RX_BUFFER_SIZE 64 /* 接收缓冲区大小 */
#define UART_TX_BUFFER_SIZE 64 /* 发送缓冲区大小 */
#define SIZE 13 /* 字符串数据大小 */
#define LED &MODULE_P22,0
static IfxAsclin_Asc g_ascHandle;
static uint8 g_ascTxBuffer[UART_TX_BUFFER_SIZE + sizeof(Ifx_Fifo) + 8];
static uint8 g_ascRxBuffer[UART_RX_BUFFER_SIZE + sizeof(Ifx_Fifo) + 8];
uint8 g_txData[] = "Hello World!";
uint8 g_rxData[SIZE] = {0};
Ifx_SizeT g_count = sizeof(g_txData);
/* UART发送中断服务历程 */
IFX_INTERRUPT(asclin0TxISR, 0, INTPRIO_ASCLIN0_TX);
void asclin0TxISR(void)
{
IfxAsclin_Asc_isrTransmit(&g_ascHandle);
IfxPort_setPinState(LED, IfxPort_State_low);
}
/* UART接受中断服务历程 */
IFX_INTERRUPT(asclin0RxISR, 0, INTPRIO_ASCLIN0_RX);
void asclin0RxISR(void)
{
IfxAsclin_Asc_isrReceive(&g_ascHandle);
IfxPort_setPinState(LED, IfxPort_State_high);
}
/* ISR中断错误服务历程 */
IFX_INTERRUPT(asclin0ErrISR, 0, ISR_INTPRIO_ASCLIN_ER);
void asclin0ErrISR(void)
{
IfxAsclin_Asc_isrError(&g_ascHandle);
}
/*****************************************************************************************************
* @projectName: void init_ASCLIN_UART(void)
* @introduction: ASCLIN模块初始化函数
* @parameter: void
* @return: void
* @author: Unicorn
* @date: 2024/6/20
* @version: 1.0
* @note:
*****************************************************************************************************/
void init_ASCLIN_UART(void)
{
/* 先用默认值初始化 */
IfxAsclin_Asc_Config ascConfig;
IfxAsclin_Asc_initModuleConfig(&ascConfig, &MODULE_ASCLIN0);
/* 设置中断优先级 */
ascConfig.interrupt.txPriority = INTPRIO_ASCLIN0_TX;
ascConfig.interrupt.rxPriority = INTPRIO_ASCLIN0_RX;
ascConfig.interrupt.erPriority = ISR_INTPRIO_ASCLIN_ER;
ascConfig.interrupt.typeOfService = IfxCpu_Irq_getTos(IfxCpu_getCoreIndex());
/*IfxCpu_getCoreIndex() 函数用于获取当前执行代码的CPU核心索引 */
/*IfxCpu_Irq_getTos() 函数则是用来获取当前CPU核心的最高优先级中断状态*/
/*IfxCpu_Irq_getTos(IfxCpu_getCoreIndex())作用是获取当前CPU核心的当前最高优先级中断的状态。这可以用于调试或监控中断处理流程,了解系统在任何给定时间点上最紧急需要处理的中断是什么。*/
/* 使能错误标志位 */
ascConfig.errorFlags.ALL = 1; /* 全部使能 */
ascConfig.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M
ascConfig.baudrate.prescaler = 4;
ascConfig.baudrate.baudrate = UART_BAUDRATE; /* 设置波特率 */
ascConfig.baudrate.oversampling = IfxAsclin_OversamplingFactor_16;
ascConfig.frame.stopBit = IfxAsclin_StopBit_1; //停止位
ascConfig.frame.parityType = IfxAsclin_ParityType_even; //偶校验
ascConfig.frame.dataLength = IfxAsclin_DataLength_8;
ascConfig.frame.parityBit = TRUE; //启动校验
/* FIFO 配置 */
ascConfig.txBuffer = &g_ascTxBuffer;
ascConfig.txBufferSize = UART_TX_BUFFER_SIZE;
ascConfig.rxBuffer = &g_ascRxBuffer;
ascConfig.rxBufferSize = UART_RX_BUFFER_SIZE;
/* 引脚配置 */
const IfxAsclin_Asc_Pins pins =
{
NULL_PTR, IfxPort_InputMode_pullUp,
&UART_PIN_RX, IfxPort_InputMode_pullUp,
NULL_PTR, IfxPort_OutputMode_pushPull,
&UART_PIN_TX, IfxPort_OutputMode_pushPull,
IfxPort_PadDriver_cmosAutomotiveSpeed1
};
ascConfig.pins = &pins;
/* 用上述参数初始化模块 */
IfxAsclin_Asc_initModule(&g_ascHandle, &ascConfig);
IfxPort_setPinMode(LED, IfxPort_Mode_outputPushPullGeneral);
IfxPort_setPinState(LED, IfxPort_State_low);
}
/*****************************************************************************************************
* @projectName: void uart_write_byte (const uint8 dat)
* @introduction: 串口发送一个字节
* @parameter: dat 要发送的数据
* @return: void
* @author: Unicorn
* @date: 2024/6/24
* @version: 1.0
* @note:
*****************************************************************************************************/
void uart_write_byte (uint8 dat)
{
while(IfxAsclin_getTxFifoFillLevel(g_ascHandle.asclin) != 0);
IfxAsclin_write8(g_ascHandle.asclin, &dat, 1);
}
/*****************************************************************************************************
* @projectName: void uart_write_string (const char *str)
* @introduction: 串口发送一个字符串
* @parameter: *str
* @return: void
* @author: Unicorn
* @date: 2024/6/24
* @version: 1.0
* @note:
*****************************************************************************************************/
void uart_write_string (const char *str)
{
while(*str)
{
uart_write_byte(*str++);
}
}
/*****************************************************************************************************
* @projectName: uart_write_buffer (const uint8 *buff, uint32 len)
* @introduction: 串口发送数组
* @parameter: *buff
* @parameter: len
* @return: void
* @author: Unicorn
* @date: 2024/6/24
* @version: 1.0
* @note:
*****************************************************************************************************/
void uart_write_buffer (const uint8 *buff, uint32 len)
{
while(len)
{
uart_write_byte(*buff);
len--;
buff++;
}
}
/*****************************************************************************************************
* @projectName: uint8 uart_read_byte (void)
* @introduction: 读取串口接收的数据(whlie等待)
* @parameter: void
* @return: uint8 接收的数据
* @author: Unicorn
* @date: 2024/6/24
* @version: 1.0
* @note:
*****************************************************************************************************/
uint8 uart_read_byte (void)
{
uint8 return_num = 0;
while(IfxAsclin_getRxFifoFillLevel(g_ascHandle.asclin) == 0);
IfxAsclin_read8(g_ascHandle.asclin, &return_num, 1);
return return_num;
}
/*****************************************************************************************************
* @projectName: void send_receive_ASCLIN_UART_message(void)
* @introduction: 发送和接受字符串
* @parameter: void
* @return: void
* @author: Unicorn
* @date: 2024/6/20
* @version: 1.0
* @note:
*****************************************************************************************************/
void send_receive_ASCLIN_UART_message(void)
{
IfxAsclin_Asc_write(&g_ascHandle, g_txData, &g_count, TIME_INFINITE);
//IfxAsclin_Asc_read(&g_ascHandle, g_rxData, &g_count, TIME_INFINITE);
}