-
Notifications
You must be signed in to change notification settings - Fork 998
Various tweaks to pio_blink example #737
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,78 +11,103 @@ | |
| #include "hardware/clocks.h" | ||
| #include "blink.pio.h" | ||
|
|
||
| /** | ||
| * This example demonstrates using PIO to flash four LEDs at different frequencies. | ||
| * On RP2040 and RP2350A those GPIOs are all in the same "PIO range" of 0 - 31 (so a single PIO is used). | ||
| * On RP2350B the first two GPIOs are in the "lower PIO range" of 0 - 31 and the | ||
| * next two LEDs are in the "higher PIO range" of 16 - 47 (so two PIOs are used). | ||
| */ | ||
|
|
||
| void blink_pin_forever(PIO pio, uint sm, uint offset, uint pin, uint freq); | ||
|
|
||
| // by default flash leds on gpios 3-4 | ||
| // By default flash LEDs on GPIOs 3 and 4 | ||
| #ifndef PIO_BLINK_LED1_GPIO | ||
| #define PIO_BLINK_LED1_GPIO 3 | ||
| #define PIO_BLINK_LED2_GPIO (PIO_BLINK_LED1_GPIO + 1) | ||
| #endif | ||
|
|
||
| // and flash leds on gpios 5-6 | ||
| // or if the device supports more than 32 gpios, flash leds on 32-33 | ||
| // and also flash LEDs on GPIOs 5 and 6 | ||
| // Or if the device has more than 32 gpios, also flash LEDs on GPIOs 32 and 33 | ||
| #ifndef PIO_BLINK_LED3_GPIO | ||
| #if NUM_BANK0_GPIOS <= 32 | ||
| #define PIO_BLINK_LED3_GPIO 5 | ||
| #else | ||
| #define PIO_BLINK_LED3_GPIO 32 | ||
| #endif | ||
| #define PIO_BLINK_LED4_GPIO (PIO_BLINK_LED3_GPIO + 1) | ||
| #endif | ||
|
|
||
| #define PIO_BLINK_LED1_FREQUENCY 4 | ||
| #define PIO_BLINK_LED2_FREQUENCY 3 | ||
| #define PIO_BLINK_LED3_FREQUENCY 2 | ||
| #define PIO_BLINK_LED4_FREQUENCY 1 | ||
|
|
||
| int main() { | ||
| setup_default_uart(); | ||
|
|
||
| assert(PIO_BLINK_LED1_GPIO < 31); | ||
| assert(PIO_BLINK_LED3_GPIO < 31 || PIO_BLINK_LED3_GPIO >= 32); | ||
|
|
||
| // LED1 and LED2 are both expected to be in the "lower" range of PIO-addressable GPIOs | ||
| assert(PIO_BLINK_LED2_GPIO == PIO_BLINK_LED1_GPIO + 1); | ||
| assert((PIO_BLINK_LED1_GPIO < 32) && (PIO_BLINK_LED2_GPIO < 32)); | ||
| // check LED3 and LED4 are both in the same range of PIO-addressable GPIOs | ||
| assert(PIO_BLINK_LED4_GPIO == PIO_BLINK_LED3_GPIO + 1); | ||
| assert(((PIO_BLINK_LED3_GPIO < 32) && (PIO_BLINK_LED4_GPIO < 32)) || ((PIO_BLINK_LED3_GPIO >= 16) && (PIO_BLINK_LED3_GPIO < 48) && (PIO_BLINK_LED4_GPIO >= 16) && (PIO_BLINK_LED4_GPIO < 48))); | ||
|
|
||
| // LED1 and LED2 are both controlled by the program loaded into pio[0] at offset[0] | ||
| // LED3 and LED4 are both controlled by the program loaded into pio[1] at offset[1] (which might be the same as pio[0] and offset[0] if LED3 and LED4 are both on GPIOs < 32) | ||
| // LED1 is controlled by sm[0] | ||
| // LED2 is controlled by sm[1] | ||
| // LED3 is controlled by sm[2] | ||
| // LED4 is controlled by sm[3] | ||
| PIO pio[2]; | ||
| uint sm[2]; | ||
| uint sm[4]; | ||
| uint offset[2]; | ||
|
|
||
| // Find a free pio and state machine and add the program | ||
| // Find a free PIO and state machine and add the program | ||
| bool rc = pio_claim_free_sm_and_add_program_for_gpio_range(&blink_program, &pio[0], &sm[0], &offset[0], PIO_BLINK_LED1_GPIO, 2, true); | ||
| hard_assert(rc); | ||
| printf("Loaded program at %u on pio %u\n", offset[0], PIO_NUM(pio[0])); | ||
|
|
||
| // Start led1 flashing | ||
| blink_pin_forever(pio[0], sm[0], offset[0], PIO_BLINK_LED1_GPIO, 4); | ||
| // Start LED1 flashing | ||
| blink_pin_forever(pio[0], sm[0], offset[0], PIO_BLINK_LED1_GPIO, PIO_BLINK_LED1_FREQUENCY); | ||
|
|
||
| // Claim the next state machine and start led2 flashing | ||
| pio_sm_claim(pio[0], sm[0] + 1); | ||
| blink_pin_forever(pio[0], sm[0] + 1, offset[0], PIO_BLINK_LED1_GPIO + 1, 3); | ||
| // Claim the next unused state machine and start LED2 flashing | ||
| sm[1] = pio_claim_unused_sm(pio[0], true); | ||
| blink_pin_forever(pio[0], sm[1], offset[0], PIO_BLINK_LED2_GPIO, PIO_BLINK_LED2_FREQUENCY); | ||
|
|
||
| if (PIO_BLINK_LED3_GPIO >= 32) { | ||
| // Find a free pio and state machine and add the program | ||
| rc = pio_claim_free_sm_and_add_program_for_gpio_range(&blink_program, &pio[1], &sm[1], &offset[1], PIO_BLINK_LED3_GPIO, 2, true); | ||
| if ((PIO_BLINK_LED3_GPIO >= 32) || (PIO_BLINK_LED4_GPIO >= 32)) { | ||
| // Find a free PIO and state machine and add the program | ||
| rc = pio_claim_free_sm_and_add_program_for_gpio_range(&blink_program, &pio[1], &sm[2], &offset[1], PIO_BLINK_LED3_GPIO, 2, true); | ||
| printf("Loaded program at %u on pio %u\n", offset[1], PIO_NUM(pio[1])); | ||
| } else { | ||
| // no need to load the program again | ||
| rc = true; | ||
| pio[1] = pio[0]; | ||
| sm[1] = sm[0] + 2; | ||
| offset[1] = offset[0]; | ||
| pio_sm_claim(pio[1], sm[1]); | ||
| sm[2] = pio_claim_unused_sm(pio[1], true); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should have a pio_claim_free_sm_and_add_for_gpio_range function
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds like a @kilograham question to me! 😆
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or we should make the existing function clever enough to know not to add the same program to the same PIO twice.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Don't know if we can do that with the current API, as I think the PIO instruction memory is write-only?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might be able to stash an array of pio_program_t structures. Worth seeing if it makes the API better. |
||
| } | ||
| hard_assert(rc); | ||
|
|
||
| // Start led3 flashing | ||
| blink_pin_forever(pio[1], sm[1], offset[1], PIO_BLINK_LED3_GPIO, 2); | ||
| // Start LED3 flashing | ||
| blink_pin_forever(pio[1], sm[2], offset[1], PIO_BLINK_LED3_GPIO, PIO_BLINK_LED3_FREQUENCY); | ||
|
|
||
| // Claim the next unused state machine and start LED4 flashing | ||
| sm[3] = pio_claim_unused_sm(pio[1], true); | ||
| blink_pin_forever(pio[1], sm[3], offset[1], PIO_BLINK_LED4_GPIO, PIO_BLINK_LED4_FREQUENCY); | ||
|
|
||
| // Claim the next state machine and start led4 flashing | ||
| pio_sm_claim(pio[1], sm[1] + 1); | ||
| blink_pin_forever(pio[1], sm[1] + 1, offset[1], PIO_BLINK_LED3_GPIO + 1, 1); | ||
| printf("All LEDs should be flashing\n"); | ||
|
|
||
| // free up pio resources | ||
| pio_sm_unclaim(pio[1], sm[1] + 1); | ||
| if (PIO_BLINK_LED3_GPIO >= 32) { | ||
| pio_remove_program_and_unclaim_sm(&blink_program, pio[1], sm[1], offset[1]); | ||
| // free up PIO resources | ||
| pio_sm_unclaim(pio[1], sm[3]); | ||
| if ((PIO_BLINK_LED3_GPIO >= 32) || (PIO_BLINK_LED4_GPIO >= 32)) { | ||
| pio_remove_program_and_unclaim_sm(&blink_program, pio[1], sm[2], offset[1]); | ||
| } else { | ||
| pio_sm_unclaim(pio[1], sm[1]); | ||
| pio_sm_unclaim(pio[1], sm[2]); | ||
| } | ||
| pio_sm_unclaim(pio[0], sm[0] + 1); | ||
| pio_sm_unclaim(pio[0], sm[1]); | ||
| pio_remove_program_and_unclaim_sm(&blink_program, pio[0], sm[0], offset[0]); | ||
|
|
||
| // the program exits but the pio keeps running! | ||
| printf("All leds should be flashing\n"); | ||
| // the program exits but the PIO keeps running! | ||
| printf("All LEDs should continue to flash\n"); | ||
| } | ||
|
|
||
| void blink_pin_forever(PIO pio, uint sm, uint offset, uint pin, uint freq) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arguably, these asserts should be unnecessary - the code should be able to work whatever value is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it depends on the focus of the example - is it showing "here's how you flash two GPIOs in one PIO-range and two GPIOs in a different range" (which I think was the original intention?), or is it showing "here's totally generic (but more complicated) code for flashing any four GPIOs in any combination" ?
Perhaps I ought to add a comment highlighting the intention of the example? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.