完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
Event / interrupt 是gap8芯片的一个重要功能和概念。
gap8中的各种内部外设功能的实现,特别是异步的实现,都是基于event/interrupt的功能来实现的。 中断和事件的区别: 中断和事件,中断一定要有中断服务函数,但是事件却没有对应的函数. 事件可以触发其他关联操作,比如触发ADC采样等.可以在不需要CPU干预的情况下,执行这些操作. 但中断则必须要CPU介入. (个人理解:在gap8中,event 和 interrupt 对于软件开发人员来说,处理上没有什么太大差别) 关于gap8的event的发生和处理,需要如下概念: 1.管理event的硬件单元:FC event unit 和 cluster event unit。 2.event硬件管理单元监控对象是一个个硬件单元。 3.一个硬件单元可以发生多个event,只是event ID不同。 4.gap8可以产生多少个event,每个event 对应的event ID,在芯片设计之初,就已经规定好了。 5.event硬件管控单元,可以检测的event 也是固定的。 gap8中 Event的发生和处理过程 和interrupt基本相同,都是如下过程: 1.触发事件:比如引脚电平变化触发,比如写寄存器触发,等。 2.跳转到异常向量表中,再通过索引,索引到具体的异常处理中。 3.最后通过异常处理,跳转到我们驱动开发者提供的具体处理函数。 读取gap8的datasheet,知如下: 1.gap8中共有量事件管理单元: ->a. FC event unit。 ->b. Cluster event unit. 2.FC event unit 管理的 具体events如下: 可以看出FC event unit 总共管理这 15个 event . 3.Cluster event unit 管理的 具体events如下: 可以看出cluster event unit 总共管理18个event. Gap_sdk中SPIM1控制器驱动实现中设计到了 event.我们就从这个代码入手,进行分析介绍event的设置,触发,处理过程。 (1)设置event unit 对应SPIM1控制器的event 进行监控: __pi_spi_open() //spi_internal.c hal_soc_eu_set_fc_mask(SOC_EVENT_UDMA_SPIM_EOT(conf->itf)); pi_fc_event_handler_set(SOC_EVENT_UDMA_SPIM_EOT(conf->itf), spim_eot_handler); pi_fc_event_handler_set(SOC_EVENT_UDMA_SPIM_TX(conf->itf), spim_tx_handler); pi_fc_event_handler_set(SOC_EVENT_UDMA_SPIM_RX(conf->itf), spim_rx_handler); 第一句:开启了FC event unit 对SPIM1控制器的event监控。 后三句:就是将event ID号 和 对应的事件处理函数进行绑定。 void pi_fc_event_handler_set(uint32_t event_id, pi_fc_event_handler_t event_handler) { fc_event_handlers[event_id] = event_handler; } 所谓的event ID 和 事件处理函数的绑定,实际就是以event ID为数组下标,事件处理函数为数组元素。fc_event_handlers[]数组非常重要,事件触发后,就是从异常向量表中跳转到具体中断处理函数中,中断函数中就是通过这个fc_event_handlers[]数组来执行我们提供的函数。 (2)触发event: (这里以SPIM1的发送触发的EOT event 为例进行介绍) __pi_spi_send_async() //spi_internal.c spim_enqueue_channel(SPIM(device_id),(uint32_t)cs_data->udma_cmd,3* (sizeof(uint32_t)),UDMA_CORE_TX_CFG_EN(1), TX_CHANNEL); spim_enqueue_channel(SPIM(device_id), (uint32_t)data, size,UDMA_CORE_TX_CFG_EN(1),TX_CHANNEL); while((hal_read32((void*)&(SPIM(device_id)->udma.tx_cfg)) { DBG_PRINTF("%s:%dn",__func__,__LINE__); } cs_data->udma_cmd[0] = SPI_CMD_EOT(1); spim_enqueue_channel(SPIM(device_id),(uint32_t)&cs_data->udma_cmd[0],1*(sizeof(uint32_t)), UDMA_CORE_TX_CFG_EN(1), TX_CHANNEL); 第一句spim_enqueue_channel():主要是配置SPIM1控制器的发送。 第二句spim_enqueue_channel():向SPI从设备发送数据。 第三句while()循环,主要是判断发送任务是否完成或者挂起(挂起是因为被高优先级的任务抢占) 第四句spim_enqueue_channel(): 触发SPIM eot event 。然后gap8芯片就会跳转到异常处理程序中进行处理。 (3)event事件处理: 当(2)中触发SPIM eot event之后,硬件直接跳转到到 异常/中断向量表中(注意:当触发event后,程序并不是直接跳转到异常/中断向量表中,而是经过一段代码处理之后,才跳转到异常/中断向量表中的。这段跳转我们不在本讲中介绍。我们会另起一篇进行专门介绍)。 异常/中断向量表如下; 中断向量表:startup_gap8.S /******************************************************************************* INTERRUPT VECTOR TABLE 中断向量表 *******************************************************************************/ .section .vectors_irq, "ax" /* "ax"表示该节区可分配并且可执行;ax是 allocation execute的缩写 */ .option norvc; /* risc-v 选项 */ /* Cluster Notify FC Handler. */ .org 0x10 j cluster_notify_fc_handler /* PendSV Handler. */ .org 0x1c j pendSV_handler /* DMA IRQ. DMA中断 */ .extern cluster_dma_2d_handler .org 0x24 j cluster_dma_2d_handler /* Systick Handler.系统滴答处理 */ .org 0x28 j systick_handler /* FC SoC event Handler. FC SOC 事件处理。 */ .org 0x6c j fc_event_handler /* SPIM1 触发的 eot event 就是跳转到这里进行处理的 */ /* Reset Handler.重置处理 */ .org 0x80 j reset_handler /* Illegal Instruction Handler. */ .org 0x84 j ill_ins_handler /* Ecall Handler. */ .org 0x88 j ecall_handler /* This variable is pointed to the structure containing all information exchanged with the platform loader. It is using a fixed address so that the loader can also find it and then knows the address of the debug structure. */ .org 0x90 .global __rt_debug_struct_ptr __rt_debug_struct_ptr: .word Debug_Struct SPIM1控制器触发的eot event事件,会跳转到“j fc_event_handler”进行处理。 fc_event_handler标签汇编实现如下: (gap8_iet.S) /* Fc SOC event Handler. FC soc 事件处理中断 */ .extern fc_soc_event_handler /* 表明该函数实现在外部,不走这个汇编文件中 */ DECLARE fc_event_handler /* 声明这个标签“fc_event_handler”,在这里它是个函数名 */ /* Save current context. 中断来了,保存当前上下文 */ SAVE_CONTEXT_YIELD /* 调用保存上下文收益函数来保存上下文 */ lw tp, pxCurrentTCB sw sp, 0*0(tp) /* ISR Stack.中断处理程序用到的栈 */ la sp, xISRStack lw sp, 0*0(sp) jal ra, fc_soc_event_handler /* 调到这个函数中处理 该FC soc event事件中断,这是我们真正的中断处理函数 */ lw tp, pxCurrentTCB /* pxCurrentTCB 这个变量在freeRTOS中是一个指针,指向当前创建的所有任务中优先级最高的那个任务。 */ lw sp, 0*0(tp) /* Restore current context. 恢复上下文 */ RESTORE_CONTEXT_YIELD mret .endfunc 经过这段汇编代码处理,eot event的事件处理跳转到了 C代码实现的fc_soc_event_handler()函数中。 (pmsis_fc_event.c ) // TODO: Use Eric's FIRQ ABI __attribute__((section(".text"))) //指定.text段。 void fc_soc_event_handler(void) //fc event 处理函数 { /* Pop one event element from the FIFO从FIFO中取出一个事件元素 */ uint32_t event = EU_SOC_EVENTS->CURRENT_EVENT; //0x0020_0F00 对应这个寄存器“SOC_PERIPH_EVENT_ID 0x1B200F00 ”,这个寄存器中低8位存放的是事件ID号。 hal_eu_fc_evt_demux_trig_set(FC_SW_NOTIFY_EVENT, 0); //向SW_EVENT_3_TRIG 0x0020_4100UL 中写入0,也就是清除触发的bit位。方便接受下一个event. /* Trigger an event in case someone is waiting for it it will check the termination using the pending variable */ /* Now that we popped the element, we can clear the soc event FIFO event as the FIFO is generating an event as soon as the FIFO is not empty */ /*将EVENT_BUFFER_CLEAR寄存器对应的 挂起事件状态寄存器写1.(我猜想,在实时系统中,如果多个中断同时产生,如果某个中断优先级低,则它会被挂起到挂起状态寄存器中。当高优先级事件处理完毕之后,低优先级事件从挂起态变为中执行态,同时这个寄存器对应的位也要清0.)*/ EU_CORE_DEMUX->BUFFER_CLEAR = (1 << FC_SOC_EVENT_IRQN); //向EVENT_BUFFER_CLEAR 0x00204028寄存器的bit27写入1.也就是event对应挂起位清0. 数据手册中也规定所有的外设SOC_PERIPH_EVT事件对应的事件类型号是 27. // TODO: USE builtins event &= 0xFF; //这里获取事件ID号 fc_event_handlers[event]((void*)event); //调用事件ID号对应的事件处理函数,开始真正的处理函数。这个处理函数是我们自己提供的。比如spim1的eot event 对应的处理函数就是spim_eot_handler。 } (至此,SPIM1控制触发的eot event,最终就会跳转到我们当初设置的处理函数spim_eot_handler()中) 注: 1.Gap8的spi event 触发是通过写寄存器,来实现的。 2.gap8中的 SPIM 的操作是指令集的。 3.gap8 SPIM 控制器给我们提供同一个寄存器接口(这种“接口”的叫法是我自己起的,慎用)。 SPIM控制器对应的接口寄存器如下: RX_SADDR 0x1A102100 RX_SIZE 0x1A102104 RX_CFG 0x1A102108 TX_SADDR 0x1A102110 TX_SIZE 0x1A102114 TX_CFG 0x1A102118 (这套接口很简单,接受对应3个寄存器,发送对应3个寄存器) 使用时,只需要将对应通道的数据,地址和长度写入对应的寄存器 即可。 当然以上两组寄存器除了发送我们要发送的有效数据。其他的,比如,配置spiM的时钟,相位,极性等数据,也是通过以上两组寄存器,进行传输送(当然主要是TX_xx那一组进行发送)。 上面已经提到,gap8的SPIM 的操作是通过指令来控制的。其实配置spiM的时钟,相位,极性等数据,就是按照各种指令的格式来进行配置的。 spim对应的各种指令及格式如下: Name Command number Size Description SPI_CMD_CFG 0 32 SPIM configuration command. SPI_CMD_SOT 1 32 SPIM Start of Transfer command. SPI_CMD_SEND_CMD 2 32 SPIM send command command. SPI_CMD_SEND_ADDR 3 32 SPIM send address command. SPI_CMD_DUMMY 4 32 SPIM dummy RX command. SPI_CMD_WAIT 5 32 SPIM wait uDMA external event command. SPI_CMD_TX_DATA 6 32 SPIM send data command (max 64kbits). SPI_CMD_RX_DATA 7 32 SPIM receive data command (max 64kbits). SPI_CMD_RPT 8 32 SPIM repeat next transfer command. SPI_CMD_EOT 9 32 SPIM End of Transfer command. SPI_CMD_RPT_END 10 32 SPIM end of repeat command. SPI_CMD_RX_CHECK 11 32 SPIM RX check data command. SPI_CMD_FULL_DUPL 12 32 SPIM full duplex mode command. (每种指令都有对应的名字,命令号,及对应的功能。) 4.还要注意到一点,gap8中的 SPIM 其实是和 uDMA紧密结合的。这些指令从某种程序上也可以看做是给uDMA和SPIM控制器的。 这种指令集的方式操作 SPIM的方法和顺序如下; 1.配置指令集的数据:spim 时钟,相位,极性,等等(一般需要多个uint32_t,通常组成数组) 2.配置要发送数据的 地址,大小,等 3.配置spim发送结束后的指令数据,比如是否产生event事件。 gap8的异步机制,基本都依赖于这个event事件。 |
|
|
|
只有小组成员才能发言,加入小组>>
3300 浏览 9 评论
2974 浏览 16 评论
3476 浏览 1 评论
9036 浏览 16 评论
4068 浏览 18 评论
1152浏览 3评论
595浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
581浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2319浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1880浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-11 10:54 , Processed in 1.121258 second(s), Total 79, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号