main.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #include <stdio.h>
  2. #include "hardware/gpio.h"
  3. #include "pico/stdlib.h"
  4. #include "tinykernel/kernel.hpp"
  5. #include "pico/multicore.h"
  6. // Atomic printf helper: stdio is shared, so wrap each call with the kernel lock.
  7. #define P(...) \
  8. do { \
  9. bool _lk = tk::lock(); \
  10. printf("[C%u] ", (unsigned)get_core_num()); \
  11. printf(__VA_ARGS__); \
  12. tk::unlock(_lk); \
  13. } while (0)
  14. // ---------------------------------------------------------------------------
  15. // Static task (registered at link time via TK_TASK): toggles the onboard LED.
  16. void task_led(void* arg) {
  17. (void)arg;
  18. for (;;) {
  19. gpio_put(25, !gpio_get(25));
  20. tk::sleep_ms(200);
  21. }
  22. }
  23. TK_TASK(task_led, tk::PRIO_NORMAL)
  24. // ---------------------------------------------------------------------------
  25. // Static task: FPU self-check. Runs the same deterministic float/double sequence
  26. // twice; any corruption of FPU state across context switches shows up as a
  27. // mismatch or a drifting result.
  28. static float fpu_run_f(float v) {
  29. for (int i = 0; i < 10000; ++i) v = v * 1.000001f + 0.5f;
  30. return v;
  31. }
  32. static double fpu_run_d(double v) {
  33. for (long i = 0; i < 10000; ++i) v = v * 1.0000000002 + 0.5;
  34. return v;
  35. }
  36. void task_fpu(void* arg) {
  37. (void)arg;
  38. for (;;) {
  39. float fa = fpu_run_f(1.5f);
  40. float fb = fpu_run_f(1.5f);
  41. double da = fpu_run_d(2.5);
  42. double db = fpu_run_d(2.5);
  43. if (fa != fb || da != db) {
  44. P("FPU FAIL f: %8.6f vs %8.6f d: %.9f vs %.9f\n", (double)fa, (double)fb, da, db);
  45. } else {
  46. P("FPU ok f: %8.6f d: %.9f\n", (double)fa, da);
  47. }
  48. tk::sleep_ms(300);
  49. }
  50. }
  51. TK_TASK(task_fpu, tk::PRIO_NORMAL)
  52. // ---------------------------------------------------------------------------
  53. // Dynamic task (higher priority): busy-spins for a few ms to demonstrate that it
  54. // preempts the lower-priority tasks immediately.
  55. static void task_hi(void* arg) {
  56. (void)arg;
  57. for (;;) {
  58. volatile uint32_t n = 0;
  59. while (n < 500000u) ++n;
  60. P("HI prio=%u busy-spin done, now=%llu ms\n", (unsigned)tk::PRIO_HIGH, (unsigned long long)tk::now_ms());
  61. tk::sleep_ms(700);
  62. }
  63. }
  64. // ---------------------------------------------------------------------------
  65. // Dynamic task: prints a few times and then exits.
  66. static void task_dying(void* arg) {
  67. (void)arg;
  68. for (int i = 1; i <= 3; ++i) {
  69. P("DYING %d (now=%llu ms)\n", i, (unsigned long long)tk::now_ms());
  70. tk::sleep_ms(250);
  71. }
  72. P("DYING calling tk::exit()\n");
  73. tk::exit(0);
  74. }
  75. // ---------------------------------------------------------------------------
  76. // Dynamic task: plain periodic printer at normal priority.
  77. static void task_print(void* arg) {
  78. (void)arg;
  79. uint32_t count = 0;
  80. for (;;) {
  81. P("A #%lu now=%llu ms\n", (unsigned long)count++, (unsigned long long)tk::now_ms());
  82. tk::sleep_ms(150);
  83. }
  84. }
  85. int main() {
  86. stdio_init_all();
  87. gpio_init(25);
  88. gpio_set_dir(25, GPIO_OUT);
  89. printf("tinykernel: registering dynamic tasks...\n");
  90. auto h_hi = tk::create(task_hi, nullptr, tk::PRIO_HIGH);
  91. auto h_dy = tk::create(task_dying, nullptr, tk::PRIO_LOW);
  92. auto h_pr = tk::create(task_print, nullptr, tk::PRIO_NORMAL);
  93. if (h_hi.slot == 0xFF || h_dy.slot == 0xFF || h_pr.slot == 0xFF) {
  94. printf("tinykernel: task creation FAILED\n");
  95. for (;;) {
  96. }
  97. }
  98. printf("tinykernel: starting scheduler (preemptive, core M33 only)\n");
  99. tk::start(); // never returns
  100. }