3434#include "mpconfigport.h"
3535#include "py/gc.h"
3636#include "py/runtime.h"
37+ #include "peripherals/external_interrupts.h"
3738#include "peripherals/pins.h"
3839#include "shared-bindings/microcontroller/__init__.h"
3940#include "shared-bindings/pulseio/PulseIn.h"
4041
41- #ifdef SAMD21
42- #include "hpl/gclk/hpl_gclk_base.h"
43- #endif
44-
4542#include "tick.h"
4643
47- static pulseio_pulsein_obj_t * active_pulseins [EIC_EXTINT_NUM ];
48- static uint64_t last_ms [EIC_EXTINT_NUM ];
49- static uint16_t last_us [EIC_EXTINT_NUM ];
50-
51- bool eic_get_enable (void ) {
52- #ifdef SAMD51
53- return EIC -> CTRLA .bit .ENABLE ;
54- #endif
55- #ifdef SAMD21
56- return EIC -> CTRL .bit .ENABLE ;
57- #endif
58- }
59-
60- void eic_set_enable (bool value ) {
61- #ifdef SAMD51
62- EIC -> CTRLA .bit .ENABLE = value ;
63- while (EIC -> SYNCBUSY .bit .ENABLE != 0 ) {}
64- // This won't actually block long enough in Rev A of SAMD51 and will miss edges in the first
65- // three cycles of the peripheral clock. See the errata for details. It shouldn't impact us.
66- #endif
67- #ifdef SAMD21
68- EIC -> CTRL .bit .ENABLE = value ;
69- while (EIC -> STATUS .bit .SYNCBUSY != 0 ) {}
70- #endif
71- }
72-
73- void eic_reset (void ) {
74- #ifdef SAMD51
75- EIC -> CTRLA .bit .SWRST = true;
76- while (EIC -> SYNCBUSY .bit .SWRST != 0 ) {}
77- // This won't actually block long enough in Rev A of SAMD51 and will miss edges in the first
78- // three cycles of the peripheral clock. See the errata for details. It shouldn't impact us.
79- #endif
80- #ifdef SAMD21
81- EIC -> CTRL .bit .SWRST = true;
82- while (EIC -> STATUS .bit .SYNCBUSY != 0 ) {}
83- #endif
84- }
85-
86- void pulsein_reset (void ) {
87- for (int i = 0 ; i < EIC_EXTINT_NUM ; i ++ ) {
88- active_pulseins [i ] = NULL ;
89- last_ms [i ] = 0 ;
90- last_us [i ] = 0 ;
91- #ifdef SAMD51
92- NVIC_DisableIRQ (EIC_0_IRQn + i );
93- NVIC_ClearPendingIRQ (EIC_0_IRQn + i );
94- #endif
95- }
96- eic_reset ();
97- #ifdef SAMD21
98- NVIC_DisableIRQ (EIC_IRQn );
99- NVIC_ClearPendingIRQ (EIC_IRQn );
100- #endif
101- }
102-
10344static void pulsein_set_config (pulseio_pulsein_obj_t * self , bool first_edge ) {
104- uint8_t sense_setting = EIC_CONFIG_FILTEN0 ;
45+ uint32_t sense_setting ;
10546 if (!first_edge ) {
106- sense_setting |= EIC_CONFIG_SENSE0_BOTH_Val ;
47+ sense_setting = EIC_CONFIG_SENSE0_BOTH_Val ;
48+ configure_eic_channel (self -> channel , sense_setting );
49+ return ;
10750 } else if (self -> idle_state ) {
108- sense_setting | = EIC_CONFIG_SENSE0_FALL_Val ;
51+ sense_setting = EIC_CONFIG_SENSE0_FALL_Val ;
10952 } else {
110- sense_setting | = EIC_CONFIG_SENSE0_RISE_Val ;
53+ sense_setting = EIC_CONFIG_SENSE0_RISE_Val ;
11154 }
112- eic_set_enable (false);
113- uint8_t config_index = self -> channel / 8 ;
114- uint8_t position = (self -> channel % 8 ) * 4 ;
115- uint32_t masked_value = EIC -> CONFIG [config_index ].reg & ~(0xf << position );
116- EIC -> CONFIG [config_index ].reg = masked_value | (sense_setting << position );
117- eic_set_enable (true);
55+ turn_on_eic_channel (self -> channel , sense_setting , EIC_HANDLER_PULSEIN );
11856}
11957
120- static void pulsein_interrupt_handler (uint8_t channel ) {
58+ void pulsein_interrupt_handler (uint8_t channel ) {
12159 // Grab the current time first.
12260 uint32_t current_us ;
12361 uint64_t current_ms ;
12462 current_tick (& current_ms , & current_us );
12563 // current_tick gives us the remaining us until the next tick but we want the number since the
12664 // last ms.
12765 current_us = 1000 - current_us ;
128- pulseio_pulsein_obj_t * self = active_pulseins [ channel ] ;
66+ pulseio_pulsein_obj_t * self = get_eic_channel_data ( channel ) ;
12967 if (self -> first_edge ) {
13068 self -> first_edge = false;
13169 pulsein_set_config (self , false);
13270 } else {
133- uint32_t ms_diff = current_ms - last_ms [ self -> channel ] ;
134- uint16_t us_diff = current_us - last_us [ self -> channel ] ;
71+ uint32_t ms_diff = current_ms - self -> last_ms ;
72+ uint16_t us_diff = current_us - self -> last_us ;
13573 uint32_t total_diff = us_diff ;
136- if (last_us [ self -> channel ] > current_us ) {
137- total_diff = 1000 + current_us - last_us [ self -> channel ] ;
74+ if (self -> last_us > current_us ) {
75+ total_diff = 1000 + current_us - self -> last_us ;
13876 if (ms_diff > 1 ) {
13977 total_diff += (ms_diff - 1 ) * 1000 ;
14078 }
@@ -154,26 +92,16 @@ static void pulsein_interrupt_handler(uint8_t channel) {
15492 self -> start ++ ;
15593 }
15694 }
157- last_ms [ self -> channel ] = current_ms ;
158- last_us [ self -> channel ] = current_us ;
95+ self -> last_ms = current_ms ;
96+ self -> last_us = current_us ;
15997}
16098
16199void common_hal_pulseio_pulsein_construct (pulseio_pulsein_obj_t * self ,
162100 const mcu_pin_obj_t * pin , uint16_t maxlen , bool idle_state ) {
163101 if (!pin -> has_extint ) {
164102 mp_raise_RuntimeError ("No hardware support on pin" );
165103 }
166- uint32_t mask = 1 << pin -> extint_channel ;
167- if (active_pulseins [pin -> extint_channel ] != NULL ||
168- (eic_get_enable () == 1 &&
169- #ifdef SAMD51
170- ((EIC -> INTENSET .bit .EXTINT & mask ) != 0 ||
171- (EIC -> EVCTRL .bit .EXTINTEO & mask ) != 0 ))) {
172- #endif
173- #ifdef SAMD21
174- ((EIC -> INTENSET .vec .EXTINT & mask ) != 0 ||
175- (EIC -> EVCTRL .vec .EXTINTEO & mask ) != 0 ))) {
176- #endif
104+ if (eic_get_enable () && !eic_channel_free (pin -> extint_channel )) {
177105 mp_raise_RuntimeError ("EXTINT channel already in use" );
178106 }
179107
@@ -188,42 +116,22 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
188116 self -> start = 0 ;
189117 self -> len = 0 ;
190118 self -> first_edge = true;
119+ self -> last_us = 0 ;
120+ self -> last_ms = 0 ;
191121
192- active_pulseins [ pin -> extint_channel ] = self ;
122+ set_eic_channel_data ( pin -> extint_channel , ( void * ) self ) ;
193123
194124 // Check to see if the EIC is enabled and start it up if its not.'
195- // SAMD51 EIC can only be clocked up to 100mhz so we use the 48mhz clock.
196125 if (eic_get_enable () == 0 ) {
197- #ifdef SAMD51
198- MCLK -> APBAMASK .bit .EIC_ = true;
199- hri_gclk_write_PCHCTRL_reg (GCLK , EIC_GCLK_ID ,
200- GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos ));
201- #endif
202-
203- #ifdef SAMD21
204- PM -> APBAMASK .bit .EIC_ = true;
205- _gclk_enable_channel (EIC_GCLK_ID , GCLK_CLKCTRL_GEN_GCLK0_Val );
206- #endif
207-
208-
209- #ifdef SAMD21
210- NVIC_DisableIRQ (EIC_IRQn );
211- NVIC_ClearPendingIRQ (EIC_IRQn );
212- NVIC_EnableIRQ (EIC_IRQn );
213- #endif
126+ turn_on_external_interrupt_controller ();
214127 }
215128
216129 gpio_set_pin_function (pin -> pin , GPIO_PIN_FUNCTION_A );
217130
218- #ifdef SAMD51
219- NVIC_DisableIRQ (EIC_0_IRQn + self -> channel );
220- NVIC_ClearPendingIRQ (EIC_0_IRQn + self -> channel );
221- NVIC_EnableIRQ (EIC_0_IRQn + self -> channel );
222- #endif
131+ turn_on_cpu_interrupt (self -> channel );
223132
224133 // Set config will enable the EIC.
225134 pulsein_set_config (self , true);
226- EIC -> INTENSET .reg = mask << EIC_INTENSET_EXTINT_Pos ;
227135}
228136
229137bool common_hal_pulseio_pulsein_deinited (pulseio_pulsein_obj_t * self ) {
@@ -234,39 +142,9 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) {
234142 if (common_hal_pulseio_pulsein_deinited (self )) {
235143 return ;
236144 }
237- uint32_t mask = 1 << self -> channel ;
238- EIC -> INTENCLR .reg = mask << EIC_INTENSET_EXTINT_Pos ;
239- #ifdef SAMD51
240- NVIC_DisableIRQ (EIC_0_IRQn + self -> channel );
241- NVIC_ClearPendingIRQ (EIC_0_IRQn + self -> channel );
242- #endif
243- active_pulseins [self -> channel ] = NULL ;
145+ turn_off_eic_channel (self -> channel );
244146 reset_pin (self -> pin );
245147 self -> pin = NO_PIN ;
246-
247- bool all_null = true;
248- for (uint8_t i = 0 ; all_null && i < 16 ; i ++ ) {
249- all_null = all_null && active_pulseins [i ] == NULL ;
250- }
251- #ifdef SAMD21
252- if (all_null && EIC -> INTENSET .reg == 0 ) {
253- NVIC_DisableIRQ (EIC_IRQn );
254- NVIC_ClearPendingIRQ (EIC_IRQn );
255- }
256- #endif
257- // Test if all channels are null and deinit everything if they are.
258- if (all_null && EIC -> EVCTRL .reg == 0 && EIC -> INTENSET .reg == 0 ) {
259- eic_set_enable (false);
260- #ifdef SAMD51
261- MCLK -> APBAMASK .bit .EIC_ = false;
262- hri_gclk_write_PCHCTRL_reg (GCLK , EIC_GCLK_ID , 0 );
263- #endif
264-
265- #ifdef SAMD21
266- PM -> APBAMASK .bit .EIC_ = false;
267- hri_gclk_write_CLKCTRL_reg (GCLK , GCLK_CLKCTRL_ID (EIC_GCLK_ID ));
268- #endif
269- }
270148}
271149
272150void common_hal_pulseio_pulsein_pause (pulseio_pulsein_obj_t * self ) {
@@ -289,9 +167,9 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self,
289167 }
290168
291169 // Reconfigure the pin and make sure its set to detect the first edge.
292- last_ms [self -> channel ] = 0 ;
293- last_us [self -> channel ] = 0 ;
294170 self -> first_edge = true;
171+ self -> last_ms = 0 ;
172+ self -> last_us = 0 ;
295173 gpio_set_pin_function (self -> pin , GPIO_PIN_FUNCTION_A );
296174 uint32_t mask = 1 << self -> channel ;
297175 // Clear previous interrupt state and re-enable it.
@@ -343,69 +221,3 @@ uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self,
343221 common_hal_mcu_enable_interrupts ();
344222 return value ;
345223}
346-
347- void external_interrupt_handler (uint8_t channel ) {
348- pulsein_interrupt_handler (channel );
349- EIC -> INTFLAG .reg = (1 << channel ) << EIC_INTFLAG_EXTINT_Pos ;
350- }
351-
352- #ifdef SAMD21
353- void EIC_Handler (void ) {
354- for (uint8_t i = 0 ; i < 16 ; i ++ ) {
355- if ((EIC -> INTFLAG .vec .EXTINT & (1 << i )) != 0 ) {
356- external_interrupt_handler (i );
357- }
358- }
359- }
360- #endif
361-
362- #ifdef SAMD51
363- void EIC_0_Handler (void ) {
364- external_interrupt_handler (0 );
365- }
366- void EIC_1_Handler (void ) {
367- external_interrupt_handler (1 );
368- }
369- void EIC_2_Handler (void ) {
370- external_interrupt_handler (2 );
371- }
372- void EIC_3_Handler (void ) {
373- external_interrupt_handler (3 );
374- }
375- void EIC_4_Handler (void ) {
376- external_interrupt_handler (4 );
377- }
378- void EIC_5_Handler (void ) {
379- external_interrupt_handler (5 );
380- }
381- void EIC_6_Handler (void ) {
382- external_interrupt_handler (6 );
383- }
384- void EIC_7_Handler (void ) {
385- external_interrupt_handler (7 );
386- }
387- void EIC_8_Handler (void ) {
388- external_interrupt_handler (8 );
389- }
390- void EIC_9_Handler (void ) {
391- external_interrupt_handler (9 );
392- }
393- void EIC_10_Handler (void ) {
394- external_interrupt_handler (10 );
395- }
396- void EIC_11_Handler (void ) {
397- external_interrupt_handler (11 );
398- }
399- void EIC_12_Handler (void ) {
400- external_interrupt_handler (12 );
401- }
402- void EIC_13_Handler (void ) {
403- external_interrupt_handler (13 );
404- }
405- void EIC_14_Handler (void ) {
406- external_interrupt_handler (14 );
407- }
408- void EIC_15_Handler (void ) {
409- external_interrupt_handler (15 );
410- }
411- #endif
0 commit comments