要点亮led灯或获得输入io的状态应该是比较容易的,打开端口时钟,然后读写相关的gpio寄存器就可以了,但是要实现一个输入中断,就要费些周折了。
对stm32(cortex-m3)的芯片,要实现一个gpio中断一般需要如下几步:
1、 配置时钟控制器寄存器(rcc)的apb2rstr,确保对应的gpioa ~ gpiog时钟使能。
2、 对gpio寄存器的crl(或crh)要设置正确的输入模式,如浮空输入模式(对接收io中断来说,当然要设置成输入模式)。
3、 要通过afio寄存器配置中断的输入来源,对stm32芯片来说,具有19路exti中断线,其中3路分别连接pvd输出、rtc闹钟事件及usb唤醒事件,剩下的对gpioa ~ gpiog 7*16=112个io点来说,同时只能配置16路io输入中断。
4、 接下来要配置exit寄存器,根据需要来配置是上升沿触发中断、还是下降沿触发中断或两者都触发。
5、 而后比较重要的是, 要配置nvic的setena寄存器,让对应的exti0、exti1、exti2、exti3、exti4、exti9_5或exti15_10中断位使能,此外还要配置各中断的优先级(前提是中断优先级分组寄存器已配置完毕)。
6、 最后我们要设置中断向量表(该向量表要重定位到内存中,以便于动态修改),在exti0、exti1、exti2、exti3、exti4、exti9_5或exti15_10对应的位置,放入我们的中断函数的入口地址。
和pc平台程序开发不同,基本上你每做一步,都可以很直观的看到你的进展和成果,但对嵌入式开发来说,如果上述几步有任何一个环节出了问题,你的进展都是零,有时候你会花上一天的时间去反复核实每个寄存器的值是否正确,以期获得你希望的结果。所以说嵌入式开发是惊喜的型的,要么成,要么不成,一线之隔!
接下来我们说一下gpio实现的详细步骤,首先在cortexm3.h头文件中添加gpio相关的寄存器描述:
struct cortexm3_gpio { static const uint32 c_base = 0x40010800; static const uint32 a = 0; static const uint32 b = 1; static const uint32 c = 2; static const uint32 d = 3; static const uint32 e = 4; static const uint32 f = 5; static const uint32 g = 6; static const uint32 gpio_mode_null = 0x00; static const uint32 gpio_mode_speed_10mhz = 0x01; static const uint32 gpio_mode_speed_2mhz = 0x02; static const uint32 gpio_mode_speed_50mhz = 0x03; static const uint32 gpio_mode_in_floating = 0x04; volatile uint32 crl; volatile uint32 crh; volatile uint32 idr; volatile uint32 odr; volatile uint32 bsrr; volatile uint32 brr; volatile uint32 lckr; }; struct cortexm3_exti { static const uint32 c_base = 0x40010400; volatile uint32 imr; volatile uint32 emr; volatile uint32 rtsr; volatile uint32 ftsr; volatile uint32 swier; volatile uint32 pr; }; struct cortexm3_afio { static const uint32 c_base = 0x40010000; volatile uint32 evcr; volatile uint32 mapr; volatile uint32 exticr[4]; }; 由于nvic相关的代码我们已经在《nvic中断处理》说过了,这里就不重复了。
对.net micro framework的架构来说,要实现如下几个接口:
1、cpu_gpio_initialize
2、cpu_gpio_uninitialize
3、cpu_gpio_attributes
4、cpu_gpio_disablepin
5、cpu_gpio_enableoutputpin
6、cpu_gpio_enableinputpin
7、cpu_gpio_enableinputpin2
8、cpu_gpio_getpinstate
9、cpu_gpio_setpinstate
10、cpu_gpio_getpincount
11、cpu_gpio_getpinsmap
12、cpu_gpio_getsupportedresistormodes
13、cpu_gpio_getsupportedinterruptmodes
14、cpu_gpio_pinisbusy
15、cpu_gpio_reservepin
16、cpu_gpio_getdebounce
17、cpu_gpio_setdebounce
考虑到难易程度和篇幅,我们只介绍cpu_gpio_initialize、cpu_gpio_enableoutputpin、 cpu_gpio_enableinputpin和exti_irqhandler 中断函数的具体实现。
bool gpio_driver::initialize() { cortexm3_afio &afio = cortexm3::afio(); for(int i=0;i<4;i ) { afio.exticr[i]=0x0000; } cortexm3_exti &exti= cortexm3::exti(); exti.imr = 0x00000000; exti.emr = 0x00000000; exti.rtsr = 0x00000000; exti.ftsr = 0x00000000; exti.pr = 0x0007ffff; if(!cpu_intc_activateinterruptex(cortexm3_nvic::c_irq_index_exti0,(uint32)(void *)exti_irqhandler )) return false; return true; } 其中比较重要的是cpu_intc_activateinterruptex函数,它可动态设置c_irq_index_exti0中断所对应的中断函数的入口地址。
void gpio_driver::enableoutputpin(gpio_pin pin, bool initialstate) { assert(pin < c_maxpins); uint32 port = pintoport(pin); uint32 bit = pintobit(pin); uint32 pos = (bit % 8)<<2; cortexm3_gpio &gpio= cortexm3::gpio(port); if(bit<8) { gpio.crl = (gpio.crl & ~(0x0f << pos)) | (cortexm3_gpio::gpio_mode_speed_50mhz << pos); } else { gpio.crh = (gpio.crh & ~(0x0f << pos)) | (cortexm3_gpio::gpio_mode_speed_50mhz << pos); } if(initialstate) gpio.bsrr = 0x1 << bit; else gpio.brr = 0x1 << bit; } 输出默认为通用推挽输出模式,你也可以根据实际需要进行必要的调整。
bool gpio_driver::enableinputpin(gpio_pin pin, bool glitchfilterenable, gpio_interrupt_service_routine isr, void *pinisrparam, gpio_int_edge intedge, gpio_resistor resistorstate) { assert(pin < c_maxpins); uint32 port = pintoport(pin); uint32 bit = pintobit(pin); uint32 pos = (bit % 8)<<2; cortexm3_gpio &gpio= cortexm3::gpio(port); //浮空输入 if(bit<8) { gpio.crl = (gpio.crl & ~(0x0f << pos))| (cortexm3_gpio::gpio_mode_in_floating << pos); } else { gpio.crh = (gpio.crh & ~(0x0f << pos))| (cortexm3_gpio::gpio_mode_in_floating << pos); } //中断输入源配置(afio) cortexm3_afio &afio = cortexm3::afio(); afio.exticr[bit >> 2] &= ~(0x0f << (0x04 * (bit & 0x03))); afio.exticr[bit >> 2] |= port << (0x04 * (bit & 0x03)); cortexm3_exti &exti=cortexm3::exti(); if(isr) { switch(intedge) { case gpio_int_none: //无中断 exti.imr &= ~(0x1<<bit); return false; case gpio_int_edge_low: //下降沿中断 case gpio_int_level_low: exti.imr |= 0x1<<bit; exti.ftsr |= 0x1<<bit; //下降沿有效 exti.rtsr &= ~(0x1<<bit); //上升沿无效 break; //略 default: assert(0); return false; } } return true; } gpio输入的实现比较繁琐一些,可以根据需要仅把端口配置成输入模式,而不配置相应的中断参数。这样可以通过不断扫描的方式获得输入信号。
void gpio_driver::isr(void *param) { cortexm3_exti &exti=cortexm3::exti(); uint32 interruptsactive = exti.pr; uint32 bitmask = 0x1, bitindex = 0; while(interruptsactive) { while((interruptsactive & bitmask) == 0) { bitmask <<= 1; bitindex; } cortexm3_afio &afio = cortexm3::afio(); uint32 port = (afio.exticr[bitindex >> 2]>>(0x04 * (bitindex & 0x03))) & 0xf; gpio_pin pin = bittopin( bitindex, port); pin_isr_descriptor& pinisr = g_gpio_driver.m_pinisr[ pin ]; pinisr.fire( (void*)&pinisr ); interruptsactive ^= bitmask; exti.pr |= bitmask; } } 在中断函数中,根据相关寄存器的值来判断哪一个(或同时哪一些)gpio发生的中断,并由此执行业已配置好的异步中断处理函数。
好了,写完了gpio驱动程序,我们就可以漂漂亮亮的在nativesample中写我们的测试程序了:
void isr( gpio_pin pin, bool pinstate, void* param ) { if(pinstate) // released, up { cpu_gpio_setpinstate(gpio_driver::pf7,0x0); } else // pressed, down { cpu_gpio_setpinstate(gpio_driver::pf7,0x1); } } void applicationentrypoint() { //led d1 d2 d3 d4 cpu_gpio_enableoutputpin(gpio_driver::pf7,false); cpu_gpio_enableoutputpin(gpio_driver::pf8,false); //user按钮 = 0x1 cpu_gpio_enableinputpin(gpio_driver::pg8,false,isr,gpio_int_edge_both,resistor_pulldown); while(true) { cpu_gpio_setpinstate(gpio_driver::pf8,!cpu_gpio_getpinstate(gpio_driver::pf8)); events_waitforevents( 0, 1000 ); } } 上面的程序比我们最初在《调试初步:点亮led灯》中提到的代码清爽多了,把程序下载到开发板上运行,你会发现d3 led灯以一秒为周期不断地闪烁,而d2 led灯则在user按钮按下时才亮,放开时则灭。
只要细心 耐心,其实嵌入式开发还是比较容易的,并且功能实现那一刻喜悦的“强度”,是作为pc平台软件开发者所难以企及的
转载于:https://blog.51cto.com/yfsoft/321228
总结
以上是凯发ag旗舰厅登录网址下载为你收集整理的【.net micro framework portingkit - 08】gpio驱动的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得凯发ag旗舰厅登录网址下载网站内容还不错,欢迎将凯发ag旗舰厅登录网址下载推荐给好友。