I2S ADC triggered with CAN data frame message

alega77
Posts: 2
Joined: Fri Dec 18, 2020 3:05 pm

I2S ADC triggered with CAN data frame message

Postby alega77 » Fri Dec 18, 2020 3:34 pm

Hi All,

I am using a fast sampling ADC toghether with I2S. The goal is sampling the CAN bus (CAN_L) once a new data frame is incoming in the queue.

To get kind of syncronization I just do the i2s_adc_enable if there is a message in CAN message incoming, like reported below:

Code: Select all

if(xQueueReceive(CAN_cfg.rx_queue,&rx_frame, 3*portTICK_PERIOD_MS)==pdTRUE){
      
      i2s_adc_enable(I2S_NUM_0);
      i2s_read(I2S_NUM_0, &buffer1, sizeof(buffer1), &bytes_read, 10);      
      i2s_adc_disable(I2S_NUM_0);
By doing so, I get bit of ACK sometimes around 80 sample (over 100) (see CAN01.jpg), sometimes around 60/100 sample (see CAN02.jpg).
The question is: Is there a way to trigger the ADC with the SOF (start of frame bit) of the CAN frame on the CAN bus?

I set the ADC to obtain a sample per bit (500kpbs since the CAN network is configured with a data rate of 500kbps).

Code: Select all

// i2s init function
void i2sInit(){
   i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
    .sample_rate =  500000,              // The format of the signal using ADC_BUILT_IN
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_I2S_MSB,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,      //ESP_INTR_FLAG_LEVEL1
    .dma_buf_count = 2,
    .dma_buf_len = 100,
    .use_apll = false,
    .tx_desc_auto_clear = false,
    .fixed_mclk = 0
   };
   i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
   i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT);
   //i2s_adc_enable(I2S_NUM_0);
   i2s_adc_disable(I2S_NUM_0);
}

Code: Select all

// CAN init funcion
void canInit(){
  CAN_cfg.speed=CAN_SPEED_500KBPS;    //can set speed
  CAN_cfg.tx_pin_id = GPIO_NUM_5;     // can set TX to pin 5
  CAN_cfg.rx_pin_id = GPIO_NUM_4;     // can set RX to pin 4
  CAN_cfg.rx_queue = xQueueCreate(1,sizeof(CAN_frame_t));  // mod queue size 1
  //start CAN Module
  ESP32Can.CANInit();
}
Thanks to everyone :D
Attachments
CAN02.jpg
CAN02.jpg (26.72 KiB) Viewed 2856 times
CAN01.jpg
CAN01.jpg (28.77 KiB) Viewed 2856 times

ESP_Dazz
Posts: 308
Joined: Fri Jun 02, 2017 6:50 am

Re: I2S ADC triggered with CAN data frame message

Postby ESP_Dazz » Mon Dec 21, 2020 1:48 pm

alega77 wrote: The question is: Is there a way to trigger the ADC with the SOF (start of frame bit) of the CAN frame on the CAN bus?
Currently no, the CAN controller will only generate an interrupt once a CAN message has been confirmed valid (i.e., Acknowledged and CRC is checked).

If you need an interrupt on the SOF, I think you might be better of routing the RX signal of your to a GPIO interrupt.

alega77
Posts: 2
Joined: Fri Dec 18, 2020 3:05 pm

Re: I2S ADC triggered with CAN data frame message

Postby alega77 » Tue Dec 22, 2020 5:45 pm

Many thanks for the suggestion.

I connected Pin 26 to the RX of the transceiver (sn65hvd230), so once the SOF rising is incoming it runs the ISR that do the i2s_adc_enable (see code below). In this way I can get a better syncronization (even if i loose some bit at beginning).

At least it seems something that it is replicable, as shown in CANsamples01 & 02. Same packet is sent but at different time.

Any other suggestion to improve the code? Thanks again a lot. :D

Code: Select all


void IRAM_ATTR isr_sampling() {
    if(i2read){
      i2s_adc_enable(I2S_NUM_0);    //enable reading on ADC
      i2read = 0;
    }
}

void setup() {
    ....
    // initialize pin 26 of ISR as input 
    pinMode(pin_isr, INPUT);
    // Set pin 26 as interrupt, assign isr_sampling function and set RISING mode
    attachInterrupt(digitalPinToInterrupt(pin_isr), isr_sampling, RISING);
    
    //create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
    xTaskCreatePinnedToCore(
                    Task1CANcode,   /* Task function. */
                    "TaskCAN",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    3,           /* priority of the task - 3 highest, 0 lowest prioriy*/
                    &Task1CAN,      /* Task handle to keep track of created task */
                    0);          /* pin task to core 0 */                  
  delay(500);
}

void Task1CANcode( void * pvParameters ){
  Serial.print("TaskCAN running on core ");
  Serial.println(xPortGetCoreID());
  Serial.println("CAN demo");
  CAN_frame_t rx_frame;
  
  for(;;){
    //receive next CAN frame from queue
    if(xQueueReceive(CAN_cfg.rx_queue,&rx_frame, 3*portTICK_PERIOD_MS)==pdTRUE){
      i2s_read(I2S_NUM_0, &buffer1, sizeof(buffer1), &bytes_read, 10);
      i2s_adc_disable(I2S_NUM_0);
            
      if (bytes_read == sizeof(buffer1)&& !i2read) {  // if i2read == 0
        for(int i=0; i<buffer_len; i+=1){
          Serial.printf("%d,", offset - buffer1[i]);
         }
        Serial.println();
        i2read = 1;
      }
      printf("MSG from 0x%03x, DLC %d\n",rx_frame.MsgID,  rx_frame.FIR.B.DLC);
    }
  } 
}

Attachments
CANsamples02.jpg
CANsamples02.jpg (30.1 KiB) Viewed 2711 times
CANsamples01.jpg
CANsamples01.jpg (30 KiB) Viewed 2711 times

Who is online

Users browsing this forum: No registered users and 91 guests