您尚未登录。

#1 Re: 感芯科技 » [XMG助力国产][写给新手]一些常见的坑_持续更新... » 2022-09-19 13:45:34

9.底层的TIMER_GET_MAIN_CNT_RP函数有bug,返回值为2和3,官方技术推荐使用TIMER_GET_MAIN_CNT_ALL函数替代TIMER_GET_MAIN_CNT_RP和TIMER_GET_MAIN_CNT_ALL

//推荐使用这个
#define TIMER_GET_MAIN_CNT_ALL(TIMER_SEL,main_cnt,main_cnt_rp)          main_cnt = (*(volatile u32*)(TIMER_SEL+0x12*8));\
                                                                        main_cnt_rp = main_cnt>>24;\
                                                                        main_cnt = main_cnt&0x00ffffff

//有bug
#define TIMER_GET_MAIN_CNT_RP(TIMER_SEL,main_cnt_rp)                    main_cnt_rp = (*(volatile u8*)(TIMER_SEL+0x11*8))
#define TIMER_GET_MAIN_CNT(TIMER_SEL,main_cnt)                          main_cnt = (*(volatile u32*)(TIMER_SEL+0x10*8))

#2 感芯科技 » [XMG助力国产]基于三角波调制的带死区的互补PWM » 2022-09-18 17:42:55

XMGroupe.
回复: 1

[XMG助力国产生态]
@XMGroupe.

本文介绍使用MC3172实现基于三角波调制的带死区的互补PWM产生方法。

常见的PWM调制方法有三种,即向上计数 向下计数 向上-向下计数,此demo使用向上向下计数,MC3172的PWM输出方法比较灵活,能够满足不同的需要,但是其每个timer只有四个compare让其使用存在一定局限,希望下一代能够增加到至少六个compare。

1.初始化
此demo使用timer3的P0和P1当作EPWM的P和N。

#define Dead_time   1000                //死区时间设置

void Pwm_Init(u32 timer_sel,u32 Arr,u32 Cmp)
{
    INTDEV_SET_CLK_RST(timer_sel,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK));

    TIMER_SET_OVERRIDE_GPIO(timer_sel,(TIMER_P3_OVERRIDE_GPIO|TIMER_P3_PULL_UP| \
                                        TIMER_P2_OVERRIDE_GPIO|TIMER_P2_PULL_UP| \
                                        TIMER_P1_OVERRIDE_GPIO|TIMER_P1_PULL_UP| \
                                        TIMER_P0_OVERRIDE_GPIO|TIMER_P0_PULL_UP) \
                           );

    TIMER_SET_OUTPUT_EN(timer_sel,(TIMER_P0_OUTPUT_ENABLE |TIMER_P1_OUTPUT_ENABLE |TIMER_P2_OUTPUT_ENABLE |TIMER_P3_OUTPUT_ENABLE| \
								));
    //分为四组,做两对互补
    TIMER_SET_OUT_PORT(timer_sel,(TIMER_P0_IS_COMPARER0|TIMER_P1_IS_COMPARER1| \
                                    TIMER_P2_IS_COMPARER2|TIMER_P3_IS_COMPARER3| \
									));

    TIMER_SET_COMPARER_MODE(timer_sel,(TIMER_COMPARER3_NOT_FORCE|TIMER_COMPARER2_NOT_FORCE|TIMER_COMPARER1_NOT_FORCE|TIMER_COMPARER0_NOT_FORCE));

    //下面四条用于控制频率
    TIMER_SET_MAIN_CNT_BEGIN_VALUE0(timer_sel,TIMER_MAIN_CNT_COUNT_UP,0);
    TIMER_SET_MAIN_CNT_END_VALUE0(timer_sel,Arr);
    TIMER_SET_MAIN_CNT_BEGIN_VALUE1(timer_sel,TIMER_MAIN_CNT_COUNT_DOWN,Arr);
    TIMER_SET_MAIN_CNT_END_VALUE1(timer_sel,0);

    TIMER_SET_CMD(timer_sel,TIMER_CMD_RESTART);

    TIMER_SET_COMPARER0_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
    TIMER_SET_COMPARER0_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp-Dead_time));
    TIMER_SET_COMPARER0_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp-Dead_time));
    TIMER_SET_COMPARER0_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);

    TIMER_SET_COMPARER1_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
    TIMER_SET_COMPARER1_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp+Dead_time));
    TIMER_SET_COMPARER1_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp+Dead_time));
    TIMER_SET_COMPARER1_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);

    TIMER_SET_CMD(timer_sel,TIMER_CMD_RUN);
}

