Go Down

Topic: Synchronizing a digital pin with pwm counter (Read 494 times) previous topic - next topic

kjellcb

Hiya all!

I have a project where I use one digital pin to trigger two cameras to take pictures. I also use two pins to
PWM control LED lights for these cameras.

My problem is that when on lower duty cycles on the PWM, I get flickering on the images.

Some lighter and some darker images.


Is there a way to read the counter for PWM and use that so I can trigger my cameras on the start of a PWM cycle?

This to try to get more uniform lighting on images overall.

Cameras uses 1.5 milliseconds to acquire an image, PWM pulse is at 1kHz (1 millisecond total time for the pulse from start to end)

On full duty cycle there is no problem, since lights are fully on.

Klaus_K

Have a look into the nRF52840 datasheet. You can find it in the Arduino Store store under TECH SPECS.

https://store.arduino.cc/arduino-nano-33-ble

The PWM module has four channels and all run from the same counter. You could use one channel to trigger your cameras and the other channels to control your LEDs. This will likely need some direct programming of the PWM module. The PWM module has a lot of options and I doubt the library supports them all.

femmeverbeek

Is it an idea to add a low pass filter to the power of the LED's to make them burn at constant intensity?

CrossRoads

Why not use a PWM signal to lower the perceived brightness?


Or just a resistor in series if you don't have a need to change the brightness under software control.

Steady state brightness is driven by current:
(Vcc - Vf)/current = resistor value needed.
So with 5V, Vf of say 2.2), and 5mA of current, which is still quite bright for modern LEDs, than resistance needed is:
(5V - 2.2)/.01A = 280 ohm. A standard 270 ohm will do quite fine.
(5v - 2.2)/270 ohm = 10.37mA.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

kjellcb

#4
Jul 21, 2020, 03:27 pm Last Edit: Jul 30, 2020, 03:04 pm by kjellcb
What I have found so far, is that the NRF have an interupt that can fire when PWM period is ended
Code: [Select]


// IRQ handler for ended pwm period on PWM1
extern "C"
{
        void PWM1_IRQHandler_v()
        {
            if(NRF_PWM1->EVENTS_PWMPERIODEND != 0)
            {
                NRF_PWM1->EVENTS_PWMPERIODEND = 0; // clear interrupt
                if (triggerPinValue == 1 ) // trigger value for camera
                {
                    NRF_TIMER4->TASKS_START = 1;
                    //triggerPinValue = 0;
                }
                else
                {
                    CAMERA_TRIG = 0; // Physical pin for triggering camera
                }
            }
        }
}

// IRQ handler for TIMER4, that handles camera trigger pin
extern "C"
{
    void TIMER4_IRQHandler_v()
    {
        if (NRF_TIMER4->EVENTS_COMPARE[0] == 1)
        {
            NRF_TIMER4->EVENTS_COMPARE[0] = 0;
            CAMERA_TRIG = 1; // Physical pin for triggering camera
            NRF_TIMER4->TASKS_STOP = 1;
        }
    }
}


// To activate this event the PWM needs to be set up using NRF's way

int32_t periodPWM[] = {500}; // variable for PWM period

// Set up pin for PWM
NRF_GPIO->DIRSET  = (1 << P0_21) // D8
NRF_GPIO->OUTCLR = (1 << P0_21) // set low

// Set up PWM1
NRF_PWM1->ENABLE = 0; // Disable for setup
NRF_PWM1->PRESCALER = PWM_PRESCALERPRESCALER_DIV_16 // 1us
NRF_PWM1->PSEL.OUT[0] = P0_21; // set pin for PWM channel 0
NRF_PWM1->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos); // Reset COUNTERTOP when top is reached
NRF_PWM1->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) | (PWM_DECODER_MODE_NextStep << PWM_DECODER_MODE_Pos); // Sets common compare register for all 4 channels
NRF_PWM1->LOOP        = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos); // Disable loop so PWM run forever
NRF_PWM1->COUNTERTOP = 1000; // Sets COUNTERTOP in us (1ms PWM period)
NRF_PWM1->SEQ[0].CNT = ((sizeof(periodPWM[0]) / sizeof(uint32_t)) << PWM_SEQ_CNT_CNT_Pos); // set 50% duty cycle
NRF_PWM1->SEQ[0].ENDDELAY = 0; // no delay at end
NRF_PWM1->SEQ[0].PTR = (uint32_t)&periodPWMm[0]; // Sets pointer to read sequence
NRF_PWM1->SEQ[0].REFRESH = 0; // no refresh of compare register
NRF_PWM1->SHORTS = 0; // No shortcuts between local events and tasks
NRF_PWM1->EVENTS_PWMPERIODEND = 0; // Set flag to 0
NRF_PWM1->INTEN = (PWM_INTEN_PWMPERIODEND_Msk); // enable interrupt on period end
NVIC_EnableIRQ(PWM1_IRQn); // Enable interrupt
NRF_PWM1->ENABLE = 1; // Enable PWM1
NRF_PWM1->TASKS_SEQSTART[0] = 1; // Start PWM1

// activate timer 4
NVIC_EnableIRQ(TIMER4_IRQn);







With this code, I get the sync I want on the cameras at 50% duty cycle
Now I need to work on changing the timer so I keep the CAMERA_TRIG sync with PWM pulse rising

*EDIT*
Added a picture from PulseView to show result.
Top line is camera trigger signal
Two bottom lines are PWM channels for light

Go Up