由于第一篇文章介绍的方案中,我们将NDS作为SPI通信中的主机(Master),将Arduino作为从机(Slave)。在SPI通信中,主机向从机发送数据很容易:将SS线打低电平,然后就可以发送数据到MOSI线上。而从机向主机发送数据则比较困难,因为SPI从机不能主动向主机发送数据。为了我们最后实现的方案中使从机能主动向主机发送数据,我们采用从机向主机触发一个IRQ中断,让主机知道从机有数据需要发送,然后由主机引发SPI通信,并使从机的数据发送到主机。
一、硬件中断设计
这里最核心的部分,即如何让从机(Arduino)去触发一个主机(NDS)的IRQ中断呢?这可以通过以下两步完成:
(1)硬件上:连接Atmega 168/328 CPU的 PB6 引脚到NDS Slot
1接口的第7引脚,见图1;
(2)软件上:首先配置NDS端开启CARD LINE IRQ中断,然后让Atmega CPU 在 PB6
引脚上发生一个从低电平到高电平的上升沿,或从高电平到低电平的下降沿,来触发NDS的IRQ中断。
说明:NDS Slot 1的第7引脚对应Card Line
IRQ,可接收Slot 1的外部中断到NDS内部,并进行处理。Atmega 168/328的 PB6 (即PORT B
6)和很多其它引脚一样,是个多功能复用的引脚。它有3个功能,除了可以和PB7一起连接外部晶振等功能外,也可以作为external
interrupt
source,即外部中断源。(注:不过因为NDS作为SPI主机和Atmega通信不需要再通过触发Atmega的外部硬件中断来告诉Atmega需要接收NDS即将发的数据,而NDS可以直接将SS拉低后发送,因此这里只用于Atmega去触发NDS的外部中断。所以也可以连接到Atmega的其它空余的数字引脚。)
二、NDS端对外部IRQ硬件中断的软件设置
步骤如下:
(1)首先按上篇教程先完成对NDS端的SPI初始化工作;
(2)然后编写CARD INE
IRQ中断服务函数代码,并设置该中断调用的函数到相应的中断向量表中。使用libnds的库函数,可如下操作实现:
irqSet(IRQ_CARD_LINE, card_line_irq);
其中,参数IRQ_CARD_LINE为中断号,该宏对应Slot
1卡带的CARD LINE IRQ中断号,值为IRQ_CARD_LINE=(1<<20)。参数card_line_irq为中断服务函数,其函数原型为:
static void
card_line_irq();
说明:NDS的各中断可参考REG_IE/REG_IF寄存器,如图2所示:
(3)中断开启NDS的CARD LINE
IRQ中断使能,可通过设置REG_IE寄存器第20位为1实现:
int oldIME =
REG_IME;
REG_IME =
0;
REG_IE |=
(1<<20);
REG_IME =
oldIME;
这段代码首先将NDS的中断总使能寄存器REG_IME置0,
然后对REG_IE第20位置1,最后恢复REG_IME的原有值。这是因为REG_IE寄存器属于临界资源,也不允许操作REG_IE寄存器时发生别的中断而转去别的中断处理代码。也就是说对REG_IE的操作是原子操作。
如果使用libnds库函数则比较方便,直接调用如下函数便可:
irqEnable(IRQ_CARD_LINE);
至此,NDS端对Slot
1接口的CARD LINE IRQ的中断处理工作就准备就绪了,一旦Arduino向NDS端发送一个电平波动引发NDS的CARD
LINE IRQ中断后,card_line_irq()函数便会自动执行。因此可以在这个函数里向Arduino发送一个dummy字节,引发SPI通信,使得Arduino可以在收到这个dummy字节后随随后把数据赋给SPDR寄存器,使该数据传输给NDS主机。
三、Arduino端如何触发NDS端CARD LINE
IRQ硬件中断
上文已述,需要Arduino在PB6接口向NDS端发送一个电平波动。一般需要跟据NDS端对CARD
LINE IRQ中断响应的配置进行发送电平波动,但由于找不到文档关于NDS端对CARD LINE
IRQ中断响应的配置信息,所以不知道是该发送一个低电平到高电平的上升沿过去,还是发送一个从高电平到低电平的下降沿过去。参考DS
brut中Atmega端的代码,是这么做的:
void
do_irq()
{
}
分析该函数:
1. DDRB为PORT
B引脚对应的数据传输方向寄存器 (Port B Data Direction
Register),DDRB |= (1 <<
6); 的意思是将DDRB第6位置1,查看DataSheet,1代表输出,0代表输入。所以这里将PB6引脚配置为输出,类似于调于Arduino的库函数:pinMode
(PB6, OUTPUT);
2. PORTB为PORT B引脚对应的数据传输寄存器,相应的位如果置1代表电平为HIGH,置0代表为LOW。因此上述代码先产生了一个由低电平到高电平的上升沿,再产生一个高电平到低电平的下降沿。这样一来,肯定能触发NDS的CARD
LINE IRQ中断了。
【关闭窗口】