PWM via IR nRF5340

Hi,

I'm attempting to transmit IR signals over one of the PWM channels on the nRF5340. I noticed that the PRESCALER register only has 0 - 7 values in the OPS reference manual even though it's a 32-bit register. Is it possible to configure the 16MHz clock to be 38kHz for IR?

Thanks!

Brad

Parents
  • Hi,

    Other values are not supported. (Only the lower 3 bits of the register are in use).

  • Hi Einar,

    Would the nRF5340 be able to do IR transmission through one of the other peripherals instead?

    Thanks,

    Brad

  • Hi Einar,

    I mistyped. If you look at my code I know that 0x20 sets P1.00 (in the comments). Why does my code below not output anything on P1.00?

    void PWM0_INIT()
    {
    	// static uint32_t *pwm0RAMaddr = 0x50021000; // SRAM Address for SEQ[0] pointer
    	NRF_PWM0->PSEL.OUT[0] = (0 << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos); // replaced first_pin with 0
    	NRF_PWM0->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
    	NRF_PWM0->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
    	NRF_PWM0->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); // PWM_PRESCALER_PRESCALER_DIV_1 =
    	NRF_PWM0->COUNTERTOP = (0x1A5 << PWM_COUNTERTOP_COUNTERTOP_Pos);					  // 16MHz/421 = 38004.75   0x1A5 = 421
    	// Enable the shortcut from LOOPSDONE event to SEQSTART1 task for infinite loop
    	NRF_PWM0->SHORTS = (PWM_SHORTS_LOOPSDONE_SEQSTART1_Enabled << PWM_SHORTS_LOOPSDONE_SEQSTART1_Pos);
    	// LOOP_CNT must be greater than 0 for the LOOPSDONE event to trigger and enable looping
    	NRF_PWM0->LOOP = (1 << PWM_LOOP_CNT_Pos);
    	NRF_PWM0->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) |
    						(PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
    	// To repeat a single sequence until stopped, it must be configured in SEQ[1]
    	NRF_PWM0->SEQ[0].PTR = (msgHDR << PWM_SEQ_PTR_PTR_Pos);
    	NRF_PWM0->SEQ[0].CNT = ((sizeof(msgHDR) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
    	// NRF_PWM0->SEQ[0].PTR = ((uint32_t)(seq0_ram) << PWM_SEQ_PTR_PTR_Pos);
    	// NRF_PWM0->SEQ[0].CNT = ((sizeof(seq0_ram) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
    	NRF_PWM0->SEQ[0].REFRESH = 0;  // New duty cycle is pushed every PWM period
    	NRF_PWM0->SEQ[0].ENDDELAY = 0; // Play 2nd 32-bit sequence immediately after first is done
    	NRF_PWM0->SEQ[1].PTR = (msgFTR << PWM_SEQ_PTR_PTR_Pos);
    	NRF_PWM0->SEQ[1].CNT = ((sizeof(msgFTR) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
    	NRF_PWM0->SEQ[1].REFRESH = 10;
    	NRF_PWM0->SEQ[1].ENDDELAY = 10;
    	NRF_PWM0->TASKS_SEQSTART[0] = 1; // Restart sending first 32-bit sequence
    }

  • My LogicAnalyzer just shows that the pin is held high forever:

  • Sorry here is the correct version of code that is currently flashed on the board

    void PWM0_INIT()
    {	
    	static uint32_t msgHDR = 0x1234567; 
    	static uint32_t msgFTR = 0x7654321;	 
    	//static uint32_t test_seq = 0xFF00FF00; // toggled values
    	//static uint32_t *pwm0RAMaddr = 0x50021000; // SRAM Address for SEQ[0] pointer
    	NRF_PWM0->PSEL.OUT[0] = 0x20; // P1.00 --- (0 << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos); // replaced first_pin with 0
    	NRF_PWM0->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
    	NRF_PWM0->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
    	NRF_PWM0->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); // PWM_PRESCALER_PRESCALER_DIV_1 =
    	NRF_PWM0->COUNTERTOP = (0x1A5 << PWM_COUNTERTOP_COUNTERTOP_Pos); // 16MHz/421 = 38004.75   0x1A5 = 421
    	// Enable the shortcut from LOOPSDONE event to SEQSTART1 task for infinite loop
    	NRF_PWM0->SHORTS = (PWM_SHORTS_LOOPSDONE_SEQSTART1_Enabled << PWM_SHORTS_LOOPSDONE_SEQSTART1_Pos);
    	// LOOP_CNT must be greater than 0 for the LOOPSDONE event to trigger and enable looping
    	NRF_PWM0->LOOP = (1 << PWM_LOOP_CNT_Pos);
    	NRF_PWM0->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) |
    						(PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
    	// To repeat a single sequence until stopped, it must be configured in SEQ[1]
    	NRF_PWM0->SEQ[0].PTR = ((uint32_t)(msgHDR) << PWM_SEQ_PTR_PTR_Pos);
    	NRF_PWM0->SEQ[0].CNT = ((sizeof(msgHDR) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
    	// NRF_PWM0->SEQ[0].PTR = ((uint32_t)(seq0_ram) << PWM_SEQ_PTR_PTR_Pos);
    	// NRF_PWM0->SEQ[0].CNT = ((sizeof(seq0_ram) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
    	NRF_PWM0->SEQ[0].REFRESH = 0;  // New duty cycle is pushed every PWM period
    	NRF_PWM0->SEQ[0].ENDDELAY = 0; // Play 2nd 32-bit sequence immediately after first is done
    	NRF_PWM0->SEQ[1].PTR = ((uint32_t)(msgFTR) << PWM_SEQ_PTR_PTR_Pos);
    	NRF_PWM0->SEQ[1].CNT = ((sizeof(msgFTR) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
    	NRF_PWM0->SEQ[1].REFRESH = 0;
    	NRF_PWM0->SEQ[1].ENDDELAY = 0;
    	NRF_PWM0->TASKS_SEQSTART[0] = 1; // Restart sending first 32-bit sequence
    }

  • Hi Brad,

    I tested the code now, and found an additional issue. Your msgHDR and msgFTR are not arrays, so when setting them in NRF_PWM0->SEQ[0].PTR and NRF_PWM0->SEQ[1].PTR, you should have used the & to get the address. I just did it differently, and made some (larger arrays instead), modifying your function slightly:

    #define OUTPUT_PIN 32
    
    void PWM0_INIT()
    {	
    	uint16_t msgHDR[] = {0x0000, 0xFFFF, 0x8000, 0x0000, 0xFFFF, 0x8000,
    			     0x0000, 0xFFFF, 0x8000, 0x0000, 0xFFFF, 0x8000}; 
    	uint16_t msgFTR[] = {0x0000, 0xFFFF, 0x8000, 0x0000, 0xFFFF, 0x8000,
    			     0x0000, 0xFFFF, 0x8000, 0x0000, 0xFFFF, 0x8000};	 
    	//static uint32_t test_seq = 0xFF00FF00; // toggled values
    	//static uint32_t *pwm0RAMaddr = 0x50021000; // SRAM Address for SEQ[0] pointer
    	NRF_PWM0->PSEL.OUT[0] = OUTPUT_PIN;// 0x20; // P1.00 --- (0 << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos); // replaced first_pin with 0
    	NRF_PWM0->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
    	NRF_PWM0->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
    	NRF_PWM0->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); // PWM_PRESCALER_PRESCALER_DIV_1 =
    	NRF_PWM0->COUNTERTOP = (0x1A5 << PWM_COUNTERTOP_COUNTERTOP_Pos); // 16MHz/421 = 38004.75   0x1A5 = 421
    	// Enable the shortcut from LOOPSDONE event to SEQSTART1 task for infinite loop
    	NRF_PWM0->SHORTS = (PWM_SHORTS_LOOPSDONE_SEQSTART1_Enabled << PWM_SHORTS_LOOPSDONE_SEQSTART1_Pos);
    	// LOOP_CNT must be greater than 0 for the LOOPSDONE event to trigger and enable looping
    	NRF_PWM0->LOOP = (1 << PWM_LOOP_CNT_Pos);
    	NRF_PWM0->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) |
    						(PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
    	// To repeat a single sequence until stopped, it must be configured in SEQ[1]
    	NRF_PWM0->SEQ[0].PTR = ((uint32_t)(msgHDR) << PWM_SEQ_PTR_PTR_Pos);
    	NRF_PWM0->SEQ[0].CNT = ((sizeof(msgHDR) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
    	// NRF_PWM0->SEQ[0].PTR = ((uint32_t)(seq0_ram) << PWM_SEQ_PTR_PTR_Pos);
    	// NRF_PWM0->SEQ[0].CNT = ((sizeof(seq0_ram) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
    	NRF_PWM0->SEQ[0].REFRESH = 0;  // New duty cycle is pushed every PWM period
    	NRF_PWM0->SEQ[0].ENDDELAY = 0; // Play 2nd 32-bit sequence immediately after first is done
    	NRF_PWM0->SEQ[1].PTR = ((uint32_t)(msgFTR) << PWM_SEQ_PTR_PTR_Pos);
    	NRF_PWM0->SEQ[1].CNT = ((sizeof(msgFTR) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
    	NRF_PWM0->SEQ[1].REFRESH = 0;
    	NRF_PWM0->SEQ[1].ENDDELAY = 0;
    	NRF_PWM0->TASKS_SEQSTART[0] = 1; // Restart sending first 32-bit sequence
    }

    With that, I also got output on P1.00. There is one additional pitfall, though. Are you testing on the DK? If so, P1.00 is routed to the onboard debugger when that is in use. So in order to actually connect it to the pin header instead, change the switch position to the left of the NFC connector to "nRF ONLY". With that I got this working:

    (Here I copy-pasted your function into the blinky sample and built for nrf5340dk_nrf5340_cpuapp.

    Einar

Reply Children
No Data
Related