feature(PWM): PWM Fix
Fixed PWM with a helper function to calculate clock divider and wrap value. Added Comments
This commit is contained in:
parent
f67b58493c
commit
3813bf38f4
|
@ -16,27 +16,16 @@
|
||||||
|
|
||||||
#define PWM_PIN 2
|
#define PWM_PIN 2
|
||||||
#define PWM_FREQ 20
|
#define PWM_FREQ 20
|
||||||
#define PWM_DUTY 0.5
|
#define PWM_DUTY 50
|
||||||
|
|
||||||
#define ADC_PIN 26
|
#define ADC_PIN 26
|
||||||
#define ADC_FREQ 25
|
#define ADC_FREQ 25
|
||||||
|
|
||||||
void setup () {
|
/**
|
||||||
gpio_set_function(PWM_PIN, GPIO_FUNC_PWM);
|
* Callback function for repeating timer to read ADC value
|
||||||
uint slice_num = pwm_gpio_to_slice_num(PWM_PIN);
|
* @param t The timer that triggered the callback
|
||||||
|
* @return True to keep the timer running, false to stop it
|
||||||
pwm_set_wrap(slice_num, 100);
|
*/
|
||||||
// Setup PWM with 20 Hz frequency and 50% duty cycle
|
|
||||||
pwm_set_chan_level(slice_num, PWM_CHAN_A, PWM_DUTY * 100);
|
|
||||||
pwm_set_enabled(slice_num, true);
|
|
||||||
pwm_set_clkdiv(slice_num, 1);
|
|
||||||
|
|
||||||
// Set up ADC
|
|
||||||
adc_init();
|
|
||||||
adc_gpio_init(ADC_PIN);
|
|
||||||
adc_select_input(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool repeating_timer_callback (struct repeating_timer *t) {
|
bool repeating_timer_callback (struct repeating_timer *t) {
|
||||||
// Read ADC value
|
// Read ADC value
|
||||||
uint16_t result = adc_read();
|
uint16_t result = adc_read();
|
||||||
|
@ -52,18 +41,77 @@ bool repeating_timer_callback (struct repeating_timer *t) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main () {
|
/**
|
||||||
stdio_init_all();
|
* Helper function to calculate the clock divider and wrap value for PWM
|
||||||
setup();
|
* Based on: https://www.i-programmer.info/programming/hardware/14849-the-pico-in-c-basic-pwm.html
|
||||||
|
*
|
||||||
|
* RP2040 clock is 125 MHz, PWM Counter is 16-bit
|
||||||
|
* Clock divider is 16-bit, with 12-bit integer and 4-bit fraction
|
||||||
|
* @param slice_num PWM slice number
|
||||||
|
* @param channel PWM channel
|
||||||
|
* @param frequency PWM frequency
|
||||||
|
* @param duty_cycle PWM duty cycle
|
||||||
|
* @return PWM wrap value
|
||||||
|
*/
|
||||||
|
uint32_t pwm_set_freq_duty (uint slice_num,
|
||||||
|
uint channel, uint32_t frequency, int duty_cycle) {
|
||||||
|
uint32_t clock = 125000000;
|
||||||
|
|
||||||
struct repeating_timer timer;
|
// divider = Ceil(16 * clock / 65536 * frequency) + remainder
|
||||||
|
// = Ceil(clock / frequency / 4096) + remainder
|
||||||
|
uint32_t divider16 = clock / frequency / 4096 +
|
||||||
|
(clock % (frequency * 4096) !=
|
||||||
|
0); // Round up if less than 1
|
||||||
|
|
||||||
|
// If divider is less than 16, set it to 16 (16-bit counter)
|
||||||
|
if (divider16 / 16 == 0)
|
||||||
|
{
|
||||||
|
divider16 = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap value is 16 bits, so max value is 65535 (2^16 - 1)
|
||||||
|
uint32_t wrap = clock * 16 / divider16 / frequency - 1;
|
||||||
|
|
||||||
|
// Set clock divider and wrap value
|
||||||
|
pwm_set_clkdiv_int_frac(slice_num, divider16 / 16,
|
||||||
|
divider16 & 0xF);
|
||||||
|
pwm_set_wrap(slice_num, wrap);
|
||||||
|
|
||||||
|
// Level = wrap * duty_cycle(as fraction)
|
||||||
|
// = wrap * duty_cycle / 100
|
||||||
|
pwm_set_chan_level(slice_num, channel, wrap * duty_cycle / 100);
|
||||||
|
return wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup Function for PWM and ADC
|
||||||
|
* @param timer Repeating timer for ADC
|
||||||
|
*/
|
||||||
|
void setup (struct repeating_timer *timer) {
|
||||||
|
// PWM setup
|
||||||
|
gpio_set_function(PWM_PIN, GPIO_FUNC_PWM);
|
||||||
|
uint slice_num = pwm_gpio_to_slice_num(PWM_PIN);
|
||||||
|
uint channel = pwm_gpio_to_channel(PWM_PIN);
|
||||||
|
pwm_set_freq_duty(slice_num, channel, PWM_FREQ, PWM_DUTY);
|
||||||
|
pwm_set_enabled(slice_num, true);
|
||||||
|
|
||||||
|
// ADC setup
|
||||||
|
adc_init();
|
||||||
|
adc_gpio_init(ADC_PIN);
|
||||||
|
adc_select_input(0);
|
||||||
|
|
||||||
// Setup timer interrupt
|
// Setup timer interrupt
|
||||||
add_repeating_timer_ms(ADC_FREQ,
|
add_repeating_timer_ms(ADC_FREQ,
|
||||||
repeating_timer_callback,
|
repeating_timer_callback,
|
||||||
NULL,
|
NULL,
|
||||||
&timer
|
timer
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
stdio_init_all();
|
||||||
|
struct repeating_timer timer;
|
||||||
|
setup(&timer);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue