Skip to content

Instantly share code, notes, and snippets.

@technobly
Created January 8, 2014 08:13
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save technobly/8313449 to your computer and use it in GitHub Desktop.
Save technobly/8313449 to your computer and use it in GitHub Desktop.
SPARK CORE CUSTOM PWM FREQUENCY EXAMPLE Define your own frequency! PWM Glitch issue fixed!!
//-----------------------------------------------
// SPARK CORE CUSTOM PWM FREQUENCY EXAMPLE
//===============================================
// Define your own frequency below!
// PWM Glitch issue fixed, only sets up PWM once,
// ... thereafter sets duty cycle.
// This allows true 0 - 100% PWM.
// Copy this into a new application at:
// https://www.spark.io/build and go nuts!
//-----------------------------------------------
// Technobly / BDub - Jan 8th, 2014
//===============================================
#define PWM_FREQ 1000 // in Hertz (SET YOUR FREQUENCY)
#define ANALOG_PIN A2 // potentiometer connected to analog pin A2
uint16_t TIM_ARR = (uint16_t)(24000000 / PWM_FREQ) - 1; // Don't change! Calc's period.
int val = 0; // variable to store the read ADC value
void setup() {
pinMode(A0, OUTPUT); // sets the pin as output
pinMode(A1, OUTPUT); // sets the pin as output
pinMode(A4, OUTPUT); // sets the pin as output
pinMode(A5, OUTPUT); // sets the pin as output
pinMode(A6, OUTPUT); // sets the pin as output
pinMode(A7, OUTPUT); // sets the pin as output
pinMode(D0, OUTPUT); // sets the pin as output
pinMode(D1, OUTPUT); // sets the pin as output
}
void loop() {
// analogRead values go from 0 to 4095, analogWrite values from 0 to 255
// read the input pin (0-4095) and scale it to 0-255 by dividing by 16.
val = analogRead(ANALOG_PIN) / 16;
// Write newly scaled value to A0, A1, A4, A5, A6, A7, D0 and D1.
analogWrite2(A0, val);
analogWrite2(A1, val);
analogWrite2(A4, val);
analogWrite2(A5, val);
analogWrite2(A6, val);
analogWrite2(A7, val);
analogWrite2(D0, val);
analogWrite2(D1, val);
delay(10); // wait 10 milliseconds
}
// User defined analogWrite() to gain control of PWM initialization
void analogWrite2(uint16_t pin, uint8_t value) {
TIM_OCInitTypeDef TIM_OCInitStructure;
if (pin >= TOTAL_PINS || PIN_MAP[pin].timer_peripheral == NULL) {
return;
}
// SPI safety check
if (SPI.isEnabled() == true && (pin == SCK || pin == MOSI || pin == MISO)) {
return;
}
// I2C safety check
if (Wire.isEnabled() == true && (pin == SCL || pin == SDA)) {
return;
}
// Serial1 safety check
if (Serial1.isEnabled() == true && (pin == RX || pin == TX)) {
return;
}
if (PIN_MAP[pin].pin_mode != OUTPUT && PIN_MAP[pin].pin_mode != AF_OUTPUT_PUSHPULL) {
return;
}
// Don't re-init PWM and cause a glitch if already setup, just update duty cycle and return.
if (PIN_MAP[pin].pin_mode == AF_OUTPUT_PUSHPULL) {
TIM_OCInitStructure.TIM_Pulse = (uint16_t)(value * (TIM_ARR + 1) / 255);
if (PIN_MAP[pin].timer_ch == TIM_Channel_1) {
PIN_MAP[pin].timer_peripheral-> CCR1 = TIM_OCInitStructure.TIM_Pulse;
} else if (PIN_MAP[pin].timer_ch == TIM_Channel_2) {
PIN_MAP[pin].timer_peripheral-> CCR2 = TIM_OCInitStructure.TIM_Pulse;
} else if (PIN_MAP[pin].timer_ch == TIM_Channel_3) {
PIN_MAP[pin].timer_peripheral-> CCR3 = TIM_OCInitStructure.TIM_Pulse;
} else if (PIN_MAP[pin].timer_ch == TIM_Channel_4) {
PIN_MAP[pin].timer_peripheral-> CCR4 = TIM_OCInitStructure.TIM_Pulse;
}
return;
}
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//PWM Frequency : PWM_FREQ (Hz)
uint16_t TIM_Prescaler = (uint16_t)(SystemCoreClock / 24000000) - 1; //TIM Counter clock = 24MHz
// TIM Channel Duty Cycle(%) = (TIM_CCR / TIM_ARR + 1) * 100
uint16_t TIM_CCR = (uint16_t)(value * (TIM_ARR + 1) / 255);
// AFIO clock enable
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
pinMode(pin, AF_OUTPUT_PUSHPULL);
// TIM clock enable
if (PIN_MAP[pin].timer_peripheral == TIM2)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
else if (PIN_MAP[pin].timer_peripheral == TIM3)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
else if (PIN_MAP[pin].timer_peripheral == TIM4)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
// Time base configuration
TIM_TimeBaseStructure.TIM_Period = TIM_ARR;
TIM_TimeBaseStructure.TIM_Prescaler = TIM_Prescaler;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(PIN_MAP[pin].timer_peripheral, & TIM_TimeBaseStructure);
// PWM1 Mode configuration
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = TIM_CCR;
if (PIN_MAP[pin].timer_ch == TIM_Channel_1) {
// PWM1 Mode configuration: Channel1
TIM_OC1Init(PIN_MAP[pin].timer_peripheral, & TIM_OCInitStructure);
TIM_OC1PreloadConfig(PIN_MAP[pin].timer_peripheral, TIM_OCPreload_Enable);
} else if (PIN_MAP[pin].timer_ch == TIM_Channel_2) {
// PWM1 Mode configuration: Channel2
TIM_OC2Init(PIN_MAP[pin].timer_peripheral, & TIM_OCInitStructure);
TIM_OC2PreloadConfig(PIN_MAP[pin].timer_peripheral, TIM_OCPreload_Enable);
} else if (PIN_MAP[pin].timer_ch == TIM_Channel_3) {
// PWM1 Mode configuration: Channel3
TIM_OC3Init(PIN_MAP[pin].timer_peripheral, & TIM_OCInitStructure);
TIM_OC3PreloadConfig(PIN_MAP[pin].timer_peripheral, TIM_OCPreload_Enable);
} else if (PIN_MAP[pin].timer_ch == TIM_Channel_4) {
// PWM1 Mode configuration: Channel4
TIM_OC4Init(PIN_MAP[pin].timer_peripheral, & TIM_OCInitStructure);
TIM_OC4PreloadConfig(PIN_MAP[pin].timer_peripheral, TIM_OCPreload_Enable);
}
TIM_ARRPreloadConfig(PIN_MAP[pin].timer_peripheral, ENABLE);
// TIM enable counter
TIM_Cmd(PIN_MAP[pin].timer_peripheral, ENABLE);
}
@chron0
Copy link

