IMX6LL|串口通信

在这里插入图片描述

相关寄存器

  • UART1时钟源

    • CCM_CSCDR1
  • 初始化 UART1

    • UART1_UCR1:使能uart1、自动波特率

    • UART1_UCR2:设置串口的发送帧格式

      • 奇偶校验位、软件复位

      • 数据长度

      • 发送完成标志、数据接受标志

      • 发送使能、接收使能

    • UART1_UCR3:bit2置1,官方要求设置

    • UART1_UFCR:时钟分频、发送与接收的 fifo大小

    • UART1_UBIR、UART1_UBMR:波特率

在这里插入图片描述

  • 收发数据
    • UART1_UTXD :发送一个字符
    • UART1_URXD :接受一个字符

55.15 UART Memory Map/Register Definition

在这里插入图片描述

makefile修改

官方sdk的设置波特率函数使用了除法,需要提供gcc除法库

LIBPATH := -lgcc  -static -L/usr/lib/gcc/arm-none-eabi/6.3.1
  • -lgcc 表示会链接“libgcc.a”库

  • -static -L 表示静态库所在路径

代码:

#include "uart.h"



void uart_init(void)

{

    /*时钟初始化,设置 UART 根时钟,并设置为40MHz*/

    CCM->CSCDR1 &= ~(0x01 << 6); //设置UART选择 PLL3 / 6 = 80MHz

    CCM->CSCDR1 &= ~(0x3F);      //清零

    CCM->CSCDR1 |= (0x01 << 0);  //设置串口根时钟分频值为1,UART根时钟频率为:80M / (dev + 1) = 40MHz



    //禁用 UART1

    UART1->UCR1 &= ~UART_UCR1_UARTEN_MASK; 



    /*软件复位*/

    UART1->UCR2 &= ~UART_UCR2_SRST_MASK;

    while ((UART1->UCR2 & UART_UCR2_SRST_MASK) == 0)

    {

    }

  

    /*引脚初始化*/

    IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX, 0);     

    IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX, 0x10b0);



    IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX, 0);

    IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX, 0x10b0);



    /*******uart初始化******/

    /*设置控制寄存器到默认值*/

    UART1->UCR2 |= (1 << 5);  //8位数宽度

    UART1->UCR2 &= ~(1 << 6); //一位停止位

    UART1->UCR2 &= ~(1 << 8); //禁用奇偶校验位



    UART1->UCR2 |= (1 << 2);  //使能发送

    UART1->UCR2 |= (1 << 1);  //使能接收

    UART1->UCR2 |= (1 << 14); //忽略流控



    /* For imx family device, UARTs are used in  mode, so that this bit should always be set.*/

    UART1->UCR3 |= UART_UCR3_RXDMUXSEL_MASK;



    //UART1->UFCR = (UART1->UFCR & ~UART_UFCR_TXTL_MASK) | UART_UFCR_TXTL(1); //设置发送FIFO 阀值

    //UART1->UFCR = (UART1->UFCR & ~UART_UFCR_TXTL_MASK) | UART_UFCR_TXTL(1); //设置接收FIFO 阀值



    UART1->UCR1 &= ~UART_UCR1_ADBR_MASK; //禁用可变波特率





    /*波特率设置方式 1 。 使用官方SDK设置波特率函数*/

   UART_SetBaudRate(UART1, 115200, 40000000);  //第三个参数是串口的时钟频率

#if 0

    /*波特率设置方式 2 。 手动计算,填入寄存器*/

    /*设置串口波特率

    * Ref Freq时钟 40MHz

    * UFCR RFDIV   110  0x06 7分频    5.714MHz

    * BaudRate     115200bps

    * UBMR         31-1 = 0x09

    * UBIR         10-1 = 0x1E

    */

    UART1->UFCR &= ~(0x07 << 7); //清零分频值

    UART1->UFCR |= (0x06 << 7);  //设置分频值,40MHz /7 =  5.714MHz



    UART1->UBIR = 0x09;

    UART1->UBMR = 0x1E;

#endif

    /*开启串口*/

    UART1->UCR1 |= UART_UCR1_UARTEN_MASK;



}





/*!

 * 功能:官方SDK 串口字符串读取函数

 * @brief Reads the receiver register.

 *

 * This function is used to read data from receiver register.

 * The upper layer must ensure that the receiver register is full or that

 * the RX FIFO has data before calling this function.

 *

 * @param base UART peripheral base address.

 * @return Data read from data register.

 */

static inline uint8_t UART_ReadByte(UART_Type *base)

{

    return (uint8_t)((base->URXD & UART_URXD_RX_DATA_MASK) >> UART_URXD_RX_DATA_SHIFT);

}





/*函数功能:串口接收函数

 *参数: base,指定串口。data,保存接收到的数据。 length,要接收的数据长度

 *

*/

void UART_ReadBlocking(UART_Type *base, uint8_t *data, uint8_t length)

{

    while (length--)

    {

        /* 等待接收完成 */

        while (!(base->USR2 & UART_USR2_RDR_MASK))

        {

        }

        /*读取接收到的数据 */

        *(data++) = UART_ReadByte(base);

    }

}





