WK2204扩展芯片
WK2204是首款具备256级FIFO的低功耗并支持 UART/SPI/IIC总线接口的4通道UART器件。可以通过模式选择使得该芯片工作于以上任何一种主接口模式,将选定的主接口扩展为4个增强功能的UART。(我使用的是SPI接口)
SPI主接口特性
- 最高速度10M bit/s
- 仅支持SPI从模式
- SPI模式0
- 支持最长256字节连续收发
硬件连接
本次实验使用STM32F429IGT6作为主控芯片,使用spi3接口,挑选RS232_16串口进行通信。
CubeMX配置
在CubeMX中配置spi3,除了基本的时钟配置(时钟需要根据板子进行配置),spi3的配置如图所示(直接从RT-Thread Studio中进入CubeMX)
配置完成后,生成工程代码
提示备份配置文件,则配置成功,会看到工程中多出来一个cubemx文件夹
RT-Thread Studio配置
- 添加软件包和相关组件
软件包只有wk2124版本,但是不影响我此次的使用
- 保存配置会看到packages中多出来wk2204的文件夹(其中spi_slave.c文件是我自己加的,刚开始编译时wk2124_usart.c文件被帅选掉了,进入属性将其从过滤器中删除即可)
- 为了程序更加简洁,我对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 */
- 因为要先将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);
- 到此,会看到已经挂载出了四个串口设备
使用
在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;
}