Unfortunatelly it is already on ram... Also, I've tried the two core option using a queue to comunicate between cores, but it also introduces delays... I expected that the NMI would have no timming variations because other subsystems but it does, I'm not an expert in ARM architecture but I suppose that whenever there is a context change depending on the processor status it has to do more or less work when it enters/leaves the interrupt. That or the interrupt risen by the PIO gets delayed somehow.I am kind of surprised that the USB IRQ could interfere with an NMI interrupt since it has the highest priority. I guess the USB code running might throw your time sensitive interrupt handler code out of the XIP cache and that would make it run slower. Flagging your time sensitive code to all run out of RAM should fix that issue. I tend to run my time sensitive code out of RAM on the second core and allow the USB stack to do as it pleases with the first core and the XIP cache.
In case someone wants to see the code here it is, is a bit complex, is from a logic analyzer that I've been developing for some years now, it has a "burst mode" and what I'm trying to implement is the measurement of the time that happens between bursts. As the analyzer is capable of sampling 100Mhz signals I need that 5ns resolution...
Code:
;PIO program.program POSITIVE_CAPTURE_MEASUREBURSTS pull out y 32 ;read loop count pull mov x, osr ;read capture length (use MOV instead of PULL so we can MOV it again on each loop) irq wait 1 ;trigger NMI to sync first timestamp .wrap_target in pins 32 ;read sample jmp pin POST_CAPTURE;exit wrap if pin is set.wrapPOST_CAPTURE: in pins 32 ;read sample jmp x-- POST_CAPTURE;loop if more samples needed jmp y-- LOOP ;jump to loop control irq 1 ;trigger NMI on the CPU to capture burst timestamp irq 0 ;notify to the main program that we have finished capturingLOCK: jmp LOCK ;block the programLOOP: irq 1 ;trigger NMI on the CPU to capture burst timestamp mov x, osr ;read loop countINNER_LOOP: jmp pin POST_CAPTURE ;wait for trigger jmp INNER_LOOP
Code:
//Capture start and NMI/SysTick handlersvoid __not_in_flash_func(sysTickRoll)(){ systickLoops++;}void __not_in_flash_func(loopEndHandler)(){ //Save timestamp loopTimestamp[timestampIndex++] = systick_hw->cvr | systickLoops << 24; //timestamp; //Clear PIO interrupt capturePIO->irq = (1u << 1);}bool startCaptureSimple(uint32_t freq, uint32_t preLength, uint32_t postLength, uint8_t loopCount, uint8_t measureBursts, const uint8_t* capturePins, uint8_t capturePinCount, uint8_t triggerPin, bool invertTrigger, CHANNEL_MODE captureMode){ int maxSamples; switch(captureMode) { case MODE_8_CHANNEL: maxSamples = 131072; break; case MODE_16_CHANNEL: maxSamples = 65536; break; case MODE_24_CHANNEL: maxSamples = 32768; break; } //Too many samples requested? if(preLength + (postLength * (loopCount + 1)) >= maxSamples) return false; //Frequency too high? if(freq > 100000000) return false; //Incorrect pin count? if(capturePinCount < 0 || capturePinCount > 24) return false; //Incorrect trigger pin? if(triggerPin < 0 || triggerPin > 24) return false; //Clear capture buffer (to avoid sending bad data if the trigger happens before the presamples are filled) memset(captureBuffer, 0, sizeof(captureBuffer)); //Store info about the capture lastPreSize = preLength; lastPostSize = postLength; lastLoopCount = loopCount; lastCapturePinCount = capturePinCount; lastTriggerInverted = invertTrigger; lastCaptureComplexFast = false; lastCaptureMode = captureMode; //Map channels to pins for(uint8_t i = 0; i < capturePinCount; i++) lastCapturePins[i] = pinMap[capturePins[i]]; //Store trigger info triggerPin = pinMap[triggerPin]; lastTriggerPin = triggerPin; //Calculate clock divider based on frequency, it generates a clock 2x faster than the capture freequency float clockDiv = (float)clock_get_hz(clk_sys) / (float)(freq * 2); //Store the PIO unit and clear program memory capturePIO = pio0; pio_clear_instruction_memory(capturePIO); //Configure capture SM sm_Capture = pio_claim_unused_sm(capturePIO, true); pio_sm_clear_fifos(capturePIO, sm_Capture); pio_sm_restart(capturePIO, sm_Capture); //Load correct program, depending on the trigger edge if(invertTrigger) { if(measureBursts) captureOffset = pio_add_program(capturePIO, &NEGATIVE_CAPTURE_MEASUREBURSTS_program); else captureOffset = pio_add_program(capturePIO, &NEGATIVE_CAPTURE_program); } else { if(measureBursts) captureOffset = pio_add_program(capturePIO, &POSITIVE_CAPTURE_MEASUREBURSTS_program); else captureOffset = pio_add_program(capturePIO, &POSITIVE_CAPTURE_program); } //Configure capture pins for(int i = 0; i < 24; i++) pio_sm_set_consecutive_pindirs(capturePIO, sm_Capture, pinMap[i], 1, false); for(uint8_t i = 0; i < 24; i++) pio_gpio_init(capturePIO, pinMap[i]); //Configure trigger pin pio_sm_set_consecutive_pindirs(capturePIO, sm_Capture, triggerPin, 1, false); pio_gpio_init(capturePIO, triggerPin); //Configure state machines pio_sm_config smConfig = measureBursts? (invertTrigger? NEGATIVE_CAPTURE_MEASUREBURSTS_program_get_default_config(captureOffset): POSITIVE_CAPTURE_MEASUREBURSTS_program_get_default_config(captureOffset)) : (invertTrigger? NEGATIVE_CAPTURE_program_get_default_config(captureOffset): POSITIVE_CAPTURE_program_get_default_config(captureOffset)); //Input starts at pin INPUT_PIN_BASE sm_config_set_in_pins(&smConfig, INPUT_PIN_BASE); //Set clock to 2x required frequency sm_config_set_clkdiv(&smConfig, clockDiv); //Autopush per dword sm_config_set_in_shift(&smConfig, true, true, 0); //Configure trigger pin as JMP pin. sm_config_set_jmp_pin(&smConfig, triggerPin); //Configure interupt 0 pio_interrupt_clear (capturePIO, 0); pio_set_irq0_source_enabled(capturePIO, pis_interrupt0, true); irq_set_exclusive_handler(PIO0_IRQ_0, simple_capture_completed); irq_set_enabled(PIO0_IRQ_0, true); //Set-up burst measure if(loopCount > 0 && measureBursts) { //Configure NMI to get capture timestamp pio_interrupt_clear (capturePIO, 1); pio_set_irq1_source_enabled(capturePIO, pis_interrupt1, true); syscfg_hw->proc0_nmi_mask = 1 << PIO0_IRQ_1; oldNMIHandler = exception_set_exclusive_handler(NMI_EXCEPTION, loopEndHandler); //Reset loop counter systickLoops = 0; //Enable systick oldSysTickHandler = exception_set_exclusive_handler(SYSTICK_EXCEPTION, sysTickRoll); systick_hw->rvr = 0x00FFFFFF; systick_hw->cvr = 0x00FFFFFF; systick_hw->csr = 0x5; } //Reset timestamp index timestampIndex = 0; //Initialize state machine pio_sm_init(capturePIO, sm_Capture, captureOffset, &smConfig); //Configure DMA's configureCaptureDMAs(captureMode); //Enable state machine pio_sm_set_enabled(capturePIO, sm_Capture, true); //Write loop count and capture length to post program to start the capture process pio_sm_put_blocking(capturePIO, sm_Capture, loopCount); pio_sm_put_blocking(capturePIO, sm_Capture, postLength - 1); //Finally clear capture status, process flags and capture type captureFinished = false; captureProcessed = false; lastCaptureType = CAPTURE_TYPE_SIMPLE; //We're done return true;}
Statistics: Posted by Dr.Gusman — Sat Jun 08, 2024 11:42 pm