/*!

 * 功能:官方SDK 串口发送函数

 * 参数:base,指定串口。data,指定要发送的字节

 * This function is used to write data to transmitter register.

 * The upper layer must ensure that the TX register is empty or that

 * the TX FIFO has room before calling this function.

 */

static inline void UART_WriteByte(UART_Type *base, uint8_t data)

{

    base->UTXD = data & UART_UTXD_TX_DATA_MASK;

}



/*

 *功能:官方SDK 串口字符串发送函数

 *参数说明:

*/

void UART_WriteBlocking(UART_Type *base, const uint8_t *data, uint8_t length)

{



    while (length--)

    {

        /* Wait for TX fifo valid.

         * This API can only ensure that the data is written into the data buffer but can't

         * ensure all data in the data buffer are sent into the transmit shift buffer.

         */

        while (!(base->USR2 & UART_USR2_TXDC_MASK))

        {

        }

        UART_WriteByte(base, *(data++));

    }

}



/* 官方SDK 波特率设置函数,

 * 修改内容:修改了函数的返回值,波特率设置成功,返回1 。波特率设置失败返回 0

 *This UART instantiation uses a slightly different baud rate calculation.

 * Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)).

 * To get a baud rate, three register need to be writen, UFCR,UBMR and UBIR

 * At first, find the approximately maximum divisor of src_Clock and baudRate_Bps.

 * If the numerator and denominator are larger then register maximum value(0xFFFF),

 * both of numerator and denominator will be divided by the same value, which

 * will ensure numerator and denominator range from 0~maximum value(0xFFFF).

 * Then calculate UFCR and UBIR value from numerator, and get UBMR value from denominator.

 */

int32_t UART_SetBaudRate(UART_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)

{

    uint32_t numerator = 0u;

    uint32_t denominator = 0U;

    uint32_t divisor = 0U;

    uint32_t refFreqDiv = 0U;

    uint32_t divider = 1U;

    uint64_t baudDiff = 0U;

    uint64_t tempNumerator = 0U;

    uint32_t tempDenominator = 0u;



    /* get the approximately maximum divisor */

    numerator = srcClock_Hz;

    denominator = baudRate_Bps << 4;

    divisor = 1;



    while (denominator != 0)

    {

        divisor = denominator;

        denominator = numerator % denominator;

        numerator = divisor;

    }



    numerator = srcClock_Hz / divisor;

    denominator = (baudRate_Bps << 4) / divisor;



    /* numerator ranges from 1 ~ 7 * 64k */

    /* denominator ranges from 1 ~ 64k */

    if ((numerator > (UART_UBIR_INC_MASK * 7)) || (denominator > UART_UBIR_INC_MASK))

    {

        uint32_t m = (numerator - 1) / (UART_UBIR_INC_MASK * 7) + 1;

        uint32_t n = (denominator - 1) / UART_UBIR_INC_MASK + 1;

        uint32_t max = m > n ? m : n;

        numerator /= max;

        denominator /= max;

        if (0 == numerator)

        {

            numerator = 1;

        }

        if (0 == denominator)

        {

            denominator = 1;

        }

    }

    divider = (numerator - 1) / UART_UBIR_INC_MASK + 1;



    switch (divider)

    {

        case 1:

            refFreqDiv = 0x05;

            break;

        case 2:

            refFreqDiv = 0x04;

            break;

        case 3:

            refFreqDiv = 0x03;

            break;

        case 4:

            refFreqDiv = 0x02;

            break;

        case 5:

            refFreqDiv = 0x01;

            break;

        case 6:

            refFreqDiv = 0x00;

            break;

        case 7:

            refFreqDiv = 0x06;

            break;

        default:

            refFreqDiv = 0x05;

            break;

    }

    /* Compare the difference between baudRate_Bps and calculated baud rate.

     * Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)).

     * baudDiff = (srcClock_Hz/divider)/( 16 * ((numerator / divider)/ denominator).

     */

    tempNumerator = srcClock_Hz;

    tempDenominator = (numerator << 4);

    divisor = 1;

    /* get the approximately maximum divisor */

    while (tempDenominator != 0)

    {

        divisor = tempDenominator;

        tempDenominator = tempNumerator % tempDenominator;

        tempNumerator = divisor;

    }

    tempNumerator = srcClock_Hz / divisor;

    tempDenominator = (numerator << 4) / divisor;

    baudDiff = (tempNumerator * denominator) / tempDenominator;

    baudDiff = (baudDiff >= baudRate_Bps) ? (baudDiff - baudRate_Bps) : (baudRate_Bps - baudDiff);



    if (baudDiff < (baudRate_Bps / 100) * 3)

    {

        base->UFCR &= ~UART_UFCR_RFDIV_MASK;

        base->UFCR |= UART_UFCR_RFDIV(refFreqDiv);

        base->UBIR = UART_UBIR_INC(denominator - 1);

        base->UBMR = UART_UBMR_MOD(numerator / divider - 1);

        base->ONEMS = UART_ONEMS_ONEMS(srcClock_Hz / (1000 * divider));



        return 1;

    }

    else

    {

        return 0;

    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

左手的月光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值