[研电赛技术支持]

GD32E230C8T6《调试篇》之 FMC(闪存)的读写 + USART打印

[复制链接]
1317|7
手机看帖
扫描二维码
随时随地手机跟帖
tfqi|  楼主 | 2024-2-4 13:44 | 显示全部楼层 |阅读模式
实验工具
        主芯片GD32E230C8T6 /4段8位数码管/GN1650驱动芯片(IIC通讯)/USART/485通讯芯片
1
GD32E230C8T6
8007265bf2450ee564.png
6762665bf244b08910.png

查看GPIO

4840165bf2444e4160.png
5097865bf24409d0fc.png

查看Datasheet 2.6.7章节GPIO 复用
6718665bf243b0572d.png
1774865bf24353f0ae.png
9935665bf242ceb7d3.png
说明使用PA9、 PA10的USART0时要选择AF1;
初始化USART0 时才有了这两句;
与GD32E103不同的是E230没有gpio_init这个库函数,所以参考例程是有帮助的;

    /* connect port to USARTx_Tx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);
    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);



查看用户手册
可以看到E230有64K的主flash,这里我选了0x0800 FC00,操作最后一页;


代码
main.h


//IIC所有操作函数
void i2c_init(void);  //初始化IIC的IO口       
static void IIC_Start1(void);
static void IIC_Stop1(void);
uint8_t IIC_Rev_Byte(void);  //对IIC数据进行读出
void IIC_Wrt_Byte(uint8_t data);                //IIC发送一个字节
void IIC_ACK(void);                                                //IIC发送信号
void IIC_NAck(void);                                        //IIC不发送ACK信号
void SDA_Rx(void);                                                //主机recv from 从机
/************** GN1650 **************/
void GN1650_display(void);                                //数码管显示
void  GN1650_display_D(void);                        //数码管无显示
void GN1650_Wrt_RAM(uint8_t Address, uint8_t Data);  //对IIC数据进行写入

uint8_t GetKey(void);                                        //按键扫描
/************** usart ************/
void usart0_init();       
/************** flash ************/
uint8_t FMC_FLASH_Write( u32 data );
uint8_t FMC_FLASH_Read(u32 *data );





main.c

#define READ_SDA gpio_input_bit_get(GPIOB,GPIO_PIN_7)
#define LEDDOT 0x80
#define MAXNUM  10

#define TIMEPRESS  350 //key press times
#define DIG1 17
#define DIG2 25
#define DIG3 21
#define DIG4 29
#define ADDRMAX 512
uint8_t i;

uint16_t value=0;
               
void myGPIO_init(void)
{
         /* enable GPIOB clock */
         rcu_periph_clock_enable(RCU_GPIOA);       
               
         gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ,GPIO_PIN_0);//PB6_42  I2C0_SCL GPIO_OTYPE_PP推挽输出
         gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_0);       
}

void keycheck(void)
{
        uint16_t KeyNum;
        uint16_t LastKeyNum = 0;
        static uint8_t Keyleased=1,fastCnt=0;
        static uint16_t keydowntime = 0;
       
        KeyNum = GetKey();
        switch(KeyNum)
        {
                case DIG2:
                       
                        if(keydowntime++ >= TIMEPRESS )//long press ++
                        {
                                keydowntime=TIMEPRESS;
                                if(++fastCnt>=10)//add press times 分频
                                {
                                        fastCnt=0;
                                        value++;
                                        if(value > ADDRMAX) value = 1;  //512 to 1
                                }                               
                        }
                        else if(Keyleased && keydowntime < TIMEPRESS )//short press ++
                        {
                                value++;       
                                Keyleased = 0;
                                if(value > ADDRMAX) value = 1;    //512 to 1
                        }                                                       
                        break;       
               
                case DIG3:       
                       
                        if( keydowntime++ >= TIMEPRESS)//long press --
                        {       
                                keydowntime=TIMEPRESS;
                                if(++fastCnt>=10)//add press times 分频
                                {
                                        fastCnt=0;
                                        value--;
                                        if(value == 0) value = ADDRMAX;   //0 to 512
                                }                                                               
                        }
                        else if(Keyleased  && keydowntime++ < TIMEPRESS )//short press --
                        {
                                value--;
                                Keyleased=0; //keydown locked       
                                if(value == 0) value = ADDRMAX;   //0 to 512
                        }
                                                       
                        break;
                       
                case DIG4:
                        if(Keyleased)
                        {                       
                                FMC_FLASH_Write(value);
               
                                printf("****value=%d****\r\n",value);
                               
                                Keyleased = 0;
                        }
                        break;
                       
                default:
                       
                        Keyleased=1;//keydown loosed
               
                        fastCnt=0;

                        keydowntime = 0;
                        //lontimeflag = 1;
                        break;
        }
}

//主函数处理
int main(void)
{
        uint8_t flag = 0;
       
        systick_config();
       
        delay_ms(10);
       
        usart0_init();
               
        //myGPIO_init();
       
        delay_ms(10);
       
        i2c_init();
       
        FMC_FLASH_Read((u32 *)&value);//read flash       

    while(1)
        {
                flag =!flag;
                gpio_bit_write(GPIOA,GPIO_PIN_0,flag);
                delay_ms(1);
               
                keycheck();
               
                GN1650_display();               
                                       
                //do work1
               
                //do work2                               
        }

}
/********** 数码管显示 **********/
void  GN1650_display(void)       
{               
        GN1650_Wrt_RAM(0x68,LEDENCODE[value/1000%10]);//high //0x48 系统指令  0x41//4级亮度 8段显示 显示开
        GN1650_Wrt_RAM(0x6A,LEDENCODE[value/100%10] );//   ;
        GN1650_Wrt_RAM(0x6C,LEDENCODE[value/10%10]);
        GN1650_Wrt_RAM(0x6E,LEDENCODE[value%10] ); //low
       
        GN1650_Wrt_RAM(0x48,0x01);
       
}
/********** 数码管无显示 **********/
void  GN1650_display_D(void)       
{
        GN1650_Wrt_RAM(0x48,0x00);
}
/**********  IIC初始化 *********/
void i2c_init(void)
{
         /* enable GPIOB clock */
         rcu_periph_clock_enable(RCU_GPIOB);
         /* enable I2C0 clock */
         rcu_periph_clock_enable(RCU_I2C0);
       
         /* connect PB6 to I2C0_SCL */
         gpio_af_set(GPIOB,GPIO_AF_1,GPIO_PIN_6);
         /* connect PB7 to I2C0_SDA */
         gpio_af_set(GPIOB,GPIO_AF_1,GPIO_PIN_7);
       
         gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ,GPIO_PIN_6);//PB6_42  I2C0_SCL
         gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_6);
       
         gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ,GPIO_PIN_7);//PB7_43  I2C0_SDA
         gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);
                       
         /* configure I2C0 clock */
         //i2c_clock_config(I2C0,60000,I2C_DTCY_2);

         /* enable I2C0 */
         i2c_enable(I2C0);
         /* enable acknowledge */
         i2c_ack_config(I2C0,I2C_I2CMODE_ENABLE);
         
         /*  空闲状态 */
         gpio_bit_write(GPIOB,GPIO_PIN_6,1);
         gpio_bit_write(GPIOB,GPIO_PIN_7,1);
         
         GN1650_Wrt_RAM(0x48,0x00);//关闭显示
                
}
void SDA_Rx(void)                                        //主机recv from 从机
{
         /* enable GPIOB clock */
         rcu_periph_clock_enable(RCU_GPIOB);
         gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);
       
}
void SDA_Tx(void)
{
         /* enable GPIOB clock */
         rcu_periph_clock_enable(RCU_GPIOB);
         gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ,GPIO_PIN_7);//PB7_43  I2C0_SDA
         gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);
}

void IIC_SCL(uint8_t n)
{
        gpio_bit_write(GPIOB,GPIO_PIN_6,n);
}

void IIC_SDA(uint8_t n)
{
        gpio_bit_write(GPIOB,GPIO_PIN_7,n);
}


static void IIC_Delay(void)
{
        __IO  uint16_t cnt=1;
        while(cnt--);
}

/*********************模拟IIC通信****************/
/*
*函数功能:IIC起始
*提    示:
*输入参数:无
*输出参数:无
*返回值  :无
*/
static void IIC_Start1(void)
{
        SDA_Tx();
        //2、SCL 1
        IIC_SCL(1);
        //3、SDA 1
        IIC_SDA(1);
        //延时5us
        IIC_Delay();
        //4、SCL 0
        IIC_SDA(0);
        //延时5us
        IIC_Delay();
        //5、SDA 0
        IIC_SCL(0);
        //延时5us
        IIC_Delay();               
}


/*
*函数功能:IIC结束
*提    示:
*输入参数:无
*输出参数:无
*返回值  :无
*/

static void IIC_Stop1(void)
{
        //2、SCL 1
        IIC_SCL(1);
        //3、SDA 0
        IIC_SDA(0);
        //延时5us
        IIC_Delay();
        //4、SDA 1
        IIC_SDA(1);
        //延时5us
        IIC_Delay();
}

/*
*函数功能:IIC应答
*提    示:
*输入参数:无
*输出参数:无
*返回值  :无
*/
void IIC_ACK(void)
{       
        SDA_Rx();
        IIC_SCL(0);
        IIC_Delay();
        IIC_SDA(0);        
        IIC_Delay();     
        IIC_SCL(1);
        IIC_Delay();                  
        IIC_SCL(0);                     
        IIC_Delay();
        SDA_Tx();
        IIC_SDA(0);       
        IIC_Delay();
               
}


/****************模拟IIC通信**************/

/* 描述:一个字节数据发送函数               
* 参数:  无
* 返回值:无                */

void IIC_Wrt_Byte(uint8_t data)
{
        int i;       
    IIC_SCL(0);    //拉低时钟开始数据传输
        for(i = 0;i < 8;i++)
        {
                IIC_SDA((data & 0x80)>0 ); //check bit7
        data <<= 1;           
                IIC_Delay();   //这三个延时都是必须的
                IIC_SCL(1);
                IIC_Delay();
                IIC_SCL(0);       
                IIC_Delay();       
        }       
}

/* 描述:一个字节数据接收函数               
* 参数:  无
* 返回值:接收到的字节数据                */

uint8_t IIC_Rev_Byte(void)
{
        uint8_t dat=0;
        uint8_t i;       

        SDA_Rx();                        /* 设置数据线为输入方式 */
        IIC_Delay();                    
        for(i = 0;i < 8;i++)
        {  
                IIC_SCL(0);                /* 设置时钟线为低,准备接收数据位        */
                IIC_Delay();               
                IIC_SCL(1);                /* 设置时钟线为高使数据线上数据有效  */              
                if(READ_SDA) dat|=0x80;        //同ret++; /* 读数据位,接收的数据位放入ret中 */
                dat>>=1;
                IIC_Delay();
        }
        IIC_SCL(0);
       
        return dat;
}

// write to RAM
void GN1650_Wrt_RAM(uint8_t Address, uint8_t Data)
{
        IIC_Start1();
    IIC_Wrt_Byte(Address);
    IIC_ACK();
    IIC_Wrt_Byte(Data);
    IIC_ACK();
    IIC_Stop1();       
}
/********** get 4 按键 ID **********/
uint8_t GetKey(void)
{
        uint8_t key=0;
       
        IIC_Start1();
        IIC_Wrt_Byte(0x49);
        IIC_ACK();
        key= IIC_Rev_Byte();
        IIC_ACK();
        IIC_Stop1();
        return key;
}

#define  ADDRSTART 0x0800FC00
/****************** flash write **************/
/*!
    \brief      FLASH写
    @address    操作地址
    @size       数据长度
*/
uint8_t FMC_FLASH_Write(u32 data)
{
    fmc_state_enum FLASHStatus;
    uint16_t i;   
    uint32_t Address = ADDRSTART;
       
    /* 解锁 */
    fmc_unlock();
        /* step1: erase pages */
    fmc_page_erase(Address);
    /* step2: 操作FMC前先清空STAT 状态寄存器,非常必要*/
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR );
    fmc_word_program(Address, data);
        fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR );
    /* 上锁 */
    fmc_lock();
    return 0;
}
/****************** flash read **************/

/*!
    \brief      FLASH读
    @Address    操作地址
    @DATA      数据指针
*/
uint8_t FMC_FLASH_Read(u32 *data)
{
    uint32_t Address = ADDRSTART;

    *data = *( __IO uint32_t* ) Address;
       
    return 0;

}

/****************** usart0 print **************/

void usart0_init() // 初始化串口0
{
        /* enable COM GPIO clock */
        rcu_periph_clock_enable(RCU_GPIOA);  // 使能GPIOA时钟
        rcu_periph_clock_enable(RCU_GPIOB);  // 使能GPIOB时钟
        rcu_usart_clock_config(CK_APB2);
        rcu_periph_clock_enable(RCU_USART0);  // 使能串口0时钟
       
        /* connect port to USARTx_Tx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);

    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);
       
        /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
       
        /* configure USART Rx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
       
        /*****  485 TX enable  ****/ //pin13--PB13       
        gpio_mode_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_13); //GPIO_OSPEED_2MHZ
        gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_13);
        gpio_bit_set(GPIOB,GPIO_PIN_13); //0-Rx  
       
        // 步骤1-7:
        usart_deinit(USART0);   //reset USART0
        usart_word_length_set(USART0,USART_WL_8BIT);  ///2、配置USART字长
        usart_stop_bit_set(USART0,USART_STB_1BIT);  ///3、配置USART停止位
        usart_parity_config(USART0, USART_PM_NONE);//4、奇偶校验位
        usart_baudrate_set(USART0,115200);  ///5、配置USART波特率
        usart_transmit_config(USART0,USART_TRANSMIT_ENABLE);  // 6、USART发送配置
        usart_receive_config(USART0,USART_RECEIVE_ENABLE);
               
        usart_enable(USART0);//使能串口       
       
        // 在nvic中配置中断向量和中断优先级
        nvic_irq_enable(USART0_IRQn,1); //使能NVIC的中断
        // 使能USART子中断   
        usart_interrupt_enable(USART0,USART_INT_RBNE);
}

// 中断处理函数
void USART0_IRQHandler(void)
{       
        // 串口2外部给串口2发送了数据,就会进入下面这个中断,然后把数据读取到data里面
        if( RESET != usart_interrupt_flag_get(USART0,USART_INT_FLAG_RBNE) )// 发生中断,则返回RESET
        {
                 usart_data_receive(USART0); // 读取串口接收到的数据               
        }
        usart_interrupt_flag_clear(USART0,USART_INT_FLAG_ERR_FERR);

}

/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
    usart_data_transmit(USART0, (uint8_t)ch);
    while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
    return ch;
}

————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_50406718/article/details/135750884

使用特权

评论回复
tpgf| | 2024-3-4 12:08 | 显示全部楼层
关于内存的读写 主要就是一个时序的问题吧

使用特权

评论回复
guanjiaer| | 2024-3-4 12:44 | 显示全部楼层
在读写内存的时候需要关闭中断使能吗

使用特权

评论回复
heimaojingzhang| | 2024-3-4 13:30 | 显示全部楼层
是直接控制的数码管还是通过专用芯片控制的啊

使用特权

评论回复
paotangsan| | 2024-3-4 14:22 | 显示全部楼层
这种接口的闪存的读取速度会不会比较快

使用特权

评论回复
renzheshengui| | 2024-3-4 19:10 | 显示全部楼层
代码里边iic通讯和普通串口通讯的功能是什么

使用特权

评论回复
keaibukelian| | 2024-3-4 19:42 | 显示全部楼层
有好几个功能的那种引脚还需要看看是不是默认的功能呢 如果不是还得配置

使用特权

评论回复
申小林一号| | 2024-4-30 16:57 | 显示全部楼层
非常不错的帖子,值得推广扩散!!!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

56

主题

3317

帖子

4

粉丝