Hello,
I am programming by arduino nano 33 BLE sense REV2 board, for two SPI to communicate with two AFEs. For driving two AFEs, I am trying to generate two 8MHz clock for each AFE, but I am getting one clock of 8MHz and the other is just 4kHz.
Moreover, I am trying to use the interrupts for SPIs but it just work for one AFE and also on 'LOW' not on 'FALLING'.
I looked for solution on arduino forums and think that it is due to timer and external interrupts may be, I am not sure. does anyone have a solution for this?
Thanks in advance.
Here is the sketch:
#include <SPI.h>
#include <stdio.h>
#include <stdlib.h>
#include <nrf.h>
#include <NRF52_MBED_TimerInterrupt.h> // TimerInterrupt_Generic library
NRF52_MBED_Timer ITimer; // Timer object
#define CLOCK_OUTPUT_PIN1 4 // P0.04 (8 MHz clock on pin A0)
#define CLOCK_OUTPUT_PIN2 30 // P0.30 (8 MHz clock on pin A2)
#define SPI_CLOCK 4000000 // 4 MHz SPI clock
#define SPI_MODE SPI_MODE0 // SPI mode
#define SPI_ORDER MSBFIRST // Most Significant Bit First
#define true 1
#define false 0
// Pin definitions for AFE1 (SPI0)
#define MOSI_1 11
#define MISO_1 12
#define SCK_1 13
#define SS_1 10
#define PDNZ_1 9 // Custom PDNZ pin
#define ADC_RDY_1 8 // Custom ADC_RDY pin
// Pin definitions for AFE2 (SPI1)
#define SS_2 7
#define PDNZ_2 6 // Custom PDNZ pin
#define ADC_RDY_2 5 // ADC_RDY pin for AFE2
volatile bool readDataFlag1 = false; // Flag for AFE1
volatile bool readDataFlag2 = false; // Flag for AFE2
void AFE_Set_Register(byte csPin, byte thisRegister, unsigned long data);
void setup() {
Serial.begin(9600);
// Configure GPIO pins for clock outputs
NRF_P0->PIN_CNF[CLOCK_OUTPUT_PIN1] = (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
(GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
(GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
NRF_P0->PIN_CNF[CLOCK_OUTPUT_PIN2] = (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
(GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
(GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
// Configure TIMER4 for 8 MHz clock on CLOCK_OUTPUT_PIN1
NRF_TIMER4->MODE = TIMER_MODE_MODE_Timer; // Set as Timer
NRF_TIMER4->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos; // 16-bit Timer
NRF_TIMER4->PRESCALER = 0; // Prescaler 0 -> Full Speed (16 MHz base clock)
NRF_TIMER4->CC[0] = 1; // Toggle every 1 cycle (16 MHz / 2 = 8 MHz)
NRF_TIMER4->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
// Configure GPIOTE for toggling CLOCK_OUTPUT_PIN1
NRF_GPIOTE->CONFIG[0] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
(CLOCK_OUTPUT_PIN1 << GPIOTE_CONFIG_PSEL_Pos) |
(GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos);
// Configure TIMER3 for 8 MHz clock on CLOCK_OUTPUT_PIN2
NRF_TIMER3->MODE = TIMER_MODE_MODE_Timer; // Set as Timer
NRF_TIMER3->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos; // 16-bit Timer
NRF_TIMER3->PRESCALER = 0; // Prescaler 0 -> Full Speed (16 MHz base clock)
NRF_TIMER3->CC[0] = 1; // Toggle every 1 cycle (16 MHz / 2 = 8 MHz)
NRF_TIMER3->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
// Configure GPIOTE for toggling CLOCK_OUTPUT_PIN2
NRF_GPIOTE->CONFIG[1] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
(CLOCK_OUTPUT_PIN2 << GPIOTE_CONFIG_PSEL_Pos) |
(GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos);
// Configure PPI to connect TIMER4 to CLOCK_OUTPUT_PIN1
NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER4->EVENTS_COMPARE[0];
NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
// Configure PPI to connect TIMER3 to CLOCK_OUTPUT_PIN2
NRF_PPI->CH[1].EEP = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[0];
NRF_PPI->CH[1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[1];
// Start TIMER4 for CLOCK_OUTPUT_PIN1
NRF_TIMER4->TASKS_CLEAR = 1; // Clear Timer 4
NRF_TIMER4->TASKS_START = 1; // Start Timer 4
// Start TIMER3 for CLOCK_OUTPUT_PIN2
NRF_TIMER3->TASKS_CLEAR = 1; // Clear Timer 3
NRF_TIMER3->TASKS_START = 1; // Start Timer 3
// Enable PPI channels after timers start
NRF_PPI->CHENSET = (1 << 0) | (1 << 1); // Enable both PPI channels
// Initialize pins for AFE1
pinMode(SS_1, OUTPUT);
digitalWrite(SS_1, HIGH);
pinMode(PDNZ_1, OUTPUT);
digitalWrite(PDNZ_1, HIGH);
pinMode(ADC_RDY_1, INPUT);
// Initialize pins for AFE2
pinMode(SS_2, OUTPUT);
digitalWrite(SS_2, HIGH);
pinMode(PDNZ_2, OUTPUT);
digitalWrite(PDNZ_2, HIGH);
pinMode(ADC_RDY_2, INPUT);
// Initialize SPI
SPI.begin();
SPI.beginTransaction(SPISettings(SPI_CLOCK, SPI_ORDER, SPI_MODE));
// Initialize AFE1 and AFE2
initializeAFE_1();
initializeAFE_2();
// Start Timer Interrupt
if (ITimer.attachInterruptInterval(2000, timerISR)) { // 2000 microseconds = 2ms
Serial.println("Timer started successfully!");
}
else {
Serial.println("Failed to start timer!");
}
AFE_Set_READABLE(SS_1);
AFE_Set_READABLE(SS_2);
}
void loop() {
if (readDataFlag1) {
readDataFlag1 = false; // Reset the flag
uint32_t receivedVal1 = AFE_Read_Register(SS_1, 42); // Read GREEN_LED data from AFE1
//Serial.print("AFE1 GREEN_LED Data: ");
Serial.print(receivedVal1);
}
if (readDataFlag2) {
readDataFlag2 = false; // Reset the flag
uint32_t receivedVal2 = AFE_Read_Register(SS_2, 42); // Read GREEN_LED data from AFE2
Serial.print("\t");
Serial.print(receivedVal2);
Serial.print("\n");
}
}
void initializeAFE_1() {
AFE_Set_Register(SS_1, 0, 8); // Control 0 Reset
AFE_Set_Register(SS_1, 1, 6050); // LED2STC
AFE_Set_Register(SS_1, 2, 7998); // LED2ENDC
AFE_Set_Register(SS_1, 3, 6000); // LED2LEDSTC
AFE_Set_Register(SS_1, 4, 7999); // LED2LEDENDC
AFE_Set_Register(SS_1, 5, 50); // ALED2STC
AFE_Set_Register(SS_1, 6, 1998); // ALED2ENDC
AFE_Set_Register(SS_1, 7, 2050); // LED1STC
AFE_Set_Register(SS_1, 8, 3998); // LED1ENDC
AFE_Set_Register(SS_1, 9, 2000); // LED1LEDSTC
AFE_Set_Register(SS_1, 10, 3999); // LED1LEDENDC
AFE_Set_Register(SS_1, 11, 4050); // ALED1STC
AFE_Set_Register(SS_1, 12, 5998); // ALED1ENDC
AFE_Set_Register(SS_1, 13, 4); // LED2CONVST
AFE_Set_Register(SS_1, 14, 1999); // LED2CONVEND
AFE_Set_Register(SS_1, 15, 2004); // ALED2CONVST
AFE_Set_Register(SS_1, 16, 3999); // ALED2CONVEND
AFE_Set_Register(SS_1, 17, 4004); // LED1CONVST
AFE_Set_Register(SS_1, 18, 5999); // LED1CONVEND
AFE_Set_Register(SS_1, 19, 6004); // ALED1CONVST
AFE_Set_Register(SS_1, 20, 7999); // ALED1CONVEND
AFE_Set_Register(SS_1, 21, 0); // ADCRSTSTXT0
AFE_Set_Register(SS_1, 22, 3); // ADCRSTENDCT0
AFE_Set_Register(SS_1, 23, 2000); // ADCRSTSTCT1
AFE_Set_Register(SS_1, 24, 2003); // ADCRSTENDCT1
AFE_Set_Register(SS_1, 25, 4000); // ADCRSTSTCT2
AFE_Set_Register(SS_1, 26, 4003); // ADCRSTENDCT2
AFE_Set_Register(SS_1, 27, 6000); // ADCRSTSTCT3
AFE_Set_Register(SS_1, 28, 6003); // ADCRSTENDCT3
AFE_Set_Register(SS_1, 29, 7999); // PRPCOUNT
AFE_Set_Register(SS_1, 30, 0x107); // CONTROL1
AFE_Set_Register(SS_1, 32, 0x08002); // TIA_GAIN-----IR
AFE_Set_Register(SS_1, 33, 0x24402); // TIA_AMB_GAIN------GREEN/RED
AFE_Set_Register(SS_1, 34, 0x10014); // LEDCNTRL
AFE_Set_Register(SS_1, 35, 0x40000); // CONTROL2
AFE_Set_Register(SS_1, 49, 0x08000); // CONTROL3
digitalWrite(SS_1, HIGH);
}
void initializeAFE_2() {
AFE_Set_Register(SS_2, 0, 8); // Control 0 Reset
AFE_Set_Register(SS_2, 1, 6050); // LED2STC
AFE_Set_Register(SS_2, 2, 7998); // LED2ENDC
AFE_Set_Register(SS_2, 3, 6000); // LED2LEDSTC
AFE_Set_Register(SS_2, 4, 7999); // LED2LEDENDC
AFE_Set_Register(SS_2, 5, 50); // ALED2STC
AFE_Set_Register(SS_2, 6, 1998); // ALED2ENDC
AFE_Set_Register(SS_2, 7, 2050); // LED1STC
AFE_Set_Register(SS_2, 8, 3998); // LED1ENDC
AFE_Set_Register(SS_2, 9, 2000); // LED1LEDSTC
AFE_Set_Register(SS_2, 10, 3999); // LED1LEDENDC
AFE_Set_Register(SS_2, 11, 4050); // ALED1STC
AFE_Set_Register(SS_2, 12, 5998); // ALED1ENDC
AFE_Set_Register(SS_2, 13, 4); // LED2CONVST
AFE_Set_Register(SS_2, 14, 1999); // LED2CONVEND
AFE_Set_Register(SS_2, 15, 2004); // ALED2CONVST
AFE_Set_Register(SS_2, 16, 3999); // ALED2CONVEND
AFE_Set_Register(SS_2, 17, 4004); // LED1CONVST
AFE_Set_Register(SS_2, 18, 5999); // LED1CONVEND
AFE_Set_Register(SS_2, 19, 6004); // ALED1CONVST
AFE_Set_Register(SS_2, 20, 7999); // ALED1CONVEND
AFE_Set_Register(SS_2, 21, 0); // ADCRSTSTXT0
AFE_Set_Register(SS_2, 22, 3); // ADCRSTENDCT0
AFE_Set_Register(SS_2, 23, 2000); // ADCRSTSTCT1
AFE_Set_Register(SS_2, 24, 2003); // ADCRSTENDCT1
AFE_Set_Register(SS_2, 25, 4000); // ADCRSTSTCT2
AFE_Set_Register(SS_2, 26, 4003); // ADCRSTENDCT2
AFE_Set_Register(SS_2, 27, 6000); // ADCRSTSTCT3
AFE_Set_Register(SS_2, 28, 6003); // ADCRSTENDCT3
AFE_Set_Register(SS_2, 29, 7999); // PRPCOUNT
AFE_Set_Register(SS_2, 30, 0x107); // CONTROL1
AFE_Set_Register(SS_2, 32, 0x08002); // TIA_GAIN-----IR
AFE_Set_Register(SS_2, 33, 0x24402); // TIA_AMB_GAIN------GREEN/RED
AFE_Set_Register(SS_2, 34, 0x10014); // LEDCNTRL
AFE_Set_Register(SS_2, 35, 0x40000); // CONTROL2
AFE_Set_Register(SS_2, 49, 0x08000); // CONTROL3
digitalWrite(SS_2, HIGH);
}
void timerISR() {
// Check ADC_RDY pins and set flags accordingly
if (digitalRead(ADC_RDY_1) == FALLING) {
readDataFlag1 = true;
}
if (digitalRead(ADC_RDY_2) == FALLING) {
readDataFlag2 = true;
}
}
void AFE_Set_Register(byte csPin, byte thisRegister, unsigned long data) {
digitalWrite(csPin, LOW);
SPI.transfer(thisRegister);
SPI.transfer((data >> 16) & 0xFF);
SPI.transfer((data >> 8) & 0xFF);
SPI.transfer(data & 0xFF);
digitalWrite(csPin, HIGH);
}
unsigned long AFE_Read_Register(byte csPin, byte addrToRead) {
unsigned long result = 0;
digitalWrite(csPin, LOW);
SPI.transfer(addrToRead);
result |= (SPI.transfer(0x00) << 16);
result |= (SPI.transfer(0x00) << 8);
result |= SPI.transfer(0x00);
digitalWrite(csPin, HIGH);
return result;
}
void AFE_Set_READABLE(byte csPin) {
byte toWrite[3] = {0x00, 0x00, 0x01}; // Data to write to CONTROL0 register
writeAFERegister(csPin, 0x00, toWrite);
}
void writeAFERegister(byte cs, byte thisRegister, byte AFEValue[]) {
digitalWrite(SS, LOW);
byte addrToSend = thisRegister;
SPI.transfer(addrToSend);
SPI.transfer(AFEValue[0]);
SPI.transfer(AFEValue[1]);
SPI.transfer(AFEValue[2]);
//delayMicroseconds(1);
digitalWrite(SS, HIGH);
}