hardware_pwm_test.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /**
  2. * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <stdio.h>
  7. #include "pico/stdlib.h"
  8. #include "pico/test.h"
  9. #include "pico/time.h"
  10. #include "hardware/irq.h"
  11. #include "hardware/resets.h"
  12. #include "hardware/pwm.h"
  13. PICOTEST_MODULE_NAME("PWM", "PWM SDK Test harness");
  14. /* In a struct for future expansion of the interrupt testv */
  15. struct interrupt_state {
  16. int count;
  17. } interrupt_states[NUM_PWM_SLICES] = {0};
  18. void on_pwm_wrap() {
  19. for (int pwm = 0; pwm < NUM_PWM_SLICES; pwm++) {
  20. // See if this pwm, is the one that fired.
  21. if (pwm_get_irq_status_mask() & (1 << pwm)) {
  22. // Clear the interrupt flag that brought us here
  23. pwm_clear_irq(pwm);
  24. interrupt_states[pwm].count++;
  25. }
  26. }
  27. }
  28. int main() {
  29. reset_block(RESETS_RESET_PWM_BITS);
  30. unreset_block_wait(RESETS_RESET_PWM_BITS);
  31. setup_default_uart();
  32. PICOTEST_START();
  33. pwm_config config = pwm_get_default_config();
  34. // Test that config sets works on all PWMs by comparing what we pass in
  35. // via the API with what the registers contains afterwards
  36. pwm_config_set_phase_correct(&config, true);
  37. pwm_config_set_clkdiv(&config, 42.5);
  38. pwm_config_set_clkdiv_mode(&config, PWM_DIV_B_HIGH);
  39. pwm_config_set_output_polarity(&config, false, true);
  40. pwm_config_set_wrap(&config, 0x1234);
  41. PICOTEST_START_SECTION("PWM config init tests");
  42. for (int pwm = 0; pwm < NUM_PWM_SLICES; pwm++) {
  43. pwm_slice_hw_t *slice = &pwm_hw->slice[pwm];
  44. pwm_init(pwm, &config, false);
  45. uint div = (uint)(42.5f * (float)(1 << PWM_CH0_DIV_INT_LSB));
  46. PICOTEST_CHECK_CHANNEL(pwm, slice->top == config.top, "HW top does not match requested config");
  47. //PICOTEST_CHECK_CHANNEL(pwm, slice->ctr == 0x1234, "HW counter does not match config");
  48. PICOTEST_CHECK_CHANNEL(pwm, slice->cc == PWM_CH0_CC_RESET, "HW compares does not match config");
  49. PICOTEST_CHECK_CHANNEL(pwm, slice->div == div, "HW divider does not match config");
  50. PICOTEST_CHECK_CHANNEL(pwm, slice->csr ==
  51. (1 << PWM_CH0_CSR_PH_CORRECT_LSB | 0 << PWM_CH0_CSR_A_INV_LSB | 1 << PWM_CH0_CSR_B_INV_LSB |
  52. PWM_CH0_CSR_DIVMODE_VALUE_LEVEL << PWM_CH0_CSR_DIVMODE_LSB), "HW CSR does not match config");
  53. }
  54. PICOTEST_END_SECTION();
  55. // Need to test the SDK APIs do the right thing
  56. PICOTEST_START_SECTION("PWM SDK API tests");
  57. for (int pwm = 0; pwm < NUM_PWM_SLICES; pwm++) {
  58. pwm_slice_hw_t *slice = &pwm_hw->slice[pwm];
  59. int v = 100 + pwm * 10;
  60. pwm_set_wrap(pwm, v);
  61. PICOTEST_CHECK_CHANNEL(pwm, slice->top == v, "pwm_set_wrap() failed to set register");
  62. pwm_set_both_levels(pwm, v + 1, v);
  63. PICOTEST_CHECK_CHANNEL(pwm, slice->cc == (((v) << PWM_CH0_CC_B_LSB) | ((v + 1) << PWM_CH0_CC_A_LSB)),
  64. "pwm_set_both_levels() failed to set register");
  65. float divider = 100.5;
  66. int i = (int16_t) divider;
  67. int f = (int8_t) ((divider - i) * 16);
  68. pwm_set_clkdiv(pwm, divider);
  69. PICOTEST_CHECK_CHANNEL(pwm, slice->div == (i << 4 | f), "pwm_set_clkdiv() failed to set register");
  70. i++;
  71. pwm_set_clkdiv_int_frac(pwm, i, f);
  72. PICOTEST_CHECK_CHANNEL(pwm, slice->div == (i << 4 | f),
  73. "pwm_set_clkdiv_int_frac() failed to set register");
  74. int c = 1234;
  75. pwm_set_counter(pwm, c);
  76. PICOTEST_CHECK_CHANNEL(pwm, slice->ctr == c, "pwm_set_counter() failed to set register");
  77. int cc = pwm_get_counter(pwm);
  78. PICOTEST_CHECK_CHANNEL(pwm, slice->ctr == cc && cc == c, "pwm_get_counter() failed to get register");
  79. pwm_set_output_polarity(pwm, false, false);
  80. PICOTEST_CHECK_CHANNEL(pwm,
  81. !(slice->csr & PWM_CH0_CSR_A_INV_BITS) && !(slice->csr & PWM_CH0_CSR_B_INV_BITS),
  82. "pwm_set_output_polarity() (F/F)");
  83. pwm_set_output_polarity(pwm, true, false);
  84. PICOTEST_CHECK_CHANNEL(pwm, (slice->csr & PWM_CH0_CSR_A_INV_BITS) && !(slice->csr & PWM_CH0_CSR_B_INV_BITS),
  85. "pwm_set_output_polarity() (T/F)");
  86. pwm_set_output_polarity(pwm, false, true);
  87. PICOTEST_CHECK_CHANNEL(pwm, !(slice->csr & PWM_CH0_CSR_A_INV_BITS) && (slice->csr & PWM_CH0_CSR_B_INV_BITS),
  88. "pwm_set_output_polarity() (F/T)");
  89. pwm_set_output_polarity(pwm, true, true);
  90. PICOTEST_CHECK_CHANNEL(pwm, (slice->csr & PWM_CH0_CSR_A_INV_BITS) && (slice->csr & PWM_CH0_CSR_B_INV_BITS),
  91. "pwm_set_output_polarity() (T/T)");
  92. pwm_set_phase_correct(pwm, true);
  93. PICOTEST_CHECK_CHANNEL(pwm, (slice->csr & PWM_CH0_CSR_PH_CORRECT_BITS), "pwm_set_phase_correct(T)");
  94. pwm_set_phase_correct(pwm, false);
  95. PICOTEST_CHECK_CHANNEL(pwm, !(slice->csr & PWM_CH0_CSR_PH_CORRECT_BITS), "pwm_set_phase_correct(F)");
  96. for (int m = PWM_DIV_FREE_RUNNING; m <= PWM_DIV_B_FALLING; m++) {
  97. pwm_set_clkdiv_mode(pwm, m);
  98. PICOTEST_CHECK_CHANNEL(pwm, ((slice->csr & PWM_CH0_CSR_DIVMODE_BITS) >> PWM_CH0_CSR_DIVMODE_LSB) == m,
  99. "pwm_set_clkdiv_mode");
  100. }
  101. }
  102. PICOTEST_END_SECTION();
  103. PICOTEST_START_SECTION("PWM IRQ tests");
  104. irq_set_exclusive_handler(PWM_IRQ_WRAP, on_pwm_wrap);
  105. irq_set_enabled(PWM_IRQ_WRAP, true);
  106. config = pwm_get_default_config();
  107. // Slow down the interrupt rate a load, don't need it high.
  108. // This give about 40 per second on Picoboard
  109. pwm_config_set_clkdiv(&config, 50);
  110. for (int pwm = 0; pwm < NUM_PWM_SLICES; pwm++) {
  111. pwm_init(pwm, &config, false);
  112. pwm_clear_irq(pwm);
  113. pwm_set_irq_enabled(pwm, true);
  114. }
  115. // Now enable all the PWM at the same time.
  116. pwm_set_mask_enabled(0xff);
  117. sleep_ms(1000);
  118. int err = 0;
  119. for (int p = 0; p < NUM_PWM_SLICES; p++) {
  120. PICOTEST_CHECK_CHANNEL(p, interrupt_states[p].count != 0, "No interrupts detected from PWM %d\n");
  121. }
  122. PICOTEST_END_SECTION();
  123. PICOTEST_END_TEST();
  124. }