需要注意,采用向上-向下计数方法,其PWM频率为 系统频率/ARR/2,因此死区时间为 Dead_time * (2/系统频率)
此实验采用200M外部有源晶振,因此demo的PWM频率为100 000 000/ARR,死区时间为 1000*10ns = 10us(正常不需要这么大,此处为了验证EPWM在大占空比时能否实现强制输出)。

2.占空比修改函数

void Set_PWM_Duty(u32 timer_sel,u32 Arr,float Duty1)
{
    static u8 flag_set = 0;
    static float Duty_old = 0.0;
    static u32 Compare_old = 0;
    static u32 Cmp = 0;
    u32 CNT = 0;
    u8 RP = 0;

    if(Duty_old != Duty1)
    {
        Duty_old = Duty1;
        Cmp = (u32)(Duty1*Arr);
        flag_set = 0x80;        //最高位置1,开启修改占空比
    }
    if((flag_set & 0x80) != 0)      //判断最高位
    {
        if((Cmp > Dead_time)&&((Arr - Cmp) > Dead_time))     //P、N脚正常输出
        {
            TIMER_SET_COMPARER_MODE(timer_sel,(TIMER_COMPARER3_NOT_FORCE|TIMER_COMPARER2_NOT_FORCE| \
                    TIMER_COMPARER1_NOT_FORCE|TIMER_COMPARER0_NOT_FORCE));
        }
        else if(Cmp <= Dead_time)                            //P脚关闭输出
        {
            TIMER_SET_COMPARER_MODE(timer_sel,(TIMER_COMPARER3_NOT_FORCE|TIMER_COMPARER2_NOT_FORCE| \
                                TIMER_COMPARER1_NOT_FORCE|TIMER_COMPARER0_FORCE0));
        }
        else if(((Arr - Cmp) <= Dead_time))                  //N脚关闭输出
        {
            TIMER_SET_COMPARER_MODE(timer_sel,(TIMER_COMPARER3_NOT_FORCE|TIMER_COMPARER2_NOT_FORCE| \
                                TIMER_COMPARER1_FORCE0|TIMER_COMPARER0_NOT_FORCE));
        }

        TIMER_GET_MAIN_CNT_ALL(timer_sel,CNT,RP);
        if(RP == 1)         //不在规则区0,修改规则区0
        {
            if(flag_set == 0x80)   //第一次修改
            {
                flag_set = 0x81;   //修改标志位,规则0 次序1
                //compare0
                TIMER_SET_COMPARER0_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
                TIMER_SET_COMPARER0_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp-Dead_time));
                //compare1
                TIMER_SET_COMPARER1_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
                TIMER_SET_COMPARER1_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp+Dead_time));
            }
            else if(flag_set == 0x82)      //第二修改
            {
                flag_set = 0;   //修改标志位
                //compare0
                TIMER_SET_COMPARER0_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
                TIMER_SET_COMPARER0_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp-Dead_time));
                //compare1
                TIMER_SET_COMPARER1_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
                TIMER_SET_COMPARER1_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp+Dead_time));
            }
        }
        //修改规则1区
        else
        {
            if(flag_set == 0x80)   //第一修改
            {
                flag_set = 0x82;   //修改标志位,规则1 次序1
                //compare0
                TIMER_SET_COMPARER0_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp-Dead_time));
                TIMER_SET_COMPARER0_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
                //compare1
                TIMER_SET_COMPARER1_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp+Dead_time));
                TIMER_SET_COMPARER1_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
            }
            else if(flag_set == 0x81)      //第二修改,修改结束
            {
                flag_set = 0;   //修改标志位
                //compare0
                TIMER_SET_COMPARER0_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp-Dead_time));
                TIMER_SET_COMPARER0_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
                //compare1
                TIMER_SET_COMPARER1_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp+Dead_time));
                TIMER_SET_COMPARER1_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
            }
        }
    }
}

上面的函数实现了EPWM的占空比设置和死区校验,防止出现占空比寄存数大于死区时间时输出高电平的现象。

3.输出PWM
输出的PWM如下图所示
Snipaste_2022-09-18_17-40-36.jpg
在其占空比较小时,其输出电平被强制输出为低电平
Snipaste_2022-09-18_17-40-44.jpg

#3 Re: 感芯科技 » [XMG助力国产]MC3172驱动SSD1306 OLED » 2022-09-17 16:02:15

redstone8415 说:

2.4寸 12864 oled ssd1309驱动的可以用这个改出来吗?

可以的

#4 Re: 感芯科技 » [XMG助力国产]MC3172普通IO模拟UART-9600 » 2022-09-14 10:45:52

@XMGroupe.
补一个串口数据波形图,下图是1M波特率,每个bit占1us,8,N,1,低位先传。模拟串口改参数可以参照这个波形图自己写时序。
1M%E4%B8%B2%E5%8F%A3%E8%A7%A3%E7%A0%81.jpg

#5 感芯科技 » [XMG助力国产]MC3172普通IO模拟UART-9600 » 2022-09-13 16:45:19

XMGroupe.
回复: 7

[XMG助力国产生态]
@XMGroupe.

本文介绍MC3172普通IO模拟UART

此驱动通过软件延时实现,目前9600波特率能够稳定运行。
内部RC高速时钟 192M

1.初始化代码

typedef enum _TX_STATE_{
    eUART_TX_IDLE = 0,      //发送空闲
    eUART_TX_SEND = 1,      //发送数送
}eTX_STATE;
typedef struct _eUART_TX_{
    eTX_STATE tx_state;                      //发送状态
    u32 bound;                         //波特率
    u8  nstop;                         //停止位数
}eUART_TX;

typedef enum _RX_STATE_{
    eUART_RX_IDLE = 0,      //接收空闲
    eUART_RX_RECV = 1,      //接收数据
}eRX_STATE;
typedef struct _eUART_RX_{
    eTX_STATE rx_state;                      //发送状态
    u32 bound;                         //波特率
    u8  nstop;                         //停止位数
}eUART_RX;

eUART_TX    exUART_TX;
eUART_RX    exUART_RX;
void Uart_Soft_Init(u32 Rate)
{
    /*启动外设*/
    INTDEV_SET_CLK_RST(GPIOA_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV8));//24M
    GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
    GPIO_SET_INPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN5),GPIO_SET_ENABLE);

    GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));

    exUART_TX.bound = Rate;
    exUART_TX.nstop = 1;
    exUART_TX.tx_state = eUART_TX_IDLE;
}

2.发送程序

/***   euart开始位   ***/
/*
 * baud 波特率
 */
void Send_Start_Soft(eUART_TX *extx)
{
    GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
    GPIO_SET_OUTPUT_PIN_TO_0(GPIOA_BASE_ADDR,(GPIO_PIN4));
    delay_baud(extx->bound);

    //GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN6));
}
/***   euar停止位   ***/
/*
 * baud 波特率
 * stop 停止位数
 */
void Send_Stop_Soft(eUART_TX *extx)
{
    GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
    GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));
    delay_baud(extx->bound);
}
/***   euart空闲   ***/
/*
 * baud 波特率
 * stop 停止位数
 */
void Send_Idle_Soft(eUART_TX *extx)
{
    GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
    GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));
    extx->tx_state = eUART_TX_IDLE;             //空闲标志位置
}
//发送单个byte
void Send_Byte_Soft(unsigned char dat)
{
    u8 i = 0;
    while(exUART_TX.tx_state == eUART_TX_SEND);     //等待总线空闲
    if(exUART_TX.tx_state == eUART_TX_IDLE)         //总线空闲
    {
        exUART_TX.tx_state = eUART_TX_SEND;         //总线忙
        Send_Start_Soft(&exUART_TX);
        for(i = 0; i < 8; i++)
        {
            if(dat&0x01)
            {
                GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
                GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));
            }
            else
            {
                GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
                GPIO_SET_OUTPUT_PIN_TO_0(GPIOA_BASE_ADDR,(GPIO_PIN4));
            }
            dat = dat >> 1;
            delay_baud(exUART_TX.bound);
        }
        Send_Stop_Soft(&exUART_TX);
    }
    Send_Idle_Soft(&exUART_TX);
}
//发送字符串
void Send_String_Soft(u8 *dat, u16 len)
{
    u8 temp = 0;
    u16 send_count = 0;
    u8 i = 0;
    while(send_count < len)
    {
        exUART_TX.tx_state = eUART_TX_SEND;         //总线忙
        temp = dat[send_count];
        Send_Start_Soft(&exUART_TX);
        for(i = 0; i < 8; i++)
        {
            if(temp&0x01)
            {
                GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
                GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));
            }
            else
            {
                GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
                GPIO_SET_OUTPUT_PIN_TO_0(GPIOA_BASE_ADDR,(GPIO_PIN4));
            }
            temp = temp >> 1;
            delay_baud(exUART_TX.bound);
        }
        send_count ++;
        Send_Stop_Soft(&exUART_TX);
    }
    Send_Idle_Soft(&exUART_TX);
}

3.接收函数

u8 Recv_String_Soft(u8 *recv, u16 len)
{
    u8 i = 0;
    u16 recv_count = 0;
    u8 dat = 0x00;

    while(recv_count < len)
    {
        //等待RX拉低,接收数据起始位
        while(((GPIO_GET_INPUT_VALUE_FAST(GPIOA_BASE_ADDR)&0x0020)>>5) != 0);
        //接收到起始位,设置为接收繁忙,延时波特率时间
        exUART_RX.rx_state = eUART_RX_RECV;
        delay_baud(exUART_TX.bound);
        NOP();
        for(i = 0; i < 8; i ++)
        {
            dat = dat >> 1;
            if(((GPIO_GET_INPUT_VALUE_FAST(GPIOA_BASE_ADDR)&0x0020) >> 5) == 1)
            {
                dat |= 0x80;
            }
            delay_baud(exUART_TX.bound);
        }
        recv[recv_count] = dat;
        dat = 0;
        recv_count ++;
        delay_baud(exUART_TX.bound);    //延时一个停止位时间
    }
    return recv_count;
}

4.延时函数

void delay_baud(u32 baud)
{
    u32 start,stop,ticks;
    start = CORE_CNT;
    if(baud == 9600)
    {
        ticks = 5002;
    }
    else
    {
//其他波特率对应延时自行添加
        //ticks = (u32)(Sys_Clk * 1000000 / baud);
    }
    if(0xFFFFFFFF-start>=ticks){
        stop=start+ticks;
        while(CORE_CNT<stop && CORE_CNT>start){}
    }
    else{
        stop=ticks-(0xFFFFFFFF-start);
        while(CORE_CNT>start){}
        while(CORE_CNT<stop){}
    }
}

最终效果
9600.jpg

*程序还有很多可以优化的地方,比如接收函数可以添加接收超时,此贴只作为一个DEMO,欢迎大家批评指正。
*也希望起到抛砖引玉的效果,能够看到更多优秀的程序开源。

#6 感芯科技 » [XMG助力国产]MC3172驱动DS18B20 » 2022-09-13 11:22:46

XMGroupe.
回复: 1

[XMG助力国产生态]
@XMGroupe.

本文介绍MC3172驱动DS18B20。

此驱动根据datasheet模拟实现。

1.初始化程序

#define DQ_Groupe   GPIOD_BASE_ADDR
#define DQ_IO       GPIO_PIN11

u8 DS18B20_Init(void)
{
    u16 temp = 0;
    u8 i = 0;

    INTDEV_SET_CLK_RST(GPIOD_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV2));
    GPIO_SET_OUTPUT_EN_VALUE(GPIOD_BASE_ADDR,GPIO_PIN11,GPIO_SET_ENABLE);
    //总线拉低 延时642us
    GPIO_SET_OUTPUT_PIN_TO_0(GPIOD_BASE_ADDR,GPIO_PIN11);
    delay_us(642);
    //总线拉高,DS18B20会在15us后将总线拉低
    GPIO_SET_OUTPUT_PIN_TO_1(GPIOD_BASE_ADDR,GPIO_PIN11);
    delay_us(15);

    GPIO_SET_INPUT_EN_VALUE(DQ_Groupe,DQ_IO,GPIO_SET_ENABLE);
    temp = (GPIO_GET_INPUT_VALUE_SAFE(DQ_Groupe) & 0x0800) >> 11;
    while(temp)
    {
        temp = (GPIO_GET_INPUT_VALUE_SAFE(DQ_Groupe) & 0x0800) >> 11;
        delay_us(10);
        i++;
        if(i > 100)
        {
            return 0;
        }
    }
    return 1;

}

