/** * To configure a PWM signal at 20 Hz with a 50% duty cycle * on GP2 and feed it into an ADC at GP26 while * sampling the ADC every 25 ms, * you must use the Raspberry Pi Pico and its Pico C SDK. * * You will need to use a jumper wire to connect GP2 to GP26. * You may use a timer interrupt. */ #include #include "pico/stdlib.h" #include "hardware/pwm.h" #include "hardware/adc.h" #define PWM_PIN 2 #define PWM_FREQ 20 #define PWM_DUTY 50 #define ADC_PIN 26 #define ADC_FREQ 25 /** * Callback function for repeating timer to read ADC value * @param t The timer that triggered the callback * @return True to keep the timer running, false to stop it */ bool repeating_timer_callback (struct repeating_timer *t) { // Read ADC value uint16_t result = adc_read(); uint64_t time = time_us_64(); printf("%02d:%02d:%02d:%03d -> ADC value: %d\n", (int) (time / 3600000000), (int) (time / 60000000) % 60, (int) (time / 1000000) % 60, (int) (time / 1000) % 1000, result ); return true; } /** * Helper function to calculate the clock divider and wrap value for PWM * 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; // 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 add_repeating_timer_ms(ADC_FREQ, repeating_timer_callback, NULL, timer ); } int main () { stdio_init_all(); struct repeating_timer timer; setup(&timer); while (true) { tight_loop_contents(); } }