diff --git a/Makefile b/Makefile index 33032f0..3bdfee6 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,11 @@ ifeq ($(shell test -d $(name) && echo "ok"),) @false endif -project: .check-name +project: +ifeq ($(strip $(name)), "") + @echo "error: project name must be set, ex: name=" + @false +endif @./scripts/scaffold_project.bash $(name) $(SDK_VERSION) format: .check-name diff --git a/bit_counter/CMakeLists.txt b/bit_counter/CMakeLists.txt new file mode 100644 index 0000000..575c776 --- /dev/null +++ b/bit_counter/CMakeLists.txt @@ -0,0 +1,38 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Pull in Raspberry Pi Pico SDK (must be before project) +include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake) + +project(bit_counter C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(bit_counter main.c ) + +pico_set_program_name(bit_counter "bit_counter") +pico_set_program_version(bit_counter "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(bit_counter 0) +pico_enable_stdio_usb(bit_counter 1) + +# Add the standard library to the build +target_link_libraries(bit_counter + pico_stdlib) + +# Add the standard include files to the build +target_include_directories(bit_counter PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(bit_counter) + diff --git a/bit_counter/main.c b/bit_counter/main.c new file mode 100644 index 0000000..750a01f --- /dev/null +++ b/bit_counter/main.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include + +#define NB_LED_BAR_GPIO 10 + +static const int LED_BAR_GPIO[NB_LED_BAR_GPIO] = {28, 27, 26, 22, 21, 20, 19, 18, 17, 16}; + +typedef int led_state; +enum LED_STATE { OFF, ON }; + +typedef struct led led; +struct led { + int gpio; + led_state state; +}; + +void set_led_state(led *l, int state) { + if (l != NULL) { + l->state = state; + gpio_put(l->gpio, l->state); + } +} + +char* state_into_str(led_state state) { + switch (state) { + case ON: + return "ON"; + case OFF: + return "OFF"; + default: + return "OFF"; + } +} + +void init_led_bar(led leds[]) { + for (int i = 0; i < NB_LED_BAR_GPIO; i++, leds++) { + *leds = (led) { + .gpio = LED_BAR_GPIO[i], .state = OFF + }; + } +} + + +void print_led_bar_state(led leds[]) { + for (int i = 0; i < NB_LED_BAR_GPIO; i++, leds++) { + char *state = state_into_str(leds->state); + char led_state[12]; + sprintf(led_state, "%3s (%d)", state, leds->gpio); + if (i != NB_LED_BAR_GPIO - 1) { + strcat(led_state, " | "); + } + printf(led_state); + } + printf("\n"); +} + +/** + * Convert an integer into a 10 bits array (corresponding to the number of LED). + * + * It loops over the less to the most significant bit and for each bit, masks it with + * the value to find if the value bit is 0 or 1 and then store it in the bits array. + * + * Example: + * - value = 10 <=> 1010, i = 0 + * - left shift one: 1 << i <=> 0001 << 0 = 1 + * - mask the value with the shifted one: 1010 & 0001 = 0000 + * - find the result by right shifting the masked value by i: 0 >> 0 <=> 0000 >> 0 = 0 + * - i++ + */ +int *int_into_bits(int value) { + int *bits = malloc(NB_LED_BAR_GPIO * sizeof(int)); + for (int i = 0; i < NB_LED_BAR_GPIO; i++) { + int mask = 1 << i; + int masked_value = value & mask; + // the first led is the rightmost, so we start feeding the bit array by the end + bits[NB_LED_BAR_GPIO - 1 - i] = masked_value >> i; + } + return bits; +} + +void blink_failed(uint gpio, uint32_t delay_ms) { + for (;;) { + gpio_put(gpio, false); + sleep_ms(delay_ms); + + gpio_put(gpio, true); + sleep_ms(delay_ms); + } +} + +void set_default_led_state(led_state state) { + gpio_put(PICO_DEFAULT_LED_PIN, state == ON); +} + +void run_bit_counter(led leds[], uint nb_bit, uint32_t delay_ms) { + // nothing to do with 0 bit, entering in failed mode. + if (nb_bit <= 0) { + blink_failed(PICO_DEFAULT_LED_PIN, 500); + return; + } + + // healthcheck + set_default_led_state(ON); + + // `nb_bit` can't be greater than the number of leds + if (nb_bit > NB_LED_BAR_GPIO) { + nb_bit = NB_LED_BAR_GPIO; + } + + // compute the maximum value + int const max_value = 2 << nb_bit - 1; + int current_value = 1; + + for (;;) { + if (current_value == max_value) { + current_value = 1; + led *p_leds = leds; + + for (int i = 0; i < NB_LED_BAR_GPIO; i++, p_leds++) { + set_led_state(p_leds, OFF); + } + + set_default_led_state(OFF); + sleep_ms(delay_ms); + set_default_led_state(ON); + + continue; + } + + led *p_leds = leds; + int *bits = int_into_bits(current_value); + + int *p_bits = bits; + for (int i = 0; i < NB_LED_BAR_GPIO; i++, p_leds++, p_bits++) { + set_led_state(p_leds, *p_bits ? ON : OFF); + } + free(bits); + + print_led_bar_state(leds); + current_value++; + + sleep_ms(delay_ms); + } +} + +/* Initialize needed GPIO. */ +void init_gpio(void) { +#ifdef PICO_DEFAULT_LED_PIN + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); +#endif + + for (int i = 0; i < NB_LED_BAR_GPIO; i++) { + gpio_init(LED_BAR_GPIO[i]); + gpio_set_dir(LED_BAR_GPIO[i], GPIO_OUT); + } +} + +/** + * Bit counter program with a LED bar. + * + * Increment a value, convert it in bit and display the value + * on the LED bar (1: led on, 0 led OFF) until it reaches max value. + * + * BA-SIC. But it's fun to see the result. + * + * When the max value is reached, the program restarts. + * + * You can customize the incrementation speed and the number of bit to display + * (max = number of led on the bar available) by changing the `run_bit_counter` + * arguments. + * + * Ex: display only 4 bits (4 leds) with increment speed of 50 ms: + * run_bit_counter(leds, 4, 50); + */ +int main() { + stdio_init_all(); + init_gpio(); + + led leds[NB_LED_BAR_GPIO] = {}; + init_led_bar(leds); + print_led_bar_state(leds); + + run_bit_counter(leds, 11, 50); +} \ No newline at end of file diff --git a/templates/main.c.tpl b/templates/main.c.tpl index 8b848ac..f7ae846 100644 --- a/templates/main.c.tpl +++ b/templates/main.c.tpl @@ -1,4 +1,4 @@ -#include +#include #include int main() @@ -6,7 +6,7 @@ int main() stdio_init_all(); while (true) { - printf(" is running...\n"); + stdio_printf(" is running...\n"); sleep_ms(1000); } } \ No newline at end of file