Multiple SPI interfaces using arduino NANO 33 BLE sense REV2

Hello, I want to program by arduino nano 33 BEL sense REV2 for reading data from two SPI instance simultaneously. Does this board support this? Is it possible to use different MOSI, MISO and CLK pins for both?

I moved your topic to an appropriate forum category @aki888.

In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.

This is an important part of responsible forum usage, as explained in the "How to get the best out of this forum" guide. The guide contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

What does the datasheet say?

If you actually mean at exactly the same time such that the MSB of both MOSI outputs are in sync, then the answer is No.

Datasheet just says, "High speed 32 MHz SPI and Quad SPI interface 32 MHz". Other than that, I could not find any further information in the datasheet.

If simultaneous process is not possible then is there any other way to do that even one after another?

Yes, there is only one SPI bus for the Nano 33 BLE. From the variants file in the Core.

#define SPI_HOWMANY 1

to do that even one after another?

Yes. You select the device to read with the CS pin and read it. You can switch between the two devices.

Yes. You can have many devices connected to SPI but each must have it's own CS pin. To talk to a specific device you activate the CS line for that device only. So you can only talk to one device at a time.

Here is a good explanation:
https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all

Here is the code, I am using to generate the two separate 8MHz clock from the Arduino nano 33 BLE sense REV2 to run the two AFEs, clock generated on A0 (P0.04 according to pinout diagram) is at 8MHz but the other clock on A2 (P0.30) is around 3.8KHz. Moreover, timerISR timmer routine is also not working on "FALLING" and SPI is not happening.

#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);
}

according to my understanding, this is due to some interrupt problem because I have gone through some post mentioning that nano 33 BLE boards only provide one external interrupt. is there anyway to use multiple timmers and interrupt in such a way that everything works smoothly?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.