frankzappa
Well-known member
Hello!
I've set up ADC_ETC to read 10 sensors in a sequence and I'm having trouble with the interrupt I'm trying to use to move the sensor data after ADC_ETC completes. Can anyone see what's going on? I'm using the Done0 interrupt and I think I'm clearing it properly but not sure if that's the correct approach. I would appreciate some help, I'm seriously getting depressed here, been trying to get this to work for three weeks. The problem is that the interrupt is firing constantly. If I remove the print I get the correct values but clearly it should just print once per second since the ADC frequency is 1Hz.
I've set up ADC_ETC to read 10 sensors in a sequence and I'm having trouble with the interrupt I'm trying to use to move the sensor data after ADC_ETC completes. Can anyone see what's going on? I'm using the Done0 interrupt and I think I'm clearing it properly but not sure if that's the correct approach. I would appreciate some help, I'm seriously getting depressed here, been trying to get this to work for three weeks. The problem is that the interrupt is firing constantly. If I remove the print I get the correct values but clearly it should just print once per second since the ADC frequency is 1Hz.
Code:
// ADC_ETC works but interrupts keep firing
#include "Arduino.h"
#include "ADC.h"
// ADC settings
ADC *adc = new ADC();
float frequency = 1.0f;
// Buffer size and number of buffers
#define BUFFER_SIZE 10 // Size of each buffer (5 sensors per ADC)
#define NUM_BUFFERS 3 // Number of buffers to cycle through
// Define the buffers as a 2D array
DMAMEM __attribute__((aligned(32))) static uint16_t buffers[NUM_BUFFERS][BUFFER_SIZE];
// Index variable to keep track of the current buffer being filled
volatile int buffer_index = 0;
// Index of the last filled buffer
volatile int last_filled_buffer_index = 0;
// Flag to indicate new data availability
volatile bool new_data_available = false;
// Pointer to the current buffer being filled by DMA
volatile uint16_t* current_buffer = buffers[0];
extern "C" {
extern void xbar_connect(unsigned int input, unsigned int output);
}
// Forward declarations
void adc_etc_reset();
void adc_etc_setup();
void adc_init();
void setup_timer_and_xbar(const float frequency);
void start_timer();
void dma_ch0_isr();
void setup() {
while (!Serial && millis() < 5000);
Serial.println("Setup ADC with Software Trigger");
// Configure ADC1 and ADC2
adc->adc0->setAveraging(4);
adc->adc0->setResolution(12);
adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED);
adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED);
adc->adc0->singleMode();
adc->adc0->disableInterrupts();
adc->adc1->setAveraging(4);
adc->adc1->setResolution(12);
adc->adc1->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED);
adc->adc1->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED);
adc->adc1->singleMode();
adc->adc1->disableInterrupts();
adc_init();
adc_etc_reset(); // Reset the ADC_ETC module
adc_etc_setup(); // Set up the ADC_ETC for software triggering
setup_timer_and_xbar(frequency);
delay(1000);
start_timer();
}
void loop() {
delay(500);
Serial.println("Values:");
// Print the values from the last filled buffer
for (int i = 0; i < BUFFER_SIZE; i++) {
Serial.print(buffers[0][i]);
if (i < BUFFER_SIZE - 1) {
Serial.print(", ");
}
}
Serial.println();
// Print the values from the last filled buffer
for (int i = 0; i < BUFFER_SIZE; i++) {
buffers[0][i] = 0;
buffers[1][i] = 0;
buffers[2][i] = 0;
}
// Print 5 values from TRIG[0]
volatile uint32_t* trig0_results = &IMXRT_ADC_ETC.TRIG[0].RESULT_1_0; // Get the address of the first result
for (int i = 0; i < 5; i++) {
uint16_t value = *((volatile uint16_t*)trig0_results + i); // Access the 16-bit values sequentially
Serial.print(value);
Serial.print(", ");
}
// Print 5 values from TRIG[4]
volatile uint32_t* trig4_results = &IMXRT_ADC_ETC.TRIG[4].RESULT_1_0; // Get the address of the first result
for (int i = 0; i < 5; i++) {
uint16_t value = *((volatile uint16_t*)trig4_results + i); // Access the 16-bit values sequentially
Serial.print(value);
if (i < 4) {
Serial.print(", ");
}
}
Serial.println();
}
void dma_ch0_isr() {
Serial.println("DMA ISR triggered");
__disable_irq(); // Disable interrupts at the start of the ISR
// Read 5 values from TRIG[0] results
volatile uint32_t* trig0_results = &IMXRT_ADC_ETC.TRIG[0].RESULT_1_0;
for (int i = 0; i < 5; i++) {
current_buffer[i] = *((volatile uint16_t*)trig0_results + i);
}
// Read 5 values from TRIG[4] results
volatile uint32_t* trig4_results = &IMXRT_ADC_ETC.TRIG[4].RESULT_1_0;
for (int i = 0; i < 5; i++) {
current_buffer[5 + i] = *((volatile uint16_t*)trig4_results + i);
}
// Update the index of the last filled buffer
last_filled_buffer_index = buffer_index;
// Update buffer index and wrap around if necessary
buffer_index = (buffer_index + 1) % NUM_BUFFERS;
// Update the current buffer pointer to the next buffer
current_buffer = buffers[buffer_index];
// Set flag to indicate new data is available
new_data_available = true;
ADC_ETC_DONE0_1_IRQ |= ADC_ETC_DONE0_1_IRQ_TRIG_DONE0(0); // clear
asm("dsb");
__enable_irq(); // Re-enable interrupts before exiting the ISR
}
void adc_init() {
ADC1_CFG |= ADC_CFG_ADTRG; // Hardware trigger
ADC1_HC0 = 16; // ADC_ETC channel, 144 int enabled, 16 int disabled
ADC1_GC &= ~ADC_GC_ADCO; // Continuous conversion disabled, same as adc->adcX->singleMode()
ADC2_CFG |= ADC_CFG_ADTRG; // Hardware trigger
ADC2_HC0 = 16; // ADC_ETC channel
ADC2_GC &= ~ADC_GC_ADCO; // Continuous conversion disabled
}
void adc_etc_reset() {
IMXRT_ADC_ETC.CTRL = ADC_ETC_CTRL_SOFTRST; // Perform a software reset on ADC_ETC
asm volatile("dsb"); // Ensure SOFTRST operation is completed
IMXRT_ADC_ETC.CTRL &= ~ADC_ETC_CTRL_SOFTRST; // Clear SOFTRST
delay(5);
}
void adc_etc_setup() {
const uint8_t chainLength0 = 5; // Chain length for TRIG[0]
const uint8_t chainLength4 = 5; // Chain length for TRIG[4]
// Clear the TSC_BYPASS bit to ensure ADC2 is not occupied by the Touch Screen Controller
IMXRT_ADC_ETC.CTRL &= ~ADC_ETC_CTRL_TSC_BYPASS; // Clear TSC_BYPASS (bit 30)
// Enable TRIG[0] for xbar triggering
IMXRT_ADC_ETC.CTRL |= ADC_ETC_CTRL_TRIG_ENABLE((1 << 0));
// Configure TRIG[0] for ADC1
IMXRT_ADC_ETC.TRIG[0].CTRL = ADC_ETC_TRIG_CTRL_TRIG_CHAIN(chainLength0 - 1);
// Configure chain for TRIG[0]
IMXRT_ADC_ETC.TRIG[0].CHAIN_1_0 =
ADC_ETC_TRIG_CHAIN_B2B0 |
ADC_ETC_TRIG_CHAIN_CSEL0(7) |
ADC_ETC_TRIG_CHAIN_IE0(0) |
ADC_ETC_TRIG_CHAIN_HWTS0(1) |
ADC_ETC_TRIG_CHAIN_B2B1 |
ADC_ETC_TRIG_CHAIN_CSEL1(8) |
ADC_ETC_TRIG_CHAIN_IE1(0) |
ADC_ETC_TRIG_CHAIN_HWTS1(1);
IMXRT_ADC_ETC.TRIG[0].CHAIN_3_2 =
ADC_ETC_TRIG_CHAIN_B2B0 |
ADC_ETC_TRIG_CHAIN_CSEL0(12) |
ADC_ETC_TRIG_CHAIN_IE0(0) |
ADC_ETC_TRIG_CHAIN_HWTS0(1) |
ADC_ETC_TRIG_CHAIN_B2B1 |
ADC_ETC_TRIG_CHAIN_CSEL1(11) |
ADC_ETC_TRIG_CHAIN_IE1(0) |
ADC_ETC_TRIG_CHAIN_HWTS1(1);
IMXRT_ADC_ETC.TRIG[0].CHAIN_5_4 =
ADC_ETC_TRIG_CHAIN_B2B0 |
ADC_ETC_TRIG_CHAIN_IE0(1) |
ADC_ETC_TRIG_CHAIN_CSEL0(6) |
ADC_ETC_TRIG_CHAIN_HWTS0(1);
// Configure TRIG[4] for ADC2 in sync mode with TRIG[0]
IMXRT_ADC_ETC.TRIG[4].CTRL =
ADC_ETC_TRIG_CTRL_TRIG_CHAIN(chainLength4 - 1) |
ADC_ETC_TRIG_CTRL_SYNC_MODE;
// Configure chain for TRIG[4]
IMXRT_ADC_ETC.TRIG[4].CHAIN_1_0 =
ADC_ETC_TRIG_CHAIN_B2B0 |
ADC_ETC_TRIG_CHAIN_CSEL0(5) |
ADC_ETC_TRIG_CHAIN_IE0(0) |
ADC_ETC_TRIG_CHAIN_HWTS0(1) |
ADC_ETC_TRIG_CHAIN_B2B1 |
ADC_ETC_TRIG_CHAIN_CSEL1(15) |
ADC_ETC_TRIG_CHAIN_IE1(0) |
ADC_ETC_TRIG_CHAIN_HWTS1(5);
IMXRT_ADC_ETC.TRIG[4].CHAIN_3_2 =
ADC_ETC_TRIG_CHAIN_B2B0 |
ADC_ETC_TRIG_CHAIN_CSEL0(0) |
ADC_ETC_TRIG_CHAIN_IE0(0) |
ADC_ETC_TRIG_CHAIN_HWTS0(5) |
ADC_ETC_TRIG_CHAIN_B2B1 |
ADC_ETC_TRIG_CHAIN_CSEL1(13) |
ADC_ETC_TRIG_CHAIN_IE1(0) |
ADC_ETC_TRIG_CHAIN_HWTS1(5);
IMXRT_ADC_ETC.TRIG[4].CHAIN_5_4 =
ADC_ETC_TRIG_CHAIN_B2B0 |
ADC_ETC_TRIG_CHAIN_IE0(0) |
ADC_ETC_TRIG_CHAIN_CSEL0(14) |
ADC_ETC_TRIG_CHAIN_HWTS0(5);
// Attach the interrupt vector for ADC_ETC TRIG[4] interrupt
attachInterruptVector(IRQ_ADC_ETC0, dma_ch0_isr);
// Set interrupt priority if needed (optional, lower number = higher priority)
NVIC_SET_PRIORITY(IRQ_ADC_ETC0, 10); // Example priority level
// Enable the ADC_ETC interrupt
NVIC_ENABLE_IRQ(IRQ_ADC_ETC0);
}
void setup_timer_and_xbar(const float frequency) {
CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON); // Enable clock for XBAR
// Connect TMR4 Timer output to ADC_ETC Trigger input
xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG00); // Connect Timer to trigger TRIG[0]
}
void start_timer() {
// Configure TMR4 Timer directly
TMR4_ENBL &= ~(1 << 0); // Disable Timer
TMR4_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
TMR4_CSCTRL0 = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_TCF1EN;
TMR4_CNTR0 = 0;
TMR4_LOAD0 = 0;
TMR4_COMP10 = (float)F_BUS_ACTUAL / frequency / 2; // Set compare value based on desired frequency
TMR4_CMPLD10 = (float)F_BUS_ACTUAL / frequency / 2; // Set compare value
TMR4_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(3); // Timer configuration
TMR4_ENBL |= (1 << 0); // Enable Timer
// Debug output to verify timer setup
Serial.printf("Timer started with calculated period: %lu ticks\n", (uint32_t)(F_BUS_ACTUAL / (frequency * 2)));
Serial.flush();
}