#include <Arduino.h>
#include <DMAChannel.h>
#include <SD.h>
#include <imxrt.h>
#define BUTTON_PIN 3
#define BUFFER_SIZE 32768
#define SAMPLE_FREQ 20'000'000 //20'000'000 //1'000'000 to check
volatile uint32_t stopPosition = 0;
volatile uint32_t loopCount = 0;
volatile bool ReadyData = false;
DMAMEM static volatile uint32_t __attribute__((aligned(32))) dmaBuffer[BUFFER_SIZE];
DMAChannel dmaChannel_1;
void xbar_connect(unsigned int input, unsigned int output) // copied funcrion
{
if (input >= 88) return;
if (output >= 132) return;
volatile uint16_t *xbar = &XBARA1_SEL0 + (output / 2);
uint16_t val = *xbar;
if (!(output & 1)) {
val = (val & 0xFF00) | input;
} else {
val = (val & 0x00FF) | (input << 8);
}
*xbar = val;
}
void setupPIT() {
CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON); //PIT clock on
PIT_MCR = 0x00; // PIT on
PIT_LDVAL0 = PIT_DIV(); // PIT div
PIT_TCTRL0 = PIT_TCTRL_TEN | PIT_TCTRL_TIE; // PIT en + interrupt? | PIT_TCTRL_TIE
}
void setupDMA(){
dmaChannel_1.begin();
dmaChannel_1.attachInterrupt(DMA_ISR);
dmaChannel_1.interruptAtCompletion();
dmaChannel_1.source(*(volatile uint32_t*) &GPIO1_DR);
dmaChannel_1.destinationCircular(dmaBuffer, BUFFER_SIZE * 4);
dmaChannel_1.transferSize(4);
CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
xbar_connect(XBARA1_IN_PIT_TRIGGER0, XBARA1_OUT_DMA_CH_MUX_REQ30); // connect pit to dma with xbar
XBARA1_CTRL0 = XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0; //0 - 0ff; 1 - rising; 2 - falling; 3 - both
dmaChannel_1.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_0);
volatile uint32_t *mux = &DMAMUX_CHCFG0 + dmaChannel_1.channel;
*mux |= DMAMUX_CHCFG_TRIG;
dmaChannel_1.enable();
}
void setupGPIO(){
const uint32_t PIN_MASK = 0x0FFF0000;
//IOMUXC_GPR_GPR26 |= PIN_MASK; // switch GPIO1 to GPIO6.
GPIO1_GDIR &= ~PIN_MASK; // pins in
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, FALLING);
}
void DMA_ISR()
{
dmaChannel_1.clearInterrupt();
loopCount++;
}
void buttonISR(){
detachInterrupt(digitalPinToInterrupt(BUTTON_PIN)); // to fix second save of same data
PIT_TCTRL0 &= ~PIT_TCTRL_TEN; // stop timer
analogWrite(9, 0);
ReadyData = true;
}
static uint32_t PIT_DIV() {
uint32_t ahb_div = ((CCM_CBCDR >> 10) & 0x7) + 1;
uint32_t ipg_div = ((CCM_CBCDR >> 8) & 0x3) + 1;
uint32_t ipg_freq = F_CPU_ACTUAL / ahb_div / ipg_div;
return ((ipg_freq / SAMPLE_FREQ) - 1);
}
void savetoSD(){
while (!SD.begin(BUILTIN_SDCARD));
static uint16_t fileIdx = 0;
char filename[24];
snprintf(filename, sizeof(filename), "ADC_%04u.CSV", fileIdx++);
File f = SD.open(filename, FILE_WRITE);
if (!f) {
Serial.printf("Cannot open %s\n", filename);
return;
}
stopPosition = ((uintptr_t)dmaChannel_1.TCD->DADDR - (uintptr_t)dmaBuffer)/sizeof(uint32_t);
if (stopPosition >= BUFFER_SIZE) stopPosition = 0;
const uint32_t ADC_MASK = 0x00FF0000;
uint32_t value;
char line[52];
for (uint32_t i = stopPosition; i < BUFFER_SIZE; i++) {
value = (dmaBuffer[i] & ADC_MASK)>>16;
snprintf(line, sizeof(line), "%lu, %lu\r\n", i,value);
f.print(line);
}
for (uint32_t i = 0; i < stopPosition; i++) {
value = (dmaBuffer[i] & ADC_MASK)>>16;
snprintf(line, sizeof(line), "%lu, %lu\r\n", i, value);
f.print(line);
}
f.close();
Serial.printf("saved\n");
}
void generateSignal(){
analogWriteFrequency(9, SAMPLE_FREQ);
analogWriteResolution(2);
analogWrite(9, 2);
}
void clock_check(){
uint32_t ahb_div = ((CCM_CBCDR >> 10) & 0b111) + 1;
uint32_t ipg_div = ((CCM_CBCDR >> 8) & 0b11) + 1;
volatile uint32_t ahb_freq = F_CPU_ACTUAL / ahb_div;
volatile uint32_t ipg_freq = ahb_freq / ipg_div;
Serial.printf("AHD %lu\n", ahb_freq);
Serial.printf("IGP %lu\n", ipg_freq);
Serial.print("F_CPU: ");
Serial.println(F_CPU);
Serial.print("CCM_CBCDR: 0x");
Serial.println(CCM_CBCDR, HEX);
}
void setup() {
CCM_CBCDR = (CCM_CBCDR & ~(0x3 << 8)) | (0x2 << 8); // change IGP div 4 to 3 (with 2 system doesnt answer) // default AHD div = 1?
Serial.begin(115200);
while(!Serial);
setupGPIO();
setupDMA();
setupPIT();
generateSignal();
clock_check();
Serial.printf("Ready\n");
}
static uint32_t lastTime = 0;
static uint32_t lastCount = 0;
void loop() {
if(ReadyData){
arm_dcache_delete((void*)dmaBuffer, sizeof(dmaBuffer));
savetoSD();
PIT_TCTRL0 = PIT_TCTRL_TEN | PIT_TCTRL_TIE; // start timer | PIT_TCTRL_TIE ?
generateSignal();
ReadyData = false;
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, FALLING);
}
uint32_t now = micros();
if (now - lastTime >= 1'000'000) {
uint32_t transfers = (loopCount - lastCount) * BUFFER_SIZE;
uint32_t period = now - lastTime;
lastCount = loopCount;
lastTime = now;
Serial.printf("real dma clock: %lu MHz\n", transfers / period); // wrong ??
}
}