我正在尝试实现我自己的从FPGA到Arduino的SPI通信,其中我的FPGA作为MASTER并生成用于通信的芯片使能和时钟。 FPGA 在上升沿发送数据,在下降沿接收数据,我的 FPGA 代码工作正常。
在 Arduino 端,我在中断时捕获该主时钟,并在其上升沿接收数据并在其下降沿发送数据,但如果我从 10 KHz 增加时钟速度,通信将无法正常工作。
根据我的理解,Arduino Due 工作在 84 MHz,处理 1 MHz 中断不是一个大问题。您能告诉我如何使用 Arduino Due 处理这个高速时钟吗?
Arduino 代码如下:
void ISR1();
// this constant won't change
const int S_CLK = 19; // slow clock in this case FPGA is master
const int MOSI_C = 51; // Master out slave in in this case arduino
//receive data from FPGA
const int MISO_C = 50; // Master in slave out in this case arduino
//transmit data from FPGA
const int SS_C = 53; // the pin that the pushbutton is attached to
const int TRANS_INDEX = 32; //index that is used to transmit data in this
cas 32 bits are transmitted
const int REC_INDEX = 48;
#define CLK_MAIN 84000000UL
//Variables will change
int ss_check = 0; //used for reading of slave select
int mosi_data[REC_INDEX + 2]; //delcare receiving data array length
int count = 0; //used for convertion of bits to bytes
int index_r_stat = 0; //give us a value of status that
how much bits are received
int flag = 0; //used for stop reading s
int miso_out[TRANS_INDEX] = {
1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0
};
int miso_index = 0; //used for above array
int last_clk_state = 1; //used for the detection of rising and
falling edge
int check_clk;
void setup() {
// initialize the button pin as a input
pinMode(S_CLK , INPUT);
pinMode(MOSI_C , INPUT);
pinMode(MISO_C , OUTPUT);
pinMode(SS_C , INPUT);
// initialize serial communication
Serial.begin(9600);
}
void loop() {
// read the pushbutton input pin
ss_check = digitalRead(SS_C);
//Serial.println(ss_check);
//WAIT until slave select is not read
if (ss_check == 0) {
//attach interrupt so that data is
attachInterrupt(digitalPinToInterrupt(S_CLK), ISR1, CHANGE);
}
if ((index_r_stat == (REC_INDEX + 1)) && (flag == 0)) {
for (int i = 1; i < (REC_INDEX + 1); i = i + 1) {
Serial.print(mosi_data[i]);
flag = 1;
if (count < 7) {
count = count + 1;
} else {
count = 0;
Serial.println();
}
}
}
}
void ISR1() {
if ((last_clk_state == 1) && (digitalRead(S_CLK) == 0)) {
check_clk = 0;
//this code is used to transmit data to FPGA
if (miso_index < TRANS_INDEX - 1) {
digitalWrite(MISO_C, miso_out[miso_index]);
miso_index = miso_index + 1;
} else {
miso_index = miso_index;
}
} else {
check_clk = 1;
//this code is used for reading data from FPGA
if (index_r_stat < (REC_INDEX + 1)) {
mosi_data[index_r_stat] = digitalRead( MOSI_C);
index_r_stat = index_r_stat + 1;
} else {
detachInterrupt(S_CLK);
index_r_stat = index_r_stat;
}
}
last_clk_state = digitalRead(S_CLK);
}
您的 ISR 子例程可能是实现更高 SPI 速度的限制因素,特别是如果它没有针对快速执行进行优化。是的,Arduino Due 的 CPU 运行频率为 84 MHZ,但是您的 ISR 例程是否只需 84 cc 即可执行以达到 1MHZ?我认为你上面列出的代码需要 100-1000CC 的量级。所以时钟周期的上限为 84KHZ。还有上升沿和下降沿的 ISR。所以将其除以 2。
以下是优化 ISR 以实现更快 SPI 通信的一些注意事项:
直接寄存器访问 考虑直接访问 GPIO 寄存器以实现更快的读写操作,而不是使用 Arduino 库函数(例如 digitalRead() 和 digitalWrite())。这可以显着减少开销并提高 ISR 性能。
通过简化 ISR 内的数据处理来优化数据处理,以最大程度地减少延迟。如果可能的话,也许只分配时间用于写作,其他时间用于阅读。您可以读取一个字节,然后写入一个字节。另外,看看是否可以使用使用 SPI 硬件的 SPI 库缓冲区。所以你可以以字节而不是位来读取。