AURIX TC2XX 学习笔记(5) 同步/异步接口(ASCLIN)

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);
}

 

S32K144是恩智浦(NXP)推出的一款32位汽车级微控制器(MCU),广泛应用于汽车和工业控制等领域。DMA(直接内存访问)是一种允许硬件子系统直接读写系统内存的技术,而无需CPU的介入,这可以大大提高数据传输的效率。UART(通用异步收发传输器)是一种常用的串行通信接口。 在S32K144中使用DMA进行UART空闲中断接收的例程,主要涉及到以下几个步骤: 1. 初始化UART模块,配置波特率、数据位、停止位和校验位等参数,确保UART通信正常工作。 2. 初始化DMA模块,设置传输数据的源地址、目标地址和传输大小等参数。源地址通常是UART接收缓冲区的地址,目标地址可以是用户自定义的RAM缓冲区地址。 3. 配置DMA触发源为UART空闲中断,当UART接收到数据并保持空闲状态一段时间后,触发DMA传输。 4. 配置DMA传输模式,根据需求选择合适的传输方向(从UART到内存)和传输类型(循环或单次传输)。 5. 开启DMA通道,并使能UART空闲中断。 6. 在DMA中断服务程序中添加适当的处理逻辑,比如处理接收到的数据,以及在数据处理完毕后重新启动DMA接收等。 下面是一个简化的代码示例框架,用于说明如何实现上述功能: ```c #include "S32K144.h" // UART初始化函数 void UART_Init(void) { // 这里填写初始化UART的代码,配置波特率等相关参数 } // DMA初始化函数 void DMA_Init(void) { // 这里填写初始化DMA的代码,配置源地址、目标地址和传输大小等参数 } // UART空闲中断处理函数 void UART1_RX_IDLE_ISR(void) { // 这里填写处理接收到的数据的代码 // 处理完毕后,可以停止当前DMA传输并重新启动新的DMA传输 } int main(void) { UART_Init(); // 初始化UART DMA_Init(); // 初始化DMA // 配置UART空闲中断,使能DMA接收 // 主循环 while(1) { // 用户代码 } } // 假设的DMA中断服务程序 void DMA채널中断服务程序(void) { // 中断处理代码,这里需要根据实际的DMA通道和中断向量填写 } ``` 注意:上述代码仅提供一个框架性的示例,实际编写时需要根据S32K144的具体寄存器配置和中断向量表来编写详细的初始化和中断处理函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值