2.读写字节

//读一个字节
u8 DS18B20_ReadByte(void)
{
    u8 i = 0;
    u16 dat = 0;
    u8 byte = 0;
    for(i = 8; i > 0; i --)
    {
        //先把总线拉低1us
        GPIO_SET_OUTPUT_EN_VALUE(DQ_Groupe,DQ_IO,GPIO_SET_ENABLE);
        GPIO_SET_OUTPUT_PIN_TO_0(DQ_Groupe,DQ_IO);
        delay_us(1);
        //释放总线,延迟6us
        GPIO_SET_OUTPUT_PIN_TO_1(DQ_Groupe,DQ_IO);
        delay_us(6);
        //读取数据
        GPIO_SET_INPUT_EN_VALUE(DQ_Groupe,DQ_IO,GPIO_SET_ENABLE);
        dat = (GPIO_GET_INPUT_VALUE_SAFE(DQ_Groupe) & 0x0800) >> 11;

        byte = (byte >> 1) | (dat << 7);
        //等待48us后读取下一位
        delay_us(48);
    }
    return byte;
}
//写一个字节
void DS18B20_WriteByte(unsigned char dat)
{
    u8 i = 0;
    u16 temp = 0;
    for(i = 8; i > 0; i --)
    {
        //写入每一位数据前先把总线拉低1us
        GPIO_SET_OUTPUT_EN_VALUE(DQ_Groupe,DQ_IO,GPIO_SET_ENABLE);
        GPIO_SET_OUTPUT_PIN_TO_0(DQ_Groupe,DQ_IO);
        delay_us(1);
        //写入数据,低位开始
        if(dat & 0x01)
        {
            GPIO_SET_OUTPUT_PIN_TO_1(DQ_Groupe,DQ_IO);
        }
        else
        {
            GPIO_SET_OUTPUT_PIN_TO_0(DQ_Groupe,DQ_IO);
        }
        dat = dat >> 1;
        //总线数据持续60us
        delay_us(60);
        //释放总线,延时1us
        GPIO_SET_OUTPUT_PIN_TO_1(DQ_Groupe,DQ_IO);
        delay_us(1);
    }
}

3.读取温度

int DS18B20_ReadTemp(void)
{
    int temp = 0;
    u8 tmh,tml;
    //启动转换
    DS18B20_Init();
    delay_ms(1);
    DS18B20_WriteByte(0xcc);
    DS18B20_WriteByte(0x44);
    //发送温度读取指令
    DS18B20_Init();
    delay_ms(1);
    DS18B20_WriteByte(0xcc);
    DS18B20_WriteByte(0xbe);
    //读取温度
    tml = DS18B20_ReadByte();
    tmh = DS18B20_ReadByte();
    temp = (tmh << 8) | tml;
    return temp;
}

4.数据转换为浮点

float datatrans(int temp)
{
    float temp_re = 0;
    float tp;
    if(temp < 0)             //当温度值为负数
    {
        //因为读取的温度是实际温度的补码,所以减1,再取反求出原码
        temp = temp - 1;
        temp = ~temp;
        tp = temp;
        temp_re = tp*0.0625+0.0005;//四舍五入
        temp_re = temp_re * (-1);
    }
    else
    {
        tp = temp;
        temp_re = tp*0.0625+0.0005;
    }
    return temp_re;
}

最终效果
FluxBB bbcode

#7 Re: 感芯科技 » [XMG助力国产][写给新手]一些常见的坑_持续更新... » 2022-09-12 19:45:42

8、使用多个线程刷新显示屏时,需要加入一个刷新忙碌标志位,否则屏幕会乱码。

#8 感芯科技 » [XMG助力国产][写给新手]一些常见的坑_持续更新... » 2022-09-11 01:02:21

XMGroupe.
回复: 3

[XMG助力国产生态]
@XMGroupe.

此贴记录了拿到核心板使用至今踩过的一些坑。
----------------------------------------------
0、IO口的常见配置在工程的GPIO_GPCOM_TIMER_Example.c文件中,一些常见操作可以参考或修改参数直接使用,如果不小心将其加入到了编译。只需要在对应.c文件上右键 点击 Include/Exclude From Build即可。

1、设置IO COM模式后,如果想要使用GPIO_GET_INPUT_VALUE_SAFE来读取IO的电平,需要同时使能COM对应的GPIO时钟
例如:
INTDEV_SET_CLK_RST(COMx,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV8));
此处没有使能GPIOx_BASE_ADDR的时钟,
此时使用GPIO_GET_INPUT_VALUE_SAFE读取对应IO电平将得到全0值,
但是GPIO_GET_INPUT_VALUE_FAST可以正常使用。

INTDEV_SET_CLK_RST(COMx,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV8));
INTDEV_SET_CLK_RST(GPIOx_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV8));
此处使能了GPIOx_BASE_ADDR的时钟,
此时使用GPIO_GET_INPUT_VALUE_SAFE和GPIO_GET_INPUT_VALUE_FAST均可读取对应IO电平。

2、使用GPIO_GET_INPUT_VALUE_XXXX读取的电平返回值是十六位无符号,请注意被赋值变量的位数是否合理。

3、MC3172.h文件中第212行存在一处bug,应修改为
#define GPIO_GET_INPUT_VALUE_FAST(GPIO_SEL)     (*(volatile u16*)(GPIO_SEL+GPIO_READ_REAL_INPUT_VALUE_ADDR))

4、GPIO_SET_OUTPUT_PIN_VALUE用来设置IO的输出电平,其mask表示指定的IO口,value为16位输入,不要直接对value赋1或0进行设置
错误范例
GPIO_SET_OUTPUT_PIN_VALUE(GPIOA_BASE_ADDR,GPIO_PIN4,1);//A4设置为高电平
此处value值为0x0001,对应二进制 0000 0000 0000 0001,pin4为0
正确设置
GPIO_SET_OUTPUT_PIN_VALUE(GPIOA_BASE_ADDR,GPIO_PIN4,0x0010);//A4设置为高电平

5、有些功能需要IO口输入输出功能,参照51单片机,此处不必纠结太多,当需要在输入或输出切换时,只需要在对应的input函数或set函数前面加一句
GPIO_SET_OUTPUT_EN_VALUE(GPIOx_BASE_ADDR,GPIO_PINx,GPIO_SET_ENABLE);
GPIO_SET_INPUT_EN_VALUE(GPIOx_BASE_ADDR,GPIO_PINx,GPIO_SET_ENABLE);
即可。

6、外设速度与线程速度无关,在设置对应的外设COMx时,时钟分频是以系统主时钟进行分频的,与线程的频率无关,例如系统主时钟采用内部高速RC 192MHz,则在对COMx进行分频时,其分频基准为192M,与线程的1/4 1/8...无关。

7、断开USB线和核心板连接前,应先在烧写软件中进行断开连接操作,否则重新插入后烧写程序会无响应闪退。

*个人见解,不代表官方,如果有错误或描述不恰当的地方,欢迎官方和各位大佬批评指正。
*后面遇到新的坑会持续更新,

#9 感芯科技 » [XMG助力国产]MC3172核心板管脚图美化版 » 2022-08-25 00:20:36

XMGroupe.
回复: 7

[XMG助力国产生态]
@XMGroupe.

水个贴,自己用excell画的管脚图,找核心板的管脚功能和COM口很方便,分享给大家。

FluxBB bbcode

#11 感芯科技 » [XMG助力国产]MC3172驱动SSD1306 OLED » 2022-08-24 00:14:31

XMGroupe.
回复: 6

[XMG助力国产生态]
@XMGroupe.

本文介绍MC3172驱动SSD1306 OLED。

此驱动移植于STM32下的IIC驱动,对STM32工程中SSD1306OLED代码进行一些简单修改,完成OLED驱动。

修改内容:
1.更改IIC IO的初始化和控制函数;

void OLED_Gpio(void)
{
#ifdef OLED_ELOG
    log_i("OLED Gpio Initing");
#endif
    INTDEV_SET_CLK_RST(OLED_IOport,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV4));
    GPIO_SET_OUTPUT_EN_VALUE(OLED_IOport,(OLED_Sclk|OLED_Sdin),GPIO_SET_ENABLE);
    GPIO_SET_OUTPUT_PIN_TO_1(OLED_IOport,(OLED_Sclk|OLED_Sdin));
#ifdef OLED_ELOG
    log_i("OLED Gpio Init OK");
#endif
}
#define OLED_IOport GPIOA_BASE_ADDR
#define OLED_Sclk   GPIO_PIN14
#define OLED_Sdin   GPIO_PIN15

#define OLED_SCLK_Clr() GPIO_SET_OUTPUT_PIN_TO_0(OLED_IOport,OLED_Sclk);
#define OLED_SCLK_Set() GPIO_SET_OUTPUT_PIN_TO_1(OLED_IOport,OLED_Sclk);

#define OLED_SDIN_Clr() GPIO_SET_OUTPUT_PIN_TO_0(OLED_IOport,OLED_Sdin);
#define OLED_SDIN_Set() GPIO_SET_OUTPUT_PIN_TO_1(OLED_IOport,OLED_Sdin);

2.根据MC3172的IO速度优化IIC的时许;
3.加入EasyLogger调试输出代码,其使能宏定义在oled.h文件中。

#define OLED_ELOG

驱动流程:
1.将OLED驱动文件(包括oled.c+oled.h+oledfont.h)加入到工程中;
2.在oled.h中修改对应的IO口
*注:此处默认为一组IO口,即CLK和SDA都是PAx,若采用两个不同组的IO,需要修改oled.h中的IO控制函数和oled.c中的初始化函数。

#define OLED_IOport GPIOA_BASE_ADDR
#define OLED_Sclk   GPIO_PIN14
#define OLED_Sdin   GPIO_PIN15

3.在线程中添加初始化代码

OLED_Init();

*程序只实现了一些基本的显示函数,其他显示功能与常规单片机一致,可以直接添加稍作修改后使用。

最终效果
FluxBB bbcode
FluxBB bbcode

文件包
https://gitee.com/sxm90/MC3172/tree/master/SSD1306OLED

#12 感芯科技 » [XMG助力国产]MC3172移植EasyLogger » 2022-08-23 18:50:28

XMGroupe.
回复: 1

[XMG助力国产生态]
@XMGroupe.

本文介绍MC3172移植EasyLogger教程。

本人从Github中下载EasyLogger源代码后,移植到MC3172时没有像移植到STM32那么顺利。

咨询感芯技术后得知,官方没有移植标准库,标准库的代码需要自己实现。

因此对EasyLogger源代码进行了一些修改:
1.移除了BUF和ASYNC;
2.标准库的函数在elog.c中进行了实现(能力有限,有些代码可能不是最优化版本);
3.标准库的变量在elog.h中进行了声明;
4.代码的打印分隔符已经修改完,移植完可以直接使用;
5.代码添加后需要进行printf重定向,头文件引用在elog.c中;
6.elog_port_output中已经添加了输出函数。

void elog_port_output(const char *log, size_t size) {
    
    /* add your code here */
    printf_("%.*s", size, log);
}

*printf重定向方法可以参照论坛中的帖子添加开源printf库
*串口调试过程中出现的问题可以参照【调试记录】调整芯片主频之后串口需要修改串口初始化代码

移植流程:
1.将修改后的EasyLogger文件夹放入工程中;
2.修改printf重定向函数引用,在elog.c中

#include "../USER_CODE/printf.h"
#include "../USER_CODE/uart.h"

3.配置线程,可以参考官方给出的极简开发手册
4.在主函数中引用elog.h的头文件
5.在线程中初始化elog函数,初始化方法可以参考如下代码

    /* 初始化elog */
    elog_init();
    elog_set_text_color_enabled(true);//打开颜色模式
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG);
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~(ELOG_FMT_TIME | ELOG_FMT_P_INFO | ELOG_FMT_T_INFO));
    elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL);
    elog_start();

    log_a("Hello EasyLogger!");
    log_e("Hello EasyLogger!");
    log_w("Hello EasyLogger!");
    log_i("Hello EasyLogger!");
    log_d("Hello EasyLogger!");
    log_v("Hello EasyLogger!");

6.下载MobaXterm后配置端口进行测试

最终效果

FluxBB bbcode

文件包
https://gitee.com/sxm90/MC3172/tree/master/EasyLogger

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn