Author Topic: PWM trouble  (Read 100 times)

Michael Anderson

  • RFduino Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
PWM trouble
« on: December 01, 2017, 12:06:01 PM »
I am trying to modify the analogWrite() PWM code for Timer2 into a function that will send 2 types of PWM pulses over a pin.
To test out the framework I am only trying to send one pulse type up to 32 times.
I use the same clock initialization code for Timer2 inside analogWrite() along with the PWM pin setup for PPI_to_GPIOTE on cc[0] events.
 
My Goal is to have a PWM width of ~1.2 uS (1 clock tick is ~.125 uS)
with the ability to set the duty cycle to 2 options for each pulse: ~30% and ~50%.

my attempt to do this is using the timer2 interrupt ISR to set the PWM cc[0] event to the desired duty cycle value. 
I also enable cc[1] to handle setting the duty cycle value after a pulse starts,cc[2] to resetting the pwm event to zero after the cc[0] event has occured, and cc[3] to resetting the clock after ~1.2uS worth of cycles so this can all repeat.

I must be overlooking something because its not stopping after 32 pulse and also if I try to set the cc[1-3] to larger values (since 1.2uS is probably to fast for the ISR events to handle) the results are messy.

any hints or suggestions on a better way to perform this would help so much!

 
Code: [Select]
/****************************
 * main.c sketch code
 * Arduino Version 1.8.4
 * Simblee Library 1.1.4
 *
 *****************************/
#include <time.h>
#include <SPI.h>
#include <Wire.h>


// GPIO Defines
const int pin_11 = 11;     // output pin for debugging

void setup() {
  // put your setup code here, to run once:
  pinMode(pin_11,OUTPUT);
 
  Serial.begin(9600);
  Serial.println("Setup beginning");

}

void loop() {
  //send one 32-bit string to LED
  RGBWrite(pin_11,0xFFFFFFF0 , 1); //turn LED1 completely on
  while(1){};

}


/************************************
*************************************
**** CODE BELOW IS PLACED INSIDE ****
**** wiring_analog.c found in    ****
**** Simblee Library 1.1.4       ****
*************************************
*************************************/

//global variables
int RGBW_enabled = 0, RGBW_pin = 0;
 
/** Timer 2 peripheral interrupt handler.
@NOTE: before use comment out old TIMER2_interrupt(void)
 */
static void TIMER2_Interrupt(void)
{
if(RGBW_enabled == 1){
// cc[0] event is set to PWM toggling

//cc[1] event - prep bit pulses baud rate
if(NRF_TIMER2->EVENTS_COMPARE[1] != 0){
NRF_TIMER2->EVENTS_COMPARE[1] = 0;
NRF_TIMER2->CC[0] = 3;
}

//cc[2] event - prep next pulse wave
if(NRF_TIMER2->EVENTS_COMPARE[2] != 0){
NRF_TIMER2->EVENTS_COMPARE[2] = 0;
NRF_TIMER2->CC[0] = 0;

}

//cc[3] event - reset counter and increment bits sent
if(NRF_TIMER2->EVENTS_COMPARE[3] != 0){
NRF_TIMER2->EVENTS_COMPARE[3] = 0;

//decrement our counter of bits sent
if(RGBW_counter>-1){
NRF_TIMER2->TASKS_CLEAR = 1; //reset clock to zero
RGBW_counter--;
}
else{ //turn off PPI and Timer when all done
RGBW_enabled = 0; //finished writing
NRF_TIMER2->TASKS_STOP = 1; //stop timer
digitalWrite(RGBW_pin, LOW);
}
}
}
}


/*
 * Send a RGBW write string on this pin
 */
 void RGBWrite(uint32_t ulPin, uint32_t ulValue, uint32_t leds) {
int RGBW_counter = 31; //count downwards to zero
int RGBW_value = ulValue;
int RGBW_leds = leds;
RGBW_pin = ulPin; //global int
RGBW_enabled = 1; //global int
 
//Case if pin is already setup for PWM
if (Timer2_Compare_Unit_Occupied_by_Pin[0] == ulPin)
{
return; //fail since pin is busy
}
else
{
// Use Timer2 exclusively for this since our target is 800Khz or 400KHz (test both)
if (!SimbleeGZLL_used && Timer2_Compare_Unit_Occupied_by_Pin[0] == 255)
{
// Timer2 is not used: need to initialize it

// Configure ulPin as output
digitalWrite(ulPin, LOW);
pinMode(ulPin, OUTPUT);

if (ulValue > 0)
{
  // Configure GPIOTE channel "gpiote_channel" to toggle the PWM pin state
  // Note that we can only connect one GPIOTE task to an output pin
  nrf_gpiote_task_config(3, ulPin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);
}
GPIOTE_Channels_Occupied[ulPin] = 3;

//Setupt Timer2 to run off 16MHZ clock
NRF_TIMER2->TASKS_STOP = 1;
NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;
NRF_TIMER2->PRESCALER = 0; // Source clock frequency is divided by 2^6 = 64 /////////////////////////////////////////
NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;  ////////////////////////////
// Clears the timer, sets it to 0
NRF_TIMER2->TASKS_CLEAR = 1;

NRF_TIMER2->CC[0] = 3;  //PPI_PWM - Toggles the PWM pin on every compare event using PPI
NRF_TIMER2->CC[1] = 1;  //interrupt event 1 - Sets the cc[0] pulse baud length depending on bit to send
NRF_TIMER2->CC[2] = 8;  //interrupt event 2 - Sets the cc[0] to zero for next pulse start
NRF_TIMER2->CC[3] = 10; //interrupt event 3 - This resets the entire counter for next pulse

NRF_TIMER2->EVENTS_COMPARE[0] = 0;
NRF_TIMER2->EVENTS_COMPARE[1] = 0;
NRF_TIMER2->EVENTS_COMPARE[2] = 0;
NRF_TIMER2->EVENTS_COMPARE[3] = 0;

// Interrupt setup enable cc[1-3] compare events to trigger ISR
NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos);
NRF_TIMER2->INTENSET |= (TIMER_INTENSET_COMPARE2_Enabled << TIMER_INTENSET_COMPARE2_Pos);
NRF_TIMER2->INTENSET |= (TIMER_INTENSET_COMPARE3_Enabled << TIMER_INTENSET_COMPARE3_Pos);
dynamic_attachInterrupt(TIMER2_IRQn, TIMER2_Interrupt);

// Start clock
NRF_TIMER2->TASKS_START = 1;
turn_On_PPI_to_GPIO_for_PWM(ulPin, 3, NRF_TIMER2, 0);

//set pin to active in PWM mode, should lock it out from analogwrite() calls
Timer2_Compare_Unit_Occupied_by_Pin[0] = ulPin;
Pin_Occupied_for_PWM[ulPin] = 1;
}
else
{
// Simblee GZLL is locking up Timer2, we need to recode this or not use GZLL
}
}
}

If it helps the end Goal is to talk to one of these RGBW's  http://www.szledcolor.com/download/SK6812RGBW.pdf  see page 5/15 for pwm info.
This RGBW has a built in arduino library support package but the only nordic chip support is the nrf52 series that is not compatable with the nrf51 series.
« Last Edit: December 01, 2017, 02:47:04 PM by Michael Anderson »

 

anything