基于RT_Thread 驱动WK2204扩展芯片

WK2204扩展芯片

WK2204是首款具备256级FIFO的低功耗并支持 UART/SPI/IIC总线接口的4通道UART器件。可以通过模式选择使得该芯片工作于以上任何一种主接口模式,将选定的主接口扩展为4个增强功能的UART。(我使用的是SPI接口)

SPI主接口特性

  1. 最高速度10M bit/s
  2. 仅支持SPI从模式
  3. SPI模式0
  4. 支持最长256字节连续收发

硬件连接
本次实验使用STM32F429IGT6作为主控芯片,使用spi3接口,挑选RS232_16串口进行通信。
在这里插入图片描述

CubeMX配置

在CubeMX中配置spi3,除了基本的时钟配置(时钟需要根据板子进行配置),spi3的配置如图所示(直接从RT-Thread Studio中进入CubeMX)
在这里插入图片描述
在这里插入图片描述
配置完成后,生成工程代码
在这里插入图片描述
提示备份配置文件,则配置成功,会看到工程中多出来一个cubemx文件夹
在这里插入图片描述

RT-Thread Studio配置

  1. 添加软件包和相关组件
    软件包只有wk2124版本,但是不影响我此次的使用
    在这里插入图片描述
  2. 保存配置会看到packages中多出来wk2204的文件夹(其中spi_slave.c文件是我自己加的,刚开始编译时wk2124_usart.c文件被帅选掉了,进入属性将其从过滤器中删除即可)
    在这里插入图片描述
  3. 为了程序更加简洁,我对wk2124_usart.c进行了一点点改动(不改动也能直接使用,只要选择好晶振频率并且在board.h中定PKG_USING_WK2124,同时打开对应的SPI即可)修改后代码如下:
#include "board.h"
#include <rtdevice.h>
#include <rthw.h>
#include <rtthread.h>

#include <stdio.h>

#include "wk2124_usart.h"
#include "wk2124s.h"

#include <drv_log.h>
//#define DRV_DEBUG

#ifdef PKG_USING_WK2124


//WK2124晶振频率,单位Hz
#ifndef WK2124_Fosc
    #define WK2124_Fosc     14745600
#endif


/* wk2124 uart driver */
struct wk2124_uart 
{
    uint8_t swk_index; 
    uint8_t irq_enable;
    struct rt_spi_device *spi_device;
};
typedef struct
{
    const char *name;
    struct wk2124_uart uart[4];
    struct rt_serial_device serialswk[4];
    struct rt_spi_device *wk2124_device;
    rt_int32_t irq_pin;
    struct rt_semaphore irq_sem;
}WK2124;

static WK2124 wk2124[]=
{
    {
        .name = "spi30",
        .irq_pin = 55,//PD7
        .wk2124_device = RT_NULL,
    },

    {
        .name = "spi31",
        .irq_pin = GET_PIN(D, 4),//PD4
        .wk2124_device = RT_NULL,
    },

    {
        .name = "spi40",
        .irq_pin = 68,//PE4
        .wk2124_device = RT_NULL,
    },

    {
        .name = "spi41",
        .irq_pin = 137,//PI9
        .wk2124_device = RT_NULL,
    },
};



static rt_err_t wk2124_configure(struct rt_serial_device *serial,
                              struct serial_configure *cfg)
{
    struct wk2124_uart *uart;
    uint16_t baudrate;
    uint8_t baudrate_h, baudrate_l, baudrate_dec, spage0_lcr;

    RT_ASSERT(serial != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);
    uart = (struct wk2124_uart *)serial->parent.user_data;

    /*切换到PAGE0页中的子串口寄存器组 */
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE(uart->swk_index),0x00);

    /*子串口 1 控制寄存器 */
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_SCR(uart->swk_index),0x00); //子串口 发送使能  接收使能

    spage0_lcr = 0;
    if (cfg->stop_bits > 0) {
        spage0_lcr |= 0x01;
    }
    if (cfg->parity == 1) {
        spage0_lcr &= 0xfb;
        spage0_lcr |= 0x02;
    } else if (cfg->parity == 2) {
        spage0_lcr &= 0xfd;
        spage0_lcr |= 0x04;
    }
    if (cfg->data_bits == 9) {
        spage0_lcr |= 0x08;
    }
    /*子串口 配置寄存器*/
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_LCR(uart->swk_index),spage0_lcr);    //子串口 正常输出,普通模式,8位数据位,0校验,1位停止位

    /*子串口 FIFO控制寄存器*/
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_FCR(uart->swk_index),0x03);    //子串口 发送触发点,接收触发点
                                                                                  //使能 发送,接收FIFO 复位发送接收FIFO
    /*子串口 中断使能寄存器*/
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_SIER(uart->swk_index),0x00); //子串口 禁止接收FIFO数据错误中断
                                                                                                //禁止发送FIFO空中断
                                                                                                //禁止发送FIFO触点中断
                                                                                                //禁止接收FIFO接收超时中断
                                                                                                //禁止接收FIFO接收触点中断

    baudrate = WK2124_Fosc/cfg->baud_rate/16;
    baudrate_h = baudrate/0x100;
    baudrate_l = baudrate%0x100 -1;
    baudrate_dec = (uint8_t)(((WK2124_Fosc/cfg->baud_rate/16.0f) - baudrate)*16);

    /*切换到PAGE1页中的子串口寄存器组 */
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE(uart->swk_index),0x01);

    /*子串口1 波特率配置寄存器高字节 [Reg = 11.0592/(115200*16) = 6] */
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE1_BAUD1(uart->swk_index),baudrate_h);
    /*子串口1 波特率配置寄存器低字节 */
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE1_BAUD0(uart->swk_index),baudrate_l);
    /*子串口1 波特率配置寄存器小数部分*/
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE1_PRES(uart->swk_index),baudrate_dec);

    /*切换到PAGE0页中的子串口寄存器组 */
    EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE(uart->swk_index),0x00);

    return RT_EOK;
}

static rt_err_t wk2124_control(struct rt_serial_device *serial,
                            int cmd, void *arg)
{
    struct wk2124_uart *uart;
    RT_ASSERT(serial != RT_NULL);
    uart = (struct wk2124_uart *)serial->parent.user_data;
    switch (cmd)
    {
    case RT_DEVICE_CTRL_CLR_INT:
        // /* disable rx irq */
        /*切换到PAGE0页中的子串口寄存器组 */
        EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE(uart->swk_index),0x00);
        /*子串口 控制寄存器 */
        EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_SCR(uart->swk_index),0x00);	//子串口 发送不使能  接收不使能
        /*子串口 FIFO控制寄存器*/
        EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_FCR(uart->swk_index),0x03);	//子串口 发送触发点,接收触发点
                                                                                    //不使能 发送,接收FIFO 复位发送接收FIFO
        /*子串口 中断使能寄存器*/
        EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_SIER(uart->swk_index),0x00); //子串口 禁止接收FIFO数据错误中断
                                                                                    //禁止发送FIFO空中断
                                                                                    //禁止发送FIFO触点中断
                                                                                    //禁止接收FIFO接收超时中断
                                                                                    //禁止接收FIFO接收触点中断
        uart->irq_enable = 0;
        break;
    case RT_DEVICE_CTRL_SET_INT:
        // /* enable rx irq */

        //EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE(uart->swk_index),0x01);
        //EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE1_RFTL(uart->swk_index),200);
        /*切换到PAGE0页中的子串口寄存器组 */
        EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE(uart->swk_index),0x00);
        /*子串口 控制寄存器 */
        EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_SCR(uart->swk_index),0x03);	//子串口 发送使能  接收使能


        /*子串口 FIFO控制寄存器*/
        EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_FCR(uart->swk_index),0x3F);	//子串口 发送触发点,接收触发点
                                                                                    //使能 发送,接收FIFO 复位发送接收FIFO
        /*子串口 中断使能寄存器*/
        EXHW_WK2124_Write_Reg(uart->spi_device, SPAGE0_SIER(uart->swk_index),0x83); //子串口 使能接收FIFO数据错误中断
                                                                                    //禁止发送FIFO空中断
                                                                                    //禁止发送FIFO触点中断
                                                                                    //使能接收FIFO接收超时中断
                                                                                    //使能接收FIFO接收触点中断
        uart->irq_enable = 1;
        break;
    }
    return RT_EOK;
}

static int wk2124_putc(struct rt_serial_device *serial, char c)
{
    uint8_t sendbuf[10];
    struct wk2124_uart *uart;
    RT_ASSERT(serial != RT_NULL);
    uart = (struct wk2124_uart *)serial->parent.user_data;

    sendbuf[0] = c;
    Wk2124_SendBuf(uart->spi_device, uart->swk_index, sendbuf, 1);
    while(EXHW_WK2124_Read_Reg(uart->spi_device, SPAGE0_TFCNT(uart->swk_index))  > 0);
    while((EXHW_WK2124_Read_Reg(uart->spi_device, SPAGE0_FSR(uart->swk_index)) & 0x01) == 1);

    return 1;
}

static int wk2124_getc(struct rt_serial_device *serial)
{
    int ch;
    uint8_t recbuf[10];

    struct wk2124_uart *uart;
    RT_ASSERT(serial != RT_NULL);
    uart = (struct wk2124_uart *)serial->parent.user_data;

    ch = -1;    //确保没有接收数据时rt_device_read返回值为0
    if(Wk2124_GetBuf(uart->spi_device, uart->swk_index, recbuf, 1)) {
        ch = recbuf[0];
    }
    return ch;
}

static const struct rt_uart_ops wk2124_uart_ops =
{
    wk2124_configure,
    wk2124_control,
    wk2124_putc,
    wk2124_getc,
};


void WK2124_UART_IRQHandler(WK2124 *wk,uint8_t index)
{
    volatile uint8_t uart_irq_stat = 0; 
    RT_ASSERT(wk!=RT_NULL);
    RT_ASSERT(wk->uart[index].spi_device->parent.type == RT_Device_Class_SPIDevice);
    
    if (wk->uart[index].irq_enable == 0) {
       return;
    }
    /*判断串口的中断类型*/
    uart_irq_stat = EXHW_WK2124_Read_Reg(wk->uart[index].spi_device, SPAGE0_SIFR(wk->uart[index].swk_index));
    //rt_kprintf("%d %X\n",index,uart_irq_stat);

    //子串口接收FIFO触点中断标志 , 子串口接收FIFO超时中断标志
    if(uart_irq_stat & (3 << 0)) {    
        rt_hw_serial_isr(&wk->serialswk[index], RT_SERIAL_EVENT_RX_IND);
    }
    if(uart_irq_stat &(0x80))
    {
        EXHW_WK2124_Read_Reg(wk->uart[index].spi_device, SPAGE0_FSR(wk->uart[index].swk_index));
    }

}




/* 中断回调函数 */
void WK2124_IRQHandler(void *args)
{
    WK2124 *wk = args;
    rt_sem_release(&wk->irq_sem);
    rt_kprintf("x");
}

static void wk2124_irq_thread_entry(void *parameter)
{
    WK2124 *wk = parameter;
    volatile uint8_t g_irq_stat = 0; 

    while (1)
    {
        rt_sem_take(&wk->irq_sem, RT_WAITING_FOREVER);
        //
        /*使能子串口1,2,3,4的时钟*/
        g_irq_stat = EXHW_WK2124_Read_Reg(wk->wk2124_device, GIFR);
        rt_kprintf("%X ",g_irq_stat);

        //rt_kprintf("\n0x%02X\n",g_irq_stat);
        if(g_irq_stat & (1 << 0)){//子串口 1 有中断
            WK2124_UART_IRQHandler(wk,0);
        }
        if(g_irq_stat & (1 << 1)){//子串口 2 有中断
            WK2124_UART_IRQHandler(wk,1);
        }
        if(g_irq_stat & (1 << 2)){//子串口 3 有中断
            WK2124_UART_IRQHandler(wk,2);
        }
        if(g_irq_stat & (1 << 3)){//子串口 4 有中断
            WK2124_UART_IRQHandler(wk,3);
        }
        /*
        EXHW_WK2124_Write_Reg(wk->wk2124_device, GIER, 0x00);
        EXHW_WK2124_Write_Reg(wk->wk2124_device, GIER, 0x0F);*/
        if(rt_pin_read(wk->irq_pin) == PIN_LOW)
            rt_sem_release(&wk->irq_sem);

    }
}

int WK2124_IRQ_Init(WK2124 *wk)
{
    rt_err_t ret = 0;

    /* 设置引脚为输入上拉模式 */
    rt_pin_mode(wk->irq_pin, PIN_MODE_INPUT_PULLUP);
    /* 绑定中断,下降沿模式,回调函数名为WK2124_IRQHandler */
    rt_pin_attach_irq(wk->irq_pin, PIN_IRQ_MODE_FALLING, WK2124_IRQHandler, wk);
    
    /* 初始化信号量 */
    rt_sem_init(&wk->irq_sem, "irq_sem", 0, RT_IPC_FLAG_FIFO);
    rt_thread_t thread = rt_thread_create("wk2124_irq", wk2124_irq_thread_entry, wk, 2048, RT_THREAD_PRIORITY_MAX / 6, 20);
    if (thread != RT_NULL) {
        rt_thread_startup(thread);
    }  else {
        return -RT_ERROR;
    }

    /* 使能中断 */
    ret = rt_pin_irq_enable(wk->irq_pin, PIN_IRQ_ENABLE);
    rt_kprintf("rt_pin_irq_enable %d\n", ret);
    return ret;
}


int hw_wk2124_usart_init(WK2124 *wk)
{
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
    rt_err_t ret = 0;
    char name[16];

    for(uint8_t i = 0; i < 4; i++)
    {
        wk->uart[i].swk_index = i;
        wk->uart[i].irq_enable = 0;
        wk->uart[i].spi_device = wk->wk2124_device;
        wk->serialswk[i].ops    = &wk2124_uart_ops;
        wk->serialswk[i].config = config;
        wk->serialswk[i].serial_rx  = RT_NULL;
        sprintf(name,"%swk%d",wk->name,i);
        /* register UART1 device */
        ret = rt_hw_serial_register(&wk->serialswk[i], name,
                              RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
                              &wk->uart[i]);
        if (ret) {
            LOG_E("rt_hw_serial_register %s error", name);
        }
        rt_kprintf("rt_hw_serial_register %d\n", ret);
    }
    return ret;
}


int wk2124_spi_init(WK2124 *wk)
{
    RT_ASSERT(wk->name);

    if (wk->wk2124_device != RT_NULL)
    {
        return 0;
    }

    wk->wk2124_device = (struct rt_spi_device *) rt_device_find(wk->name);
    if (wk->wk2124_device == RT_NULL)
    {
        LOG_E("You should attach [%s] into SPI bus firstly.", wk->name);
        return -RT_ENOSYS;
    }

    /* check SPI device type */
    RT_ASSERT(wk->wk2124_device->parent.type == RT_Device_Class_SPIDevice);

    /* configure SPI device*/
    {
        struct rt_spi_configuration cfg;
        cfg.data_width = 8;
        cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;  /* SPI Compatible Modes 0 */
        cfg.max_hz = 40 * 1000 * 1000;                          /* SPI Interface with Clock Speeds Up to 40 MHz */
        if (rt_spi_configure(wk->wk2124_device, &cfg)) {
            LOG_E("rt_spi_configure SPI device %s error.", wk->name);
            return -RT_ERROR;
        }
    }

    if (rt_device_open((rt_device_t) wk->wk2124_device, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
    {
        LOG_E("open WK2124 SPI device %s error.", wk->name);
        return -RT_ERROR;
    }

    return RT_EOK;
}



int wk2124_device_init(void)
{
    rt_err_t ret = 0;
    //uint8_t wk2124_num = sizeof(wk2124)/sizeof(wk2124[0]);
    //rt_kprintf("----------------%d,\n",wk2124_num);

    rt_thread_mdelay(10);

    ret = wk2124_spi_init(&wk2124[1]);
    if (ret == RT_EOK) {
        rt_thread_mdelay(1);
        WK2124_IRQ_Init(&wk2124[1]);
        EXHW_WK2124_Init(wk2124[1].wk2124_device);
        rt_thread_mdelay(1);
        ret = hw_wk2124_usart_init(&wk2124[1]);
        if (ret != RT_EOK) {
            LOG_E("RT-Thread WK2124 package initialize fail.");
            //return -RT_ERROR;
        }
    }  else {
        LOG_E("RT-Thread WK2124 package initialize fail.");
        //return -RT_ERROR;
    }

    return RT_EOK;
}

INIT_ENV_EXPORT(wk2124_device_init);

#endif /* PKG_USING_WK2124 */

  1. 因为要先将SPI从设备挂载到主线上,所以添加了spi_slave.c文件
#include <rtdevice.h>
#include <board.h>


rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, GPIO_TypeDef* cs_gpiox, uint16_t cs_gpio_pin);


int rt_wk2204_spi_reg(void)
{
    //rt_hw_spi_device_attach("spi3","spi30",GPIOG,GPIO_PIN_9);
    rt_hw_spi_device_attach("spi3","spi31",GPIOD,GPIO_PIN_3);
    //rt_hw_spi_device_attach("spi4","spi40",GPIOE,GPIO_PIN_3);
    //rt_hw_spi_device_attach("spi4","spi41",GPIOI,GPIO_PIN_8);
    return 0;
}

INIT_PREV_EXPORT(rt_wk2204_spi_reg);

  1. 到此,会看到已经挂载出了四个串口设备

使用

在main.c文件中可以像调用正常串口一样调用串口

#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "board.h"
#include "string.h"

#define  KEY0 GET_PIN(H, 9)
#define  KEY4 GET_PIN(I, 4)

rt_device_t spi31wk2_dev;
rt_device_t spi31_dev;
rt_thread_t spi31wk2_th;
rt_sem_t sem;

typedef enum{
    FRAME_STEP_START = 0, /*判断表头*/
    FRAME_DATA, /*循环接收数据*/
}frame_step;

rt_err_t rx_callback(rt_device_t dev, rt_size_t size)
{
    rt_sem_release(sem);
    return RT_EOK;
}

void serial_thread_entry(void *parameter)
{
    char sensor_data = 0;
    frame_step frame = FRAME_STEP_START;
    char buffer[16];
    uint8_t offset = 0;

    while (1)
    {
        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */
        while (rt_device_read(spi31wk2_dev, -1, &sensor_data, 1) != 1)
        {
            /* 阻塞等待接收信号量,等到信号量后再次读取数据 */
            rt_sem_take(sem, RT_WAITING_FOREVER);
        }
//此部分是我自己的数据格式
        switch (frame){
            case FRAME_STEP_START:{
                offset = 0;
                if(sensor_data == 0x24){
                    buffer[offset++] = sensor_data;
                    frame =FRAME_DATA;
                }
                break;
            }
            case FRAME_DATA:{
                buffer[offset++] = sensor_data;
                if(sensor_data == 0x0a)
                {
                    //rt_device_write(rt_console_get_device(), 0, &sensor_data, 1);
                    rt_kprintf("%s\n", buffer);
                    frame = FRAME_STEP_START;
                    rt_memset(buffer, 0, 16);//给数组清零
                }
                break;
            }
        }
    }
}

int main(void)
{
	//控制台串口开关
    rt_pin_mode(KEY0,PIN_MODE_OUTPUT);
    rt_pin_write(KEY0, PIN_HIGH);
    //wk2204芯片开关
    rt_pin_mode(KEY4,PIN_MODE_OUTPUT);
    rt_pin_write(KEY4, PIN_HIGH);
    
    int count = 1;
    rt_size_t rev;
    char *str = "AT+1234\r\n";

    struct serial_configure spi31wk2_configs =
    {
        4800,    /* 115200 bits/s */
        DATA_BITS_8,        /* 8 databits */
        STOP_BITS_1,        /* 1 stopbit */
        PARITY_NONE,        /* No parity  */
        BIT_ORDER_LSB,      /* LSB first sent */
        NRZ_NORMAL,         /* Normal mode */
        RT_SERIAL_RB_BUFSZ, /* Buffer size */
        0
    };

    rt_thread_mdelay(1000);
    while (count<3)
    {
        LOG_D("Hello RT-Thread!");
        rt_thread_mdelay(1000);
        count++;
    }

    spi31wk2_dev = rt_device_find("spi31wk2");
    if (spi31wk2_dev == RT_NULL)
    {
        rt_kprintf("Can't find device\n");
        return 0;
    }
    /*初始化信号量*/
    sem = rt_sem_create("rt_sem", 0, RT_IPC_FLAG_FIFO);

    if(RT_EOK != rt_device_control(spi31wk2_dev, RT_DEVICE_CTRL_CONFIG, (void *)&spi31wk2_configs))
    {
        rt_kprintf("uart config baud rate failed.\n");
    }

/*刚开始我把open函数写在rt_device_control前面,程序运行不报错,但是就是收/
发都没有反应,调试了好久,最后还是无意中将他们换了位置,突然发现换了位置就能/
正常运行!!!*/
    rt_device_open(spi31wk2_dev, RT_DEVICE_FLAG_RDWR|RT_DEVICE_FLAG_INT_RX);

    /*数据接收回调函数*/
    rt_device_set_rx_indicate(spi31wk2_dev, rx_callback);

    /*创建线程,接收数据*/
    spi31wk2_th = rt_thread_create("spi31wk2_dev", serial_thread_entry, "spi31wk2_dev", 2048, 25, 10);
    rt_thread_startup(spi31wk2_th);

    /*写入测试命令*/
    rev = rt_device_write(spi31wk2_dev, 0, str, rt_strlen(str));
    //rt_kprintf("%s", str);
    if (rev == RT_NULL)
    {
        rt_kprintf("write data failed!size is %d\n", rev);
        rt_device_close(spi31wk2_dev);
        return 0;
    }
    rt_kprintf("write data success!  %d\n", rev);

    return RT_EOK;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值