|
35 | 35 | #include "shared-bindings/pulseio/PWMOut.h"
|
36 | 36 | #include "supervisor/shared/translate.h"
|
37 | 37 |
|
| 38 | +#include "stm32f4xx_hal.h" |
| 39 | +#include "common-hal/microcontroller/Pin.h" |
| 40 | +#include "tick.h" |
| 41 | + |
| 42 | +// A single timer is shared amongst all PulseOut objects under the assumption that |
| 43 | +// the code is single threaded. |
| 44 | +STATIC uint8_t refcount = 0; |
| 45 | + |
| 46 | +STATIC uint16_t *pulse_array = NULL; |
| 47 | +STATIC volatile uint16_t pulse_array_index = 0; |
| 48 | +STATIC uint16_t pulse_array_length; |
| 49 | + |
| 50 | +//Timer is shared, must be accessible by interrupt |
| 51 | +STATIC TIM_HandleTypeDef t7_handle; |
| 52 | +pulseio_pulseout_obj_t *curr_pulseout = NULL; |
| 53 | + |
| 54 | +STATIC void turn_on(pulseio_pulseout_obj_t *pulseout) { |
| 55 | + // Turn on PWM |
| 56 | + HAL_TIM_PWM_Start(&(pulseout->pwmout->handle), pulseout->pwmout->channel); |
| 57 | +} |
| 58 | + |
| 59 | +STATIC void turn_off(pulseio_pulseout_obj_t *pulseout) { |
| 60 | + // Turn off PWM |
| 61 | + HAL_TIM_PWM_Stop(&(pulseout->pwmout->handle), pulseout->pwmout->channel); |
| 62 | + // Make sure pin is low. |
| 63 | + HAL_GPIO_WritePin(pin_port(pulseout->pwmout->tim->pin->port), |
| 64 | + pin_mask(pulseout->pwmout->tim->pin->number), 0); |
| 65 | +} |
| 66 | + |
| 67 | +STATIC void start_timer(void) { |
| 68 | + // Set the new period |
| 69 | + t7_handle.Init.Period = pulse_array[pulse_array_index] - 1; |
| 70 | + HAL_TIM_Base_Init(&t7_handle); |
| 71 | + |
| 72 | + // TIM7 has limited HAL support, set registers manually |
| 73 | + t7_handle.Instance->SR = 0; // Prevent the SR from triggering an interrupt |
| 74 | + t7_handle.Instance->CR1 |= TIM_CR1_CEN; // Resume timer |
| 75 | + t7_handle.Instance->CR1 |= TIM_CR1_URS; // Disable non-overflow interrupts |
| 76 | + __HAL_TIM_ENABLE_IT(&t7_handle, TIM_IT_UPDATE); |
| 77 | + |
| 78 | +} |
| 79 | + |
| 80 | +STATIC void pulseout_event_handler(void) { |
| 81 | + if (curr_pulseout->pwmout == NULL) { |
| 82 | + return; //invalid interrupt |
| 83 | + } |
| 84 | + |
| 85 | + HAL_GPIO_WritePin(pin_port(2),pin_mask(6), 1); |
| 86 | + HAL_GPIO_WritePin(pin_port(2),pin_mask(6), 0); |
| 87 | + |
| 88 | + pulse_array_index++; |
| 89 | + |
| 90 | + // No more pulses. Turn off output and don't restart. |
| 91 | + if (pulse_array_index >= pulse_array_length) { |
| 92 | + turn_off(curr_pulseout); |
| 93 | + return; |
| 94 | + } |
| 95 | + |
| 96 | + // Alternate on and off, starting with on. |
| 97 | + if (pulse_array_index % 2 == 0) { |
| 98 | + turn_on(curr_pulseout); |
| 99 | + } else { |
| 100 | + turn_off(curr_pulseout); |
| 101 | + } |
| 102 | + |
| 103 | + // Count up to the next given value. |
| 104 | + start_timer(); |
| 105 | +} |
38 | 106 |
|
39 | 107 | void pulseout_reset() {
|
| 108 | + __HAL_RCC_TIM7_CLK_DISABLE(); |
| 109 | + refcount = 0; |
40 | 110 | }
|
41 | 111 |
|
42 | 112 | void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
|
43 | 113 | const pulseio_pwmout_obj_t* carrier) {
|
44 |
| - mp_raise_NotImplementedError(translate("PulseOut not yet supported")); |
| 114 | + // Add to active PulseOuts |
| 115 | + refcount++; |
| 116 | + |
| 117 | + // Calculate a 1 ms period |
| 118 | + uint32_t source, clk_div; |
| 119 | + source = HAL_RCC_GetPCLK1Freq(); // TIM7 is on APB1 |
| 120 | + clk_div = RCC->CFGR & RCC_CFGR_PPRE1; |
| 121 | + // APB quirk, see See DM00031020 Rev 4, page 115. |
| 122 | + if (clk_div != 0) { |
| 123 | + // APB prescaler for this timer is > 1 |
| 124 | + source *= 2; |
| 125 | + } |
| 126 | + |
| 127 | + uint32_t prescaler = source/1000000; //1us intervals |
| 128 | + |
| 129 | + __HAL_RCC_TIM7_CLK_ENABLE(); |
| 130 | + HAL_NVIC_SetPriority(TIM7_IRQn, 4, 0); |
| 131 | + HAL_NVIC_EnableIRQ(TIM7_IRQn); |
| 132 | + |
| 133 | + // Timers 6 and 7 have no pins, so using them doesn't affect PWM availability |
| 134 | + t7_handle.Instance = TIM7; |
| 135 | + t7_handle.Init.Period = 100; //immediately replaced. |
| 136 | + t7_handle.Init.Prescaler = prescaler - 1; |
| 137 | + t7_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; |
| 138 | + t7_handle.Init.CounterMode = TIM_COUNTERMODE_UP; |
| 139 | + t7_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; |
| 140 | + |
| 141 | + HAL_TIM_Base_Init(&t7_handle); |
| 142 | + t7_handle.Instance->SR = 0; |
| 143 | + |
| 144 | + // The HAL can't work with const, recast required. |
| 145 | + self->pwmout = (pulseio_pwmout_obj_t*)carrier; |
| 146 | + |
| 147 | + turn_off(self); |
45 | 148 | }
|
46 | 149 |
|
47 | 150 | bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) {
|
48 |
| - return true; |
| 151 | + return self->pwmout == NULL; |
49 | 152 | }
|
50 | 153 |
|
51 | 154 | void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) {
|
| 155 | + if (common_hal_pulseio_pulseout_deinited(self)) { |
| 156 | + return; |
| 157 | + } |
| 158 | + turn_on(self); |
| 159 | + self->pwmout = NULL; |
| 160 | + |
| 161 | + refcount--; |
| 162 | + if (refcount == 0) { |
| 163 | + __HAL_RCC_TIM7_CLK_DISABLE(); |
| 164 | + } |
52 | 165 | }
|
53 | 166 |
|
54 | 167 | void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pulses, uint16_t length) {
|
| 168 | + pulse_array = pulses; |
| 169 | + pulse_array_index = 0; |
| 170 | + pulse_array_length = length; |
| 171 | + curr_pulseout = self; |
| 172 | + |
| 173 | + turn_on(self); |
| 174 | + |
| 175 | + // Count up to the next given value. |
| 176 | + start_timer(); |
| 177 | + |
| 178 | + // Use when debugging, or issues are irrecoverable |
| 179 | + // uint32_t starttime = supervisor_ticks_ms64(); |
| 180 | + // uint32_t timeout = 10000; |
| 181 | + while(pulse_array_index < length) { |
| 182 | + // Do other things while we wait. The interrupts will handle sending the |
| 183 | + // signal. |
| 184 | + RUN_BACKGROUND_TASKS; |
| 185 | + |
| 186 | + // Use when debugging, or issues are irrecoverable |
| 187 | + // if ((supervisor_ticks_ms64() - starttime ) > timeout ) { |
| 188 | + // mp_raise_RuntimeError(translate("Error: Send Timeout")); |
| 189 | + // } |
| 190 | + } |
| 191 | + //turn off timer counter. |
| 192 | + t7_handle.Instance->CR1 &= ~TIM_CR1_CEN; |
| 193 | +} |
| 194 | + |
| 195 | +void TIM7_IRQHandler(void) |
| 196 | +{ |
| 197 | + // Detect TIM Update event |
| 198 | + if (__HAL_TIM_GET_FLAG(&t7_handle, TIM_FLAG_UPDATE) != RESET) |
| 199 | + { |
| 200 | + if (__HAL_TIM_GET_IT_SOURCE(&t7_handle, TIM_IT_UPDATE) != RESET) |
| 201 | + { |
| 202 | + __HAL_TIM_CLEAR_IT(&t7_handle, TIM_IT_UPDATE); |
| 203 | + pulseout_event_handler(); |
| 204 | + } |
| 205 | + } |
55 | 206 | }
|
0 commit comments