本帖最后由 supenghou 于 2023-2-17 01:09 编辑
使rtt运行起来关键要素两个: 1、 led灯闪烁起来—main函数 2、 让串口进行命令行调试信息 首先led亮起来 Led关键信息 代码: IO引脚声明 - /* defined the LED pin: GPIO1_IO4 */
- /* GPIO1_4 is Blue LED */
- #define LEDB_PIN GET_PINS(1, 4)
复制代码
IO所声明的引脚
- rt_pin_write(LEDB_PIN, PIN_HIGH); /* Set GPIO output 1 */
- rt_thread_mdelay(500); /* Delay 500mS */
- rt_pin_write(LEDB_PIN, PIN_LOW); /* Set GPIO output 0 */
- rt_thread_mdelay(500); /* Delay 500mS */
复制代码
驱动说明,这里巧妙在宏定义 #define GET_PINS(PORTx, PINx) (32 * PORTx + PINx + 1) /* PORTx:0,1, PINx:0,1...31 */ (1,4) 代入既是32*1+4+1=37 在驱动drv_pin.c中查表lpc_pin_map[],(在其他芯片有叫pin[]的或者其他名字的) 列表实现: - static struct lpc_pin lpc_pin_map[] =
- {
- __LPC55S69_PIN_DEFAULT,//代表0无效
- __LPC55S69_PIN(1, GPIO, 0, 0), /* PIO0_00 */
- __LPC55S69_PIN( 2, GPIO, 0, 1), /* PIO0_01 */
- __LPC55S69_PIN( 3, GPIO, 0, 2), /* PIO0_02 */
- __LPC55S69_PIN( 4, GPIO, 0, 3), /* PIO0_04 */
- __LPC55S69_PIN( 5, GPIO, 0, 4), /* PIO0_04 */
- ……
- /* PIO1 / GPIO,1 */
- __LPC55S69_PIN(33, GPIO, 1, 0), /* PIO1_00 */
- __LPC55S69_PIN(34, GPIO, 1, 1), /* PIO1_01 */
- __LPC55S69_PIN(35, GPIO, 1, 2), /* PIO1_02 */
- __LPC55S69_PIN(36, GPIO, 1, 3), /* PIO1_03 */
- <font color="#ff0000"> __LPC55S69_PIN(37, GPIO, 1, 4), /* PIO1_04 */</font>
- __LPC55S69_PIN(38, GPIO, 1, 5), /* PIO1_05 */
- ……
- }
复制代码
#define __LPC55S69_PIN(INDEX, REG, PORT,PIN) {INDEX, REG, PORT, PIN} 序号 属性 大类 分类IO序号 通过宏定义得知给驱动拼凑字符的,这里不明显,引用其他的芯片特性 比如单片机es8p5086驱动相关 __ES8P_PIN(3, B, 2) 则宏定义为#define __ES8P_PIN(index, gpio,gpio_index) {index, GPIO##gpio, GPIO_Pin_##gpio_index} 使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起,既为(3,GPIOB,GPIO_Pin_2) 关键字符GPIOB和GPIO_Pin_2,这样驱动,有转义字符对应的数字好处具有直视感。 操作方法和芯片给与的驱动有关系,他要什么,程序就要给什么。 我这里用的自己板子,led1是P1.1 我就把上面的GET_PINS(1, 4)该成了GET_PINS(1, 1)。
第二个需要改的是命令调试串口,这里板子和例程对应上去了无需更改,但是也说以下 更改串口,主要三个位置 1、启用对应串口驱动,2、串口对应的io脚位的对应,3、命令控制台挂在串口上 1、在rt_config.h
1
2、在drv_uart.c 实际上对外输出驱动具有寄存器,数据缓存操作区,然后针对io的映射设置三大项 上面开启串口0就是寄存器和数据缓存区打通了,然后这里对io映射进行打通,因为一个模块比如串口0可以映射到多个io口进行对外操作。 啰嗦语:实际上驱动关键信息是以结构体形式封装为整体,由系统进行发起,驱动对结构体进行实现,而驱动之际占用数据存储内存为通用内存池,驱 动实现了结构体的操作地址,换句话说是操作系统通过结构体的动作操作地址来找驱动操作方法,这里进行包含与反包含的操作,而驱动的中断也由驱动实现,尽可能的短暂的把操作把寄存器数据存储到数据缓存操作区,可以通知系统后续操作。重点在那个驱动结构体,也叫类,而动用驱动的句柄就是指引到这个类的。Find句柄得驱动,也得到驱动的“操作”。 但是io的定义在上述文件drv_uart.c未找到,那整个板子得io口都是整板声明了,很板级化,在下述文件pin_mux.c中找到了io定义位置: - void BOARD_InitPins(void)
- {
- /* Enables the clock for the I/O controller.: Enable Clock. */
- CLOCK_EnableClock(kCLOCK_Iocon);
- ... ...
- const uint32_t port0_pin29_config = (/* Pinis configured as FC0_RXD_SDA_MOSI_DATA */ <font color="#ff0000">//串口P0.29_UART_RXD</font>
- IOCON_PIO_FUNC1 |
- /* Noaddition pin function */
- IOCON_PIO_MODE_INACT|
- /*Standard mode, output slew rate control is enabled */
- IOCON_PIO_SLEW_STANDARD |
- /* Input function is not inverted */
- IOCON_PIO_INV_DI |
- /*Enables digital function */
- IOCON_PIO_DIGITAL_EN |
- /* Open drain isdisabled */
- IOCON_PIO_OPENDRAIN_DI);
- /* PORT0 PIN29 (coords: 92) is configuredas FC0_RXD_SDA_MOSI_DATA */
- IOCON_PinMuxSet(IOCON, 0U, 29U,port0_pin29_config);
- const uint32_t port0_pin30_config = (/* Pinis configured as FC0_TXD_SCL_MISO_WS */<font color="#ff0000"> //串口P0.30_UART_TXD</font>
- IOCON_PIO_FUNC1 |
- /* Noaddition pin function */
- IOCON_PIO_MODE_INACT |
- /*Standard mode, output slew rate control is enabled */
- IOCON_PIO_SLEW_STANDARD |
- /*Input function is not inverted */
- IOCON_PIO_INV_DI |
- /*Enables digital function */
- IOCON_PIO_DIGITAL_EN |
- /*Open drain is disabled */
- IOCON_PIO_OPENDRAIN_DI);
- /* PORT0 PIN30 (coords: 94) is configuredas FC0_TXD_SCL_MISO_WS */
- IOCON_PinMuxSet(IOCON, 0U, 30U,port0_pin30_config);
- ... ...
- }
复制代码在这个函数调用 - void BOARD_InitBootPins(void)
- { //主板初始化引导
- <font color="#ff0000"> BOARD_InitPins();</font>
- }
复制代码
这里就涉及到芯片引脚定义工具了,不是人为的写入。实用了io引脚定义化工具来勾选是arm高级芯片常规操作,一个程序直接对应一套板子,io固定。 实际上上面函数没用,属于批量生成函数。 而在board.c中用初始化函数调用了 BOARD_InitPins(); 。 - void rt_hw_board_init()
- {
- /* Hardware Initialization */
- <font color="#ff0000"> BOARD_InitPins(); //调用在这里</font>
- ... ...
- }
复制代码而函数rt_hw_board_init()又被components.c中的如下函数调用 - int rtthread_startup(void)
- {
- ... ...
- <font color="#ff0000"> rt_hw_board_init();</font>
- ... ...
- }
复制代码
而上述函数又被main截胡函数引用 - int $Sub$main(void)
- {
- <font color="#ff0000"> rtthread_startup();</font>
- return 0;
- }
复制代码
我一直以为会被组件初始化宏接口调用比如INIT_BOARD_EXPORT(rt_hw_board_init);初始化结果如此简单粗暴,实际用了int $Sub$$main(void)函数,函数作用是在执行main前截胡,执行这个函数,然后再通过对应语句回去,但是众所周知,是回不去的,rtt把main函数当成线程了,启动main线程了,也就是rtt不会像前后台那样执行main函数,而是做成了优先级为20的线程,main函数只有象征意义了。 3、使用uart0为控制台输出 也在rt_config.h里定义
2
这里直接引用了设备名称,因为在调用串口之前,会find到串口句柄,后续命令控制台就可以操作了。
罗嗦语:其实find有好多种,驱动find,就是在容器内找对应名字的句柄,除了驱动find外还有通用find,只要知道名字你就能找到线程然后继续操作,或者找寻信号量,只要知道名字,因为任何类都在大统一容器内,而容器分类后所有的东西都是通过链表挂连的. 其实rtt就是一种c面向对象的编程方法教材。 在github下载的5.0遇到的问题
|