无剑100SOC(wujian100)挂UART外设之④修改SDK
一、流程
printf函数, 是如何调用串口的呢?整理出这个流程,可以帮助我们修改SDK。
首先,我们知道,C语言中,printf函数循环调用fputc函数。在sdk工程中搜索fputc函数,我们可以得到如下内容。
int fputc(int ch, FILE *stream)
{(void)stream;if (console_handle == NULL) {return -1;}if (ch == '\n') {csi_usart_putchar(console_handle, '\r');}csi_usart_putchar(console_handle, ch);return 0;
}
csi_usart_putchar函数
int32_t csi_usart_putchar(usart_handle_t handle, uint8_t ch)
{return drv_usi_usart_putchar(handle, ch);
}
drv_usi_usart_putchar函数
int32_t drv_usi_usart_putchar(usart_handle_t handle, uint8_t ch)
{wj_usi_usart_priv_t *usart_priv = handle;wj_usi_reg_t *addr = (wj_usi_reg_t *)(usart_priv->base);//addr->USI_EN = 0xb;//addr->USI_EN = 0xf;addr->USI_TX_RX_FIFO = ch;while (!(addr->USI_FIFO_STA & 0x1));return 0;
}
可以看出,这三个函数说明了printf是如何输出到串口的。printf函数循环调用fputc函数,fputc函数调用了csi_usart_putchar函数,csi_usart_putchar实际为drv_usi_usart_putchar函数,drv_usi_usart_putchar函数将USI_TX_RX_FIFO的数据取出送出去。这样,printf函数的内容,被UART串口送出,被PC端的串口接收,显示出来。流程图如下。
二、思路
看drv_usi_usart_putchar函数的代码,数据的基地址为addr,而addr是从(wj_usi_reg_t *)(usart_priv->base)来的。那我们在SDK工程中搜索wj_usi_reg_t和usart_priv。结果如下
typedef struct {__IOM uint32_t USI_EN; /* Offset 0x000(R/W) */__IOM uint32_t USI_MODE_SEL; /* Offset 0x004(R/W) */__IOM uint32_t USI_TX_RX_FIFO; /* Offset 0x008(R/W) */__IOM uint32_t USI_FIFO_STA; /* Offset 0x00c(R/W) */__IOM uint32_t USI_CLK_DIV0; /* Offset 0x010(R/W) */__IOM uint32_t USI_CLK_DIV1; /* Offset 0x014(R/W) */__IOM uint32_t USI_UART_CTRL; /* Offset 0x018(R/W) */ __IOM uint32_t USI_UART_STA; /* Offset 0x01c(R/W) */__IOM uint32_t USI_I2C_MODE; /* Offset 0x020(R/W) */__IOM uint32_t USI_I2C_ADDR; /* Offset 0x024(R/W) */__IOM uint32_t USI_I2CM_CTRL; /* Offset 0x028(R/W) */__IOM uint32_t USI_I2CM_CODE; /* Offset 0x02c(R/W) */__IOM uint32_t USI_I2CS_CTRL; /* Offset 0x030(R/W) */__IOM uint32_t USI_I2C_FM_DIV; /* Offset 0x034(R/W) */__IOM uint32_t USI_I2C_HOLD; /* Offset 0x038(R/W) */__IOM uint32_t USI_I2C_STA; /* Offset 0x03c(R/W) */__IOM uint32_t USI_SPI_MODE; /* Offset 0x040(R/W) */__IOM uint32_t USI_SPI_CTRL; /* Offset 0x044(R/W) */__IOM uint32_t USI_SPI_STA; /* Offset 0x048(R/W) */__IOM uint32_t USI_INTR_CTRL; /* Offset 0x04c(R/W) */__IOM uint32_t USI_INTR_EN; /* Offset 0x050(R/W) */__IOM uint32_t USI_INTR_STA; /* Offset 0x054(R/W) */__IOM uint32_t USI_RAW_INTR_STA; /* Offset 0x058(R/W) */__IOM uint32_t USI_INTR_UNMASK; /* Offset 0x05c(R/W) */__IOM uint32_t USI_INTR_CLR; /* Offset 0x060(R/W) */__IOM uint32_t USI_DMA_CTRL; /* Offset 0x064(R/W) */__IOM uint32_t USI_DMA_THRESHOLD; /* Offset 0x068(R/W) */
} wj_usi_reg_t;
wj_usi_usart_priv_t *usart_priv = &usi_usart_instance[idx];
wj_usi_usart_priv_t为一个结构体,usart_priv是一个指向它的指针,具体值为usi_usart_instance[idx],那我们继续查找usi_usart_instance和idx。usi_usart_instance结果如下,idx是传进来的参数,这个我们一会讨论。
static wj_usi_usart_priv_t usi_usart_instance[CONFIG_USI_NUM];
在工程中查找CONFIG_USI_NUM,结果如下。是3,暂时看不出来从哪里计算出来的3。看来走到了头。那我们走usi_usart_instance的路走不通,我们去走idx的路。
#define CONFIG_USI_NUM 3
wj_usi_usart_priv_t *usart_priv = &usi_usart_instance[idx];这句话,在工程中,出现了两次,都在wj_usi_usart.c中。我们去找到它俩,可以看出,它俩分别是两个函数中的一个话, 这两个函数是drv_usi_usart_initialize和wj_usi_usart_irqhandler。看名字,第一个是USI的UART初始化函数,第二个是IRQ的中断安装。我们分别去找这两条路。
IRQ路,查找该函数,找到如下内容。根据USI_MODE_SEL选择UART或者I2C或者SPI,这个和我们在前边学习到的,USI0中包含有这三种通信方式相符合。继续查找wj_usi_irqhandler函数
void wj_usi_irqhandler(int32_t idx)
{wj_usi_priv_t *usi_priv = &usi_instance[idx];wj_usi_reg_t *addr = (wj_usi_reg_t *)(usi_priv->base);switch (addr->USI_MODE_SEL & 0x3) {case USI_MODE_UART:
#ifndef CONFIG_CHIP_PANGUwj_usi_usart_irqhandler(idx);
#endifbreak;case USI_MODE_I2C:wj_usi_i2c_irqhandler(idx);break;case USI_MODE_SPI:wj_usi_spi_irqhandler(idx);break;default:return;}
}
查到结果如下,同时观察上下,三个USI的中断安装实现,同时注意其中的wj_usi_irqhanlder的参数,0、1、2。看起来我们走到了终点。那换一条路。查找drv_usi_usart_initialize函数。
ATTRIBUTE_ISR void USI0_IRQHandler(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(0);CSI_INTRPT_EXIT();
}ATTRIBUTE_ISR void USI1_IRQHandler(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(1);CSI_INTRPT_EXIT();
}ATTRIBUTE_ISR void USI2_IRQHandler(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(2);CSI_INTRPT_EXIT();
}
查找结果如下,被csi_usart_initialize函数调用。继续。
usart_handle_t csi_usart_initialize(int32_t idx, usart_event_cb_t cb_event)
{return drv_usi_usart_initialize(idx, cb_event);
}
在board_init.c中,如下。看名字是一个初始化函数。
console_handle = csi_usart_initialize(CONSOLE_IDX, NULL);
看board_init.c文件中的函数board_init(),其中,和UART相关的有两个,第一个是一个初始化函数,第二个是一个配置函数。
void board_init(void)
{int32_t ret = 0;//32位有符号数/* init the console*/clock_timer_init();clock_timer_start();console_handle = csi_usart_initialize(CONSOLE_IDX, NULL);//csi_usart_initialize --> return drv_usi_usart_initialize(CONSOLE_IDX, NULL);//CONSOLE_IDX = 0 in the file "pin.h"/* config the UART */ret = csi_usart_config(console_handle, 115200, USART_MODE_ASYNCHRONOUS, USART_PARITY_NONE, USART_STOP_BITS_1, USART_DATA_BITS_8);//return drv_usi_usart_config(console_handle, 115200, USART_MODE_ASYNCHRONOUS, USART_PARITY_NONE, USART_STOP_BITS_1, USART_DATA_BITS_8);if (ret < 0) {return;}
}
查找board_init()函数的调用情况。在START.s,即初始化文件中,可以查到如下。
#ifndef __NO_BOARD_INIT120: jal board_init121 #endif
查找csi_usart_initialize中的CONSOLE_IDX,结果如下
#define CONSOLE_IDX 0
是0,结合上面出现的0、1、2,还有CONFIG_USI_NUM=3,再想到无剑100一共有3个USI模块,看起来很巧合。我们在查找一下CONFIG_USI_NUM。
const sg_usi_config[CONFIG_USI_NUM] = {{WJ_USI0_BASE, USI0_IRQn, USI0_IRQHandler},{WJ_USI1_BASE, USI1_IRQn, USI1_IRQHandler},{WJ_USI2_BASE, USI2_IRQn, USI2_IRQHandler},
};
在的devices.c中,如上,看起来和我们的猜测相符合,sg_usi_config是一个3行数组,每一行都是一个USI相关信息。我们分别取查找一下。
#define WJ_USI0_BASE (0x50028000UL)
#define WJ_USI1_BASE (0x60028000UL)
#define WJ_USI2_BASE (0x50029000UL)
USI0_IRQn = 28, /* usi0 Interrupt */USI1_IRQn = 29, /* usi1 Interrupt */USI2_IRQn = 30, /* usi2 Interrupt */
ATTRIBUTE_ISR void USI0_IRQHandler(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(0);CSI_INTRPT_EXIT();
}ATTRIBUTE_ISR void USI1_IRQHandler(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(1);CSI_INTRPT_EXIT();
}ATTRIBUTE_ISR void USI2_IRQHandler(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(2);CSI_INTRPT_EXIT();
}
结合上面的信息,我们可以看到,在board_init()函数中,初始化了UART,并配置了UART的参数,而有3个USI,CONSOLE_IDX=0表明了使用的是USI0。将这一切整理为一个流程图如下。
说明各函数作用。
初始化路线,board_init调用csi_usart_initialize函数,csi_usart_initialize掉用drv_usi_usart_initialize。在drv_usi_usart_initialize中,共调用五个函数。
1)target_usi_usart_init,根据idx的值,将sg_usi_config的基地址、IRQ中断号和安装程序赋值给我们要使用的。默认情况下,idx为0,即将USI0作为要使用的USI模块。
int32_t target_usi_usart_init(int32_t idx, uint32_t *base, uint32_t *irq, void **handler)
{if (idx >= CONFIG_USI_SPI_NUM) {return -1;}if (base != NULL) {*base = sg_usi_config[idx].base;}if (irq != NULL) {*irq = sg_usi_config[idx].irq;}if (handler != NULL) {*handler = sg_usi_config[idx].handler;}return idx;
}
2)drv_usi_initializ函数,给usi_priv指向的w_usi_priv_t结构体赋值
int32_t drv_usi_initialize(int32_t idx)
{uint32_t base = 0u;uint32_t irq = 0u;int32_t ret = target_usi_init(idx, &base, &irq);if (ret < 0 || ret >= CONFIG_USI_NUM) {return ERR_USI(DRV_ERROR_PARAMETER);}wj_usi_priv_t *usi_priv = &usi_instance[idx];usi_priv->base = base;usi_priv->irq = irq;return 0;
}
3)wj_usi_set_rxfifo_th,设置FIFO
void wj_usi_set_rxfifo_th(wj_usi_reg_t *addr, uint32_t length)
{addr->USI_INTR_CTRL &= ~USI_INTR_CTRL_TH_MODE;addr->USI_INTR_CTRL &= USI_INTR_CTRL_RXFIFO_TH;if (length >= USI_RX_MAX_FIFO) {addr->USI_INTR_CTRL |= USI_INTR_CTRL_RXFIFO_TH_12 | USI_INTR_CTRL_TH_MODE;} else if (length >= USI_RX_MAX_FIFO - 4) {addr->USI_INTR_CTRL |= USI_INTR_CTRL_RXFIFO_TH_8 | USI_INTR_CTRL_TH_MODE;} else if (length >= 4) {addr->USI_INTR_CTRL |= USI_INTR_CTRL_RXFIFO_TH_4 | USI_INTR_CTRL_TH_MODE;} else {addr->USI_INTR_CTRL |= USI_INTR_CTRL_RXFIFO_TH_4;}
}
4)drv_irq_register,配置IRQ的寄存器
void drv_irq_register(uint32_t irq_num, void *irq_handler)
{g_irqvector[irq_num] = irq_handler;
}
5)drv_irq_enable,使能IRQ与否
void drv_irq_enable(uint32_t irq_num)
{
#ifdef CONFIG_SYSTEM_SECUREcsi_vic_enable_sirq(irq_num);
#elsecsi_vic_enable_irq(irq_num);
#endif
}
配置UART串口参数路线,各个函数的功能由函数名就可以看出,再次不赘述,且与添加USI之后更改SDK无关。
三、更改
综上,我们得到了更改SDK所需要的信息。那么有两种思路可以选择。第一,将USI0的基地址,替换为dummy_top0的基地址。所谓偷梁换柱法。如下,即可
#define WJ_USI0_BASE (0x50028000UL)换成#define WJ_USI0_BASE (0x50004000UL)
第二种,讲我们挂的USI_myself,作为第四个USI,写入程序,并将初始化的USI从USI0改为USI_myself。具体需要更改的位置很多,如下。
1)soc.h中新增基地址
#define WJ_USI0_BASE (0x50028000UL)
#define WJ_USI1_BASE (0x60028000UL)
#define WJ_USI2_BASE (0x50029000UL)
#define WJ_USI0_BASE_myself (0x50004000UL)
2)soc.h中新增中断号
typedef enum IRQn {User_Software_IRQn = 0, /* User software interrupt */Supervisor_Software_IRQn = 1, /* Supervisor software interrupt */Machine_Software_IRQn = 3, /* Machine software interrupt */User_Timer_IRQn = 4, /* User timer interrupt */Supervisor_Timer_IRQn = 5, /* Supervisor timer interrupt */CORET_IRQn = 7, /* core Timer Interrupt */GPIO0_IRQn = 16, /* uart Interrupt */TIM0_IRQn = 17, /* timer0 Interrupt */TIM1_IRQn = 18, /* timer1 Interrupt */TIM2_IRQn = 19, /* timer2 Interrupt */TIM3_IRQn = 20, /* timer3 Interrupt */TIM4_IRQn = 21, /* timer4 Interrupt */TIM5_IRQn = 22, /* timer5 Interrupt */TIM6_IRQn = 23, /* timer6 Interrupt */TIM7_IRQn = 24, /* timer7 Interrupt */PWM_IRQn = 25, /* pwm Interrupt */RTC_IRQn = 26, /* rtc Interrupt */WDT_IRQn = 27, /* wdt Interrupt */USI0_IRQn = 28, /* usi0 Interrupt */USI1_IRQn = 29, /* usi1 Interrupt */USI2_IRQn = 30, /* usi2 Interrupt */PMU_IRQn = 31, /* pmu Interrupt */DMAC0_IRQn = 32, /* dmac0 Interrupt */TIM8_IRQn = 33, /* timer8 Interrupt */TIM9_IRQn = 34, /* timer9 Interrupt */TIM10_IRQn = 35, /* timer10 Interrupt */TIM11_IRQn = 36, /* timer11 Interrupt */TIM12_IRQn = 37, /* timer12 Interrupt */TIM13_IRQn = 38, /* timer13 Interrupt */TIM14_IRQn = 39, /* timer14 Interrupt */TIM15_IRQn = 40, /* timer15 Interrupt */USI0_IRQn_myself = 41 ,
}
IRQn_Type;
3)devices中,sg_usi_config,新增
const sg_usi_config[CONFIG_USI_NUM] = {{WJ_USI0_BASE, USI0_IRQn, USI0_IRQHandler},{WJ_USI1_BASE, USI1_IRQn, USI1_IRQHandler},{WJ_USI2_BASE, USI2_IRQn, USI2_IRQHandler},{WJ_USI0_BASE_myself, USI0_IRQn_myself, USI0_IRQHandler},
};
4)soc.h,更改CONFIG_USI_NUM
#define CONFIG_USI_NUM 4
5)devices.c中,新增
extern void USI0_IRQHandler(void);
extern void USI1_IRQHandler(void);
extern void USI2_IRQHandler(void);
extern void USI0_IRQHandler_myself(void);
6)isr.c中,新增
ATTRIBUTE_ISR void USI0_IRQHandler(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(0);CSI_INTRPT_EXIT();
}ATTRIBUTE_ISR void USI1_IRQHandler(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(1);CSI_INTRPT_EXIT();
}ATTRIBUTE_ISR void USI2_IRQHandler(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(2);CSI_INTRPT_EXIT();
}
ATTRIBUTE_ISR void USI0_IRQHandler_myself(void)
{CSI_INTRPT_ENTER();wj_usi_irqhandler(3);CSI_INTRPT_EXIT();
}
7)pin.h
#define CONSOLE_IDX 3
四、验证
终于SDK也修改完成,我们要验证一下是否正确了。流程和本系列的文章③一样,看一下打印出来的是否正确就好了。
欢迎留言讨论。
无剑100SOC(wujian100)挂UART外设之④修改SDK相关推荐
- 无剑100SOCwujian100挂UART外设之③硬件挂UART
终于来到了挂UART外设.首先是硬件层面挂上. 一.在哪 首先看无剑100SOC的代码,找到UART位于哪个位置.如下图,为无剑100的总线结构.AHB总线,有7个主机和12个从机.主机0.1.2为来 ...
- 阿里平头哥无剑100SOCwujian100挂UART外设之①将无剑100下载到gensys开发板
一.前言 组里的布置的任务,给大项目的推进打个小小的基础.经过上学期一个月和这学期开学几周,终于解决.其实真正用在挂UART的时间不多,大部分时间都用在如何把无剑100SOC下载到gensys开发板和 ...
- 无剑100SOCwujian100挂UART外设之②跑通自带UART
一.为什么 首先跑通自带的UART,有助于我们熟悉UART的使用. 二.是什么 下载官方的SDK示例,或者下载慕课的示例也可以.如下图所示,在while循环中,添加了printf("test ...
- 百行代码解读阿里 AloT 芯片平台无剑 100!
作者 | 马超 责编 | 胡巍巍 出品 | CSDN(ID:CSDNnews) 今年以来我国IT厂商都在AIot的底层平台建设方面可谓是捷报频传,在操作系统方面有如像腾讯的Tiny OS.阿里的Al ...
- matlab如何花间,酌酒花间,磨针石上;倚剑天下,挂弓扶桑。赞颂的是谁
韩琴1009的回答: 赞颂的是唐代大诗人李白.这句话出自郭沫若先生题江油李白纪念馆的楹联.这幅楹联每四个字都对应了李白的一首诗中的句子: 酌酒花间:出自唐代李白所作的<月下独酌四首·其一> ...
- 平头哥发布一站式芯片设计平台“无剑”,芯片设计成本降低50%
导读:8 月 29 日,在上海举行的世界人工智能大会上,阿里巴巴旗下半导体公司平头哥发布 SoC 芯片平台"无剑".无剑是面向 AIoT 时代的一站式芯片设计平台,提供集芯片架构. ...
- 阿里平头哥发布AIoT芯片平台“无剑”,可将芯片设计成本降低50%
允中 发自 凹非寺 量子位 报道 | 公众号 QbitAI 阿里芯片,又有大动作.这次不是AI芯片,而是芯片平台. 世界AI大会期间,平头哥发布AIoT芯片平台,命名"无剑". ...
- (61)UART外设驱动接收驱动(六)(第13天)
(61)UART外设驱动接收驱动(六)(第13天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)UART外设驱动接收驱动(六)(第13天) 5)技术交流 6)参 ...
- (60)UART外设驱动发送驱动(五)(第12天)
(60)UART外设驱动发送驱动(五)(第12天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)UART外设驱动发送驱动(五)(第12天) 5)技术交流 6)参 ...
最新文章
- linux新用户登陆密码,如何强制Linux用户在第一次登录时更改初始密码?
- 001_Redis介绍
- css中超级链接样式的设置顺序
- 使用Dockerfile构建SpringBoot应用镜像
- 如何免费试用SAP的Fiori应用
- 如何优雅的绘制一棵省市区三级可选择的树?
- Ios 12 linux,苹果发布iOS 12.4.1,以修补越狱漏洞
- VS Code 下载
- 太原市中考计算机考试系统,太原中考报名系统
- 等宽分箱_数据分析师-数据挖掘如何分箱以及对箱子中的数据进行平滑处理
- 【BZOJ2659】算不出的算式,打表找规律
- 【报告分享】2020快手短视频直播电商营销增长宝典.pdf(附下载链接)
- 记一次Mysql查询字段为空串在java中使用equals不相等的问题
- access 套用表格_将ACCESS数据库导入到EXCEL表格
- 深鸿会深大小组学习笔记:第二周,从零开发鸿蒙小游戏2048app(下)
- 3DMAX哪个版本最稳定?3DMAX哪个版本最好用?
- 基于ISO27001的数据中心信息安全管理体系
- 哄女朋友玩的c语言编程,哄女朋友开心的小套路 逗女朋友开心的话套路
- 自学Java!三面蚂蚁核心金融部,Java岗
- 高端数据中心交换机散热系统大比拼
热门文章
- c语言任伟,任 伟
- 51单片机两只老虎 c语言,基于51单片机做音乐盒(两只老虎)
- 常用数据结构和算法总结
- 关于Python爬虫之获取海量表情包+存入数据库+搭建网站通过关键字查询表情包
- 数据库基础考点笔记-3
- java 类一定要声明成public_关于使用public class 和 class声明类的区别
- T100 genero report (GR) 凭证报表开发流程
- Steering Behaviors
- 企业级应用Service Management Automation X(SMAX)的微服务之路
- Java GUI气泡诗词02