
// ****************************************************************************
//
//                                 Main code
//
// ****************************************************************************
// This example drives a PWM output at a range of duty cycles, and uses
// another PWM slice in input mode to measure the duty cycle. You'll need to
// connect these two pins with a jumper wire:

/*
Debug output
------------
PWM duty cycle measurement example
Output duty cycle = 0.0%, measured input duty cycle = 0.0%
Output duty cycle = 10.0%, measured input duty cycle = 10.0%
Output duty cycle = 50.0%, measured input duty cycle = 50.0%
Output duty cycle = 90.0%, measured input duty cycle = 89.9%
Output duty cycle = 100.0%, measured input duty cycle = 100.0%
*/

#include "include.h"

const uint OUTPUT_PIN = 2;
const uint MEASURE_PIN = 5;

float measure_duty_cycle(uint gpio)
{
	// Only the PWM B pins can be used as inputs.
	assert(pwm_gpio_to_channel(gpio) == PWM_CHAN_B);
	uint slice_num = pwm_gpio_to_slice_num(gpio);

	// Count once for every 100 cycles the PWM B input is high
	pwm_config cfg = pwm_get_default_config();
	pwm_config_set_clkdiv_mode(&cfg, PWM_DIV_B_HIGH);
	pwm_config_set_clkdiv(&cfg, 100);
	pwm_init(slice_num, &cfg, false);
	gpio_set_function(gpio, GPIO_FUNC_PWM);

	pwm_set_enabled(slice_num, true);
	sleep_ms(10);
	pwm_set_enabled(slice_num, false);
	float counting_rate = clock_get_hz(clk_sys) / 100;
	float max_possible_count = counting_rate * 0.01;
	return pwm_get_counter(slice_num) / max_possible_count;
}

const float test_duty_cycles[] =
{
	0.f,
	0.1f,
	0.5f,
	0.9f,
	1.f
};

int main()
{
	stdio_init_all();

	// wait to connect terminal
	int c;
	do {
		printf("Connect GPIO%d with GPIO%d and press spacebar to start...\n", OUTPUT_PIN, MEASURE_PIN);
		c = getchar();
	} while (c != ' ');

	printf("\nPWM duty cycle measurement example\n");

	// Configure PWM slice and set it running
	const uint count_top = 1000;
	pwm_config cfg = pwm_get_default_config();
	pwm_config_set_wrap(&cfg, count_top);
	pwm_init(pwm_gpio_to_slice_num(OUTPUT_PIN), &cfg, true);

	// Note we aren't touching the other pin yet -- PWM pins are outputs by
	// default, but change to inputs once the divider mode is changed from
	// free-running. It's not wise to connect two outputs directly together!
	gpio_set_function(OUTPUT_PIN, GPIO_FUNC_PWM);

	// For each of our test duty cycles, drive the output pin at that level,
	// and read back the actual output duty cycle using the other pin. The two
	// values should be very close!
	for (int i = 0; i < count_of(test_duty_cycles); ++i)
	{
		float output_duty_cycle = test_duty_cycles[i];
		pwm_set_gpio_level(OUTPUT_PIN, output_duty_cycle * (count_top + 1));
		float measured_duty_cycle = measure_duty_cycle(MEASURE_PIN);
		printf("Output duty cycle = %.1f%%, measured input duty cycle = %.1f%%\n",
			output_duty_cycle * 100.f, measured_duty_cycle * 100.f);
	}

	// Wait for uart output to finish
	sleep_ms(100);

	return 0;
}
