感芯MC3172开发板入门(一)呼吸灯

        最近,在微信公众号的推荐里面看到了这款单片机,厦门感芯科技的MC3172芯片,具有硬件多线程实现的功能,可以摆脱单片机那种RTOS的线程调度问题,不用考虑资源占用问题。在一定程序上,可以代替功能简单的FPGA,具有了完全并行的处理能力。重点是这款芯片还可以免费申请,就去申请体验了一下,3天左右就寄到了,到了周末正好可以玩一下。

        这款芯片有两个特别的地方:

        1,并行多线程,有点大家理解;

        2,12个通信接口可配置。

        开发板很简单,基本上引出了所有的IO,上图。

        开发板自带下载器,软件开发软件使用的是

官方资料合集:1. MC3172芯片资料合集稳定版 - - - 厦门感芯科技有限公司

开源仓库:https://gitee.com/gxchip1.

工程模板:https://gitee.com/gxchip/mc3172_template2.

CMAKE工程:https://github.com/dreamcmi/MC3172-CMake

开发工具:1. MRS:http://www.mounriver.com/download

        安装完软件后,开始干活,以点灯开始,想了想,这次做个呼吸灯把,查了下呼吸灯的原理,网上就有现成的,拿来就用。呼吸灯的原理参考了:

(143条消息) STM32——呼吸灯_hustcw98的博客-CSDN博客_stm32呼吸灯

​        手头有一个转接板,很久以前做的,有led,串行adc(LTC2360),原理图如下。

        当然,LTC2360的参考电压,应该用基准电压芯片,因为是试验板,就没有太讲究。

开发板通过SPI接口采集电压,根据电压值,改变呼吸灯的频率。很简单的一个设计。开发板的布局如下图使用,使用到的IO如下,PA12、PA13、PA14、PA15这四个用作GPIO,PC0、PC1、PC2、PC3用作SPI接口控制LTC2360,

    使用杜邦线完成两个板子的连接。

    硬件连接完成了,开始写代码,在写代码之前,先进行线程配置。

        配置界面比较友好,存储器有三种配置方式,可根据实际需要配置,时钟源有四种选择方式。共有四组线程,每组线程平分主时钟(200/4=50M),每组里面有16个线程,在进行平分,需要多少个线程,选择多少个线程。

        直接打开工程模板,界面如下图。

    左边为工程结构,右边为编辑区域。双击main.c

    找到配置的两个线程,开始代码编辑

呼吸灯采用线程1完成。

//delay函数来自【代码分享】利用内核定时器做通用delay函数 / 感芯科技 / WhyCan Forum(哇酷开发者社区)

void delay_us(u32 nus)

{

    u32 ticks;

    u32 told,tnow,tcnt=0;

    GET_CORE_CNT(told);                             //读取内核定时器数值

    ticks=nus*48;                                   //目标延时节拍数=需要延时时间(us)*CORE_CLK(MHz)/4

    if(ticks!=0)

    {

        while(1)

        {

            GET_CORE_CNT(tnow);

            if(tnow!=told)

            {

                if(tnow<told)tcnt=0xFFFFFFFF-told+tnow; //CORE_CNT递增32位,计算已延时节拍数

                else tcnt=tnow-told;

                if(tcnt>=ticks)break;                   //延时完成

            }

        };

    }

}

void GPIO_TEST(u32 gpio_sel)//, u32 aa)

{

        u32 var;

        u32 period;

    // 启动GPIOA并设置特权组及时钟频率

       INTDEV_SET_CLK_RST(GPIOB_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV2));

       // 使能GPIOA PIN0引脚

       GPIO_SET_OUTPUT_EN_VALUE(gpio_sel, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3 , GPIO_SET_ENABLE);

       delay = 500;

       while(1)

       {

           period = delay;

            GPIO_SET_OUTPUT_PIN_TO_1(gpio_sel, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3);//LED=1

            // 延时1s

            delay_us(20000);

           /************************/

            for (var = 0; var < period; ++var)

            {

                GPIO_SET_OUTPUT_PIN_TO_0(gpio_sel, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3);//LED =0

                delay_us(var);

                GPIO_SET_OUTPUT_PIN_TO_1(gpio_sel, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3);//LED=1

               delay_us(period-var);

               if(period !=delay)   //如果period已经更新,立即退出本次调节,按照新的数据,重新调节

                   break;

            }

               // GPIOA PIN0输出0

            GPIO_SET_OUTPUT_PIN_TO_0(gpio_sel, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3);//LED=0

            delay_us(20000);

            for (u32 var = period; var >0; --var)

            {

                GPIO_SET_OUTPUT_PIN_TO_0(gpio_sel, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3);//LED =0

                delay_us(var);

                GPIO_SET_OUTPUT_PIN_TO_1(gpio_sel, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3);//LED=1

                delay_us(period-var);

                if(period !=delay)   //如果period已经更新,立即退出本次调节,按照新的数据,重新调节

                    break;

            }

       }

}

void thread0_main(void)

{

    while(1){

        //user code section

        //GPIO_EXAMPLE(GPIOA_BASE_ADDR);

        GPIO_TEST(GPIOB_BASE_ADDR);//,GPIO_PIN0);

    }

    thread_end();

}

   

其中delay为全局变量,多个线程之间,可以通过全局变量进行信息传递。

LTC2360的控制使用线程2

void thread1_main(void)

{

    volatile u8 rx_data_temp[2];

    u16 ad_value=0;

    u8 tx_data_wp=0;

    u8 rx_data_rp=0;

    INTDEV_SET_CLK_RST(GPCOM8_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV2));

    GPCOM_SET_IN_PORT(GPCOM8_BASE_ADDR,(GPCOM_MASTER_IN_IS_P3));

    GPCOM_SET_OUT_PORT(GPCOM8_BASE_ADDR,( \

            GPCOM_P0_OUTPUT_ENABLE|GPCOM_P1_OUTPUT_ENABLE|GPCOM_P2_OUTPUT_ENABLE|GPCOM_P3_OUTPUT_DISABLE| \

            GPCOM_P0_IS_HIGH|      GPCOM_P1_IS_MASTER_CLK|GPCOM_P2_IS_MASTER_OUT|GPCOM_P3_IS_HIGH

                      ));

    GPCOM_SET_COM_MODE(GPCOM8_BASE_ADDR,(GPCOM_SPI_MASTER_MODE3|GPCOM_TX_MSB_FIRST|GPCOM_RX_MSB_FIRST));

    GPCOM_SET_COM_SPEED(GPCOM8_BASE_ADDR,24000000,1000000);

    GPCOM_SET_OVERRIDE_GPIO(GPCOM8_BASE_ADDR, ( \

            GPCOM_P0_OVERRIDE_GPIO| \

            GPCOM_P1_OVERRIDE_GPIO| \

            GPCOM_P2_OVERRIDE_GPIO| \

            GPCOM_P3_OVERRIDE_GPIO|GPCOM_P3_INPUT_ENABLE  \

                                              ));

    tx_data_wp=GPCOM_GET_TX_WP(GPCOM8_BASE_ADDR);

    rx_data_rp=GPCOM_GET_RX_WP(GPCOM8_BASE_ADDR);

    while(1){

        //user code section

        for (u32 var = 0; var < 100; ++var)

        {

            NOP();

        }

        GPCOM_SET_OUT_PORT(GPCOM8_BASE_ADDR,( \

                GPCOM_P0_OUTPUT_ENABLE|GPCOM_P1_OUTPUT_ENABLE|GPCOM_P2_OUTPUT_ENABLE|GPCOM_P3_OUTPUT_DISABLE| \

                GPCOM_P0_IS_LOW|      GPCOM_P1_IS_MASTER_CLK| GPCOM_P2_IS_MASTER_OUT|GPCOM_P3_IS_HIGH

                          ));

        GPCOM_SEND_TX_DATA(GPCOM8_BASE_ADDR,0,0xff);

        GPCOM_SEND_TX_DATA(GPCOM8_BASE_ADDR,1,0xff);

        tx_data_wp+=2;

        GPCOM_SEND_TX_WP(GPCOM8_BASE_ADDR,tx_data_wp);

        while(!(GPCOM_TX_FIFO_EMPTY(GPCOM8_BASE_ADDR))){};

        tx_data_wp=GPCOM_GET_TX_WP(GPCOM8_BASE_ADDR);

        while(rx_data_rp!=GPCOM_GET_RX_WP(GPCOM8_BASE_ADDR)){

            rx_data_temp[rx_data_rp&0x3]=GPCOM_GET_RX_DATA(GPCOM8_BASE_ADDR,rx_data_rp);

            rx_data_rp+=1;

        };

        rx_data_rp = 0;

        ad_value = rx_data_temp[0];

        ad_value = ad_value<<8;

        ad_value = ad_value + rx_data_temp[1];

        delay = ad_value>>6;

        GPCOM_SET_OUT_PORT(GPCOM8_BASE_ADDR,( \

                GPCOM_P0_OUTPUT_ENABLE|GPCOM_P1_OUTPUT_ENABLE|GPCOM_P2_OUTPUT_ENABLE|GPCOM_P3_OUTPUT_DISABLE| \

                GPCOM_P0_IS_HIGH|      GPCOM_P1_IS_MASTER_CLK| GPCOM_P2_IS_MASTER_OUT|GPCOM_P3_IS_HIGH

                          ));

    }

    thread_end();

}

LTC2360是12-bit的,连续读取两次,拼接完成后是16位,要把低4位处理一下,单片机通过SPI读取数据都是通过连续写0或者连续写ff实现的,数据读取必须配合写函数。

通过SPI写数据,数据写成功后,必须更新tx_data_wp这一点要注意。

    tx_data_wp=GPCOM_GET_TX_WP(GPCOM8_BASE_ADDR);

……

{

             tx_data_wp+=2;

             GPCOM_SEND_TX_WP(GPCOM8_BASE_ADDR,tx_data_wp);

             while(!(GPCOM_TX_FIFO_EMPTY(GPCOM8_BASE_ADDR))){};

         tx_data_wp=GPCOM_GET_TX_WP(GPCOM8_BASE_ADDR);

}

        目前开发板不支持在线仿真,看不到tx_data_wp变量的数据,初步猜测这个变量,是变化的。

至此,程序的功能,全部完成了。开始编译。

程序下载使用自主研发的工具,在工程模板里面就有。

        总而言之,这个单片机还是很好入门的,前期不少人进行了评测,资料比较充足。开发板的论坛地址为哇酷开发者社区。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值