本帖最后由 北方西门吹雪 于 2020-6-23 16:11 编辑
1、龙芯l2000是一款SOC芯片,具有多种丰富的外设。适用于外设的驱动,目前只提供了UART和GPIO,所以开发的过程就需要了解如何去实现底层驱动开发,才能导入各种包含net等多种扩展插件。
对比Linxu,PMON等发现RTT独有的驱动配置模式,因此,单独开一贴,分析RTT的驱动实现和现有的解决方法。
2、对于龙芯的驱动,实现的方式和其他嵌入式芯片是非常相似的,都是是确定Address,Register,然后对照手册按位置位,按照硬件的协议应答。最简单的GPIO是单向的,只需要简单按位写入就可以实现。但是包括UART,I2C等都需要按照选择状态,起始,收发,关闭的逻辑循环。
因此,以GPIO和I2C为例,说明两者的不同之处和相同的地方。
3、外设的驱动,对于龙芯来说,有两种方式:
- 原生方式baremetal代码方式去直接编写。对于RTT只使用其中的thread和任务管理的部分。
- 实用标准的RTT接口语句和模块,用标准化的RTT语句实现可以轻松移植的RTT编程,这种方式也是RTT提倡,而且也需要重视的方式。
4、 GPIO的两种方式,
- 直接用寄存器访问的方式实现gpio,如下代码,
static int loongson_pin_read(struct rt_device *device, rt_base_t pin);
- 通过注册的方式hw-register()把底层的参数传入RTT的标准语句,实现rtt的标准语言。如下代码:
227 int loongson_pin_init(void)
228 {
229 int rc;
230 static struct loongson_gpio *loongson_gpio_priv;
231
232 loongson_gpio_priv = (void *)GPIO_BASE;
233 rc = rt_device_pin_register("pin", &loongson_pin_ops, loongson_gpio_priv);
234
235 //gpio0
236 rt_hw_interrupt_install(LS2K_GPIO0_INT_IRQ, gpio_irq_handler, &_g_gpio_irq_tbl[0], "gpio0_irq");
237 rt_hw_interrupt_umask(LS2K_GPIO0_INT_IRQ);
238
239 //gpio1
240 rt_hw_interrupt_install(LS2K_GPIO1_INT_IRQ, gpio_irq_handler, &_g_gpio_irq_tbl[1], "gpio1_irq");
241 rt_hw_interrupt_umask(LS2K_GPIO1_INT_IRQ);
242
243 //gpio2
244 rt_hw_interrupt_install(LS2K_GPIO2_INT_IRQ, gpio_irq_handler, &_g_gpio_irq_tbl[2], "gpio2_irq");
245 rt_hw_interrupt_umask(LS2K_GPIO2_INT_IRQ);
246
247 //gpio3
248 rt_hw_interrupt_install(LS2K_GPIO3_INT_IRQ, gpio_irq_handler, &_g_gpio_irq_tbl[3], "gpio3_irq");
249 rt_hw_interrupt_umask(LS2K_GPIO3_INT_IRQ);
250
251 //gpio4~gpio31
252 rt_hw_interrupt_install(LS2K_GPIO_INTLO_IRQ, gpio_irq_handler, &_g_gpio_irq_tbl[4], "gpio4_irq");
253 rt_hw_interrupt_umask(LS2K_GPIO_INTLO_IRQ);
254
255 //gpio32~gpio63
256 rt_hw_interrupt_install(LS2K_GPIO_INTHI_IRQ, gpio_irq_handler, &_g_gpio_irq_tbl[5], "gpio5_irq");
257 rt_hw_interrupt_umask(LS2K_GPIO_INTHI_IRQ);
258
259 return rc;
260 }
261 INIT_BOARD_EXPORT(loongson_pin_init);
上述参数,从head文件提取了GPIO的地址等信息,然后通过INIT_BOARD_EXPORT(loongson_pin_init)初始化,这样
得到设备的启动和初始化,这个语句吧GPIO的初始化自动扫描加入BOARD初始化的序列中去。
但是,最重要的语句是
rc = rt_device_pin_register("pin", &loongson_pin_ops, loongson_gpio_priv);
这句话,直接注册了龙芯的pins,并且传递给结构体。然后,在使用gpio就可以按照的标准语句,而不用上述重写的GPIO写入代码。
然后,使用的时候直接用标准rtt语句,参照手册说明
rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT);
rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
说明:
对于GPIO的访问,在龙芯处理器用户手册第116页第13章GPIO部分说明。共64个引脚,占用64位,分别是输入输出值,输出使能,低64位中断。
地址从0x1fe10500开始到0x1fe10538,参照手册非常直观。就不赘述了。
5、I2C的驱动
5.1 I2C是作为一种总线设备挂在APB设备(Dev2),内部地址[15:12]为0x01,地址[11]选择I2C0或者I2C1,[2:0]是内部寄存器地址。
其中,[27:16]是标准的BAR_BASE地址。其他具体的逻辑是标准的I2C,不过标准速率400kbps。不过,最新的I2C已经可以支持到1M以上了。
对于,龙芯的有个小坑,就是要把i2c_sel的位置位1,如果按照缺省的0定义,就复用为GPIO的。地址0x1fe10420的[11:10].
5.2 I2C的驱动有2种方式,soft-wire,就是用GPIO来模拟i2c,还有就是如上直接使用i2c0或者,i2c1。
5.3 在实现了gpio驱动后,可以直接用rtt的soft-wire。这里,可以在menuconfig中选择,这样使用的是bit-ops.c。在compnent\driver下,可以非常清晰的看到实现i2c的硬逻辑。
5.4 如果使用驱动,那么主要引入i2c.h,i2c_core.c,i2c_dev.h等就可以了。不过,还是需要像上述的GPIO一样,需要先注册这个devs,作为一个rt_device进入系统。
6 综上所述,基于龙芯BSP的开发,按照这样的逻辑,其实开发效率会提升很多。
在不熟悉这样的系统结构之前,是希望用类似arduino的开源代码,移植到rtt的bsp中。经过分析,发现使用对应的硬件初始化,兼顾端口注册和结构体传输的方式是最有效的。
就是需要在board.h中,定义这些基地址,以及bsp相关的结构体,以及xxx_component_init(),hw_register()语句。
希望这样的简单说明,能给龙板的开发者有一些启示,快速进入项目开发阶段,避免在驱动上绕弯。
对于,扩展的插件,如net等,有些事需要硬件的支持的,对应需要及时进行驱动的标准化方式,如果使用重写的开发板gpio等硬件驱动,是不能得到充分的支持,也就是用不了滴。
|