chron0 commented Oct 18, 2014

Thanks a lot, copy/paste -> works!

@Sperryfreak01
Copy link

Is it possible to change the PWM resolution to 10 bits by changing

uint16_t TIM_CCR = (uint16_t)(value * (TIM_ARR + 1) / 255);

to

uint16_t TIM_CCR = (uint16_t)(value * (TIM_ARR + 1) / 1023);

It seems like it would be that easy but when I try it, LED fading, it appears to rollover at 256

@Sperryfreak01
Copy link

Nevermind I figured out how to get a higher resolution than 8 bit. See my fork for the code.
https://gist.github.com/Sperryfreak01/a4282fce7c64f44036ae

@hemanthvasista
Copy link

I tried compiling the above code in https://build.particle.io/build
I got these errors:

  1. "PIN_MAP" was not declared in this scope
    Solution: I added the below line
    STM32_Pin_Info* PIN_MAP = HAL_Pin_Map(); // Pointer required for highest access speed
  2. "RCC_APB2PeriphClockCmd" was not declared in this scope
    I am unable to find which files needs to be included to remove this error

Could anyone of you help me for this?

@kevinfilteau
Copy link

I have a particle photon, but can't manage to make this code works. Here are the errors :

I'm a newbie with this board, and not much experimented with this kind of feature.

Maybe some const are no more available?

servo-frequency-2.cpp: In function 'void loop()':
servo-frequency-2.cpp:37:37: error: expected ';' before ')' token
pinMode(D1, OUTPUT); // sets the pin as output
^

servo-frequency-2.cpp: In function 'void analogWrite2(uint16_t, uint16_t)':
servo-frequency-2.cpp:96:26: error: 'RCC_APB2Periph_AFIO' was not declared in this scope
uint16_t TIM_Prescaler = (uint16_t)(SystemCoreClock / 24000000) - 1; //TIM Counter clock = 24MHz
^

make[1]: *** [../build/target/user/platform-6servo-frequency-2.o] Error 1
make: *** [user] Error 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment