这两天一直被SAM R21上的USB例程所困扰,将ASF 3.21中的USB CDC、USB Keyboard例程下载到板子上,都不能正常运行,系统提示无法识别的设备。
找了很久也没有找到原因。后来偶然想到试试低版本的ASF例程,因为以前遇到过新版本的ASF在I2C上存在问题而旧版本是正常的,于是尝试了一下ASF 3.20上同样的USB CDC和USB Keyboard例程,结果发现它们是正常的,说明这次的问题又出在新版本上了。
找到问题就好办了,下面就是用比较法和文件替换法查找具体的原因了。这是一个有点痛苦的过程,因为ASF中的文件实在太多了。具体过程就不多说了,就是一个一个文件对比。我使用了Total Commander内置的文件比较功能,虽然它的功能不是最强,但是比其他软件方便快速,适合多个文件比较。最后发现是
ASF\sam0\utils\cmsis\samr21\source\gcc\startup_samr21.c 这个文件的问题。
在ASF 3.21中,增加了一些IRQ的定义,目的可能是为了节约程序空间,提高代码效率。对USB部分增加的是USB_IRQn。在startup_samr21.c中,前后对比是:
ASF 3.20
- void USB_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
-
- ...
-
- (void*) USB_Handler, /* 7 Universal Serial Bus */
ASF 3.21
- #ifdef USB_IRQn
- void USB_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
- #endif
-
USB_IRQn这个定义有点奇怪,从
#ifdef USB_IRQn这个用法看,它应该是一个宏定义,但是在程序中它是在文件
ASF\sam0\utils\cmsis\samr21\include\samr21g18a.h定义的,具体定义是一个枚举类型:
- /** Interrupt Number Definition */
- typedef enum IRQn
- {
- /****** Cortex-M0+ Processor Exceptions Numbers ******************************/
- NonMaskableInt_IRQn = -14,/**< 2 Non Maskable Interrupt */
- HardFault_IRQn = -13,/**< 3 Cortex-M0+ Hard Fault Interrupt */
- SVCall_IRQn = -5, /**< 11 Cortex-M0+ SV Call Interrupt */
- PendSV_IRQn = -2, /**< 14 Cortex-M0+ Pend SV Interrupt */
- SysTick_IRQn = -1, /**< 15 Cortex-M0+ System Tick Interrupt */
- /****** SAMR21G18A-specific Interrupt Numbers ***********************/
- PM_IRQn = 0, /**< 0 SAMR21G18A Power Manager (PM) */
- SYSCTRL_IRQn = 1, /**< 1 SAMR21G18A System Control (SYSCTRL) */
- WDT_IRQn = 2, /**< 2 SAMR21G18A Watchdog Timer (WDT) */
- RTC_IRQn = 3, /**< 3 SAMR21G18A Real-Time Counter (RTC) */
- EIC_IRQn = 4, /**< 4 SAMR21G18A External Interrupt Controller (EIC) */
- NVMCTRL_IRQn = 5, /**< 5 SAMR21G18A Non-Volatile Memory Controller (NVMCTRL) */
- DMAC_IRQn = 6, /**< 6 SAMR21G18A Direct Memory Access Controller (DMAC) */
- USB_IRQn = 7, /**< 7 SAMR21G18A Universal Serial Bus (USB) */
- EVSYS_IRQn = 8, /**< 8 SAMR21G18A Event System Interface (EVSYS) */
- SERCOM0_IRQn = 9, /**< 9 SAMR21G18A Serial Communication Interface 0 (SERCOM0) */
- SERCOM1_IRQn = 10, /**< 10 SAMR21G18A Serial Communication Interface 1 (SERCOM1) */
- SERCOM2_IRQn = 11, /**< 11 SAMR21G18A Serial Communication Interface 2 (SERCOM2) */
- SERCOM3_IRQn = 12, /**< 12 SAMR21G18A Serial Communication Interface 3 (SERCOM3) */
- SERCOM4_IRQn = 13, /**< 13 SAMR21G18A Serial Communication Interface 4 (SERCOM4) */
- SERCOM5_IRQn = 14, /**< 14 SAMR21G18A Serial Communication Interface 5 (SERCOM5) */
- TCC0_IRQn = 15, /**< 15 SAMR21G18A Timer Counter Control 0 (TCC0) */
- TCC1_IRQn = 16, /**< 16 SAMR21G18A Timer Counter Control 1 (TCC1) */
- TCC2_IRQn = 17, /**< 17 SAMR21G18A Timer Counter Control 2 (TCC2) */
- TC3_IRQn = 18, /**< 18 SAMR21G18A Basic Timer Counter 3 (TC3) */
- TC4_IRQn = 19, /**< 19 SAMR21G18A Basic Timer Counter 4 (TC4) */
- TC5_IRQn = 20, /**< 20 SAMR21G18A Basic Timer Counter 5 (TC5) */
- TC6_IRQn = 21, /**< 21 SAMR21G18A Basic Timer Counter 6 (TC6) */
- TC7_IRQn = 22, /**< 22 SAMR21G18A Basic Timer Counter 7 (TC7) */
- ADC_IRQn = 23, /**< 23 SAMR21G18A Analog Digital Converter (ADC) */
- AC_IRQn = 24, /**< 24 SAMR21G18A Analog Comparators (AC) */
- DAC_IRQn = 25, /**< 25 SAMR21G18A Digital Analog Converter (DAC) */
- PTC_IRQn = 26, /**< 26 SAMR21G18A Peripheral Touch Controller (PTC) */
- I2S_IRQn = 27, /**< 27 SAMR21G18A Inter-IC Sound Interface (I2S) */
-
- PERIPH_COUNT_IRQn = 28 /**< Number of peripheral IDs */
- } IRQn_Type;
那么#ifdef USB_IRQn就不会有效果,所以USB_Handler就被屏蔽掉了。当把startup_samr21.c中的USB_IRQn部分去掉后,程序也就正常了。USB部分的其他几个例程也是一样,只要修正了USB_IRQn部分就都正常了。
这个地方估计是ASF中的一个bug,看看在下个版本中是否会修正。同时如果我们遇到ASF中的问题,不妨试试旧版本,玩玩会有不错的效果。新版本的问题一般都是因为对程序优化造成的,旧版本虽然效率上低一点,但是功能是没有问题的。
本帖最后由 dcexpert 于 2015-1-26 00:45 编辑