Skip to content

Commit 1b106de

Browse files
authored
Merge pull request #4262 from DavePutz/issue_4111
Issue 4111 - Implement pulseio(pulsein) for RP2040
2 parents a5c6759 + 96ce43e commit 1b106de

File tree

8 files changed

+418
-1
lines changed

8 files changed

+418
-1
lines changed
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2021 Dave Putz for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h"
28+
29+
#include <stdint.h>
30+
31+
#include "py/runtime.h"
32+
#include "shared-bindings/microcontroller/__init__.h"
33+
#include "shared-bindings/pulseio/PulseIn.h"
34+
#include "shared-bindings/microcontroller/Pin.h"
35+
#include "supervisor/shared/translate.h"
36+
#include "bindings/rp2pio/StateMachine.h"
37+
#include "common-hal/pulseio/PulseIn.h"
38+
39+
pulseio_pulsein_obj_t* save_self;
40+
41+
#define NO_PIN 0xff
42+
volatile bool last_level;
43+
volatile uint16_t level_count = 0;
44+
volatile uint16_t result = 0;
45+
volatile uint16_t buf_index = 0;
46+
47+
uint16_t pulsein_program[] = {
48+
0x4001, // 1: in pins, 1
49+
};
50+
51+
void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
52+
const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) {
53+
54+
self->buffer = (uint16_t *) m_malloc(maxlen * sizeof(uint16_t), false);
55+
if (self->buffer == NULL) {
56+
mp_raise_msg_varg(&mp_type_MemoryError, translate("Failed to allocate RX buffer of %d bytes"), maxlen * sizeof(uint16_t));
57+
}
58+
self->pin = pin->number;
59+
self->maxlen = maxlen;
60+
self->idle_state = idle_state;
61+
self->start = 0;
62+
self->len = 0;
63+
save_self = self;
64+
65+
// Set everything up.
66+
rp2pio_statemachine_obj_t state_machine;
67+
68+
bool ok = rp2pio_statemachine_construct(&state_machine,
69+
pulsein_program, sizeof(pulsein_program) / sizeof(pulsein_program[0]),
70+
1000000,
71+
NULL, 0,
72+
NULL, 0,
73+
pin, 1,
74+
0,0,
75+
NULL, 0,
76+
NULL, 0,
77+
1, 0,
78+
1 << self->pin, false, true,
79+
false, 8, false, // TX, unused
80+
false,
81+
true, 32, true, // RX auto-push every 32 bits
82+
false); // claim pins
83+
pio_sm_set_enabled(state_machine.pio,state_machine.state_machine, false);
84+
self->state_machine.pio = state_machine.pio;
85+
self->state_machine.state_machine = state_machine.state_machine;
86+
self->state_machine.sm_config = state_machine.sm_config;
87+
self->state_machine.offset = state_machine.offset;
88+
pio_sm_clear_fifos(self->state_machine.pio,self->state_machine.state_machine);
89+
last_level = self->idle_state;
90+
level_count = 0;
91+
result = 0;
92+
buf_index = 0;
93+
94+
pio_sm_set_in_pins(state_machine.pio,state_machine.state_machine,pin->number);
95+
common_hal_rp2pio_statemachine_set_interrupt_handler(&state_machine,&common_hal_pulseio_pulsein_interrupt,NULL,PIO_IRQ0_INTE_SM0_RXNEMPTY_BITS);
96+
97+
// exec a set pindirs to 0 for input
98+
pio_sm_exec(state_machine.pio,state_machine.state_machine,0xe080);
99+
//exec the appropriate wait for pin
100+
if (self->idle_state == true ) {
101+
pio_sm_exec(self->state_machine.pio,self->state_machine.state_machine,0x2020);
102+
} else {
103+
pio_sm_exec(self->state_machine.pio,self->state_machine.state_machine,0x20a0);
104+
}
105+
pio_sm_set_enabled(state_machine.pio, state_machine.state_machine, true);
106+
}
107+
108+
bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) {
109+
return self->pin == NO_PIN;
110+
}
111+
112+
void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) {
113+
if (common_hal_pulseio_pulsein_deinited(self)) {
114+
return;
115+
}
116+
pio_sm_set_enabled(self->state_machine.pio, self->state_machine.state_machine, false);
117+
pio_sm_unclaim (self->state_machine.pio, self->state_machine.state_machine);
118+
m_free(self->buffer);
119+
self->pin = NO_PIN;
120+
}
121+
122+
void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) {
123+
pio_sm_set_enabled(self->state_machine.pio, self->state_machine.state_machine, false);
124+
}
125+
126+
void common_hal_pulseio_pulsein_interrupt() {
127+
128+
pulseio_pulsein_obj_t* self = save_self;
129+
uint32_t rxfifo = 0;
130+
131+
rxfifo = pio_sm_get_blocking(self->state_machine.pio, self->state_machine.state_machine);
132+
// translate from fifo to buffer
133+
for (uint i = 0; i < 32; i++) {
134+
bool level = (rxfifo & (1 << i)) >> i;
135+
if (level == last_level ) {
136+
level_count ++;
137+
} else {
138+
result = level_count;
139+
last_level = level;
140+
level_count = 1;
141+
// ignore pulses that are too long and too short
142+
if (result < 4000 && result > 10) {
143+
self->buffer[buf_index] = result;
144+
buf_index++;
145+
self->len++;
146+
}
147+
}
148+
}
149+
// check for a pulse thats too long (4000 us) or maxlen reached, and reset
150+
if (( level_count > 4000 ) || (buf_index >= self->maxlen)) {
151+
pio_sm_set_enabled(self->state_machine.pio, self->state_machine.state_machine, false);
152+
pio_sm_init(self->state_machine.pio, self->state_machine.state_machine, self->state_machine.offset, &self->state_machine.sm_config);
153+
pio_sm_restart(self->state_machine.pio,self->state_machine.state_machine);
154+
pio_sm_set_enabled(self->state_machine.pio, self->state_machine.state_machine, true);
155+
}
156+
}
157+
void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self,
158+
uint16_t trigger_duration) {
159+
// exec a wait for the selected pin to change state
160+
if (self->idle_state == true ) {
161+
pio_sm_exec(self->state_machine.pio,self->state_machine.state_machine,0x2020);
162+
} else {
163+
pio_sm_exec(self->state_machine.pio,self->state_machine.state_machine,0x20a0);
164+
}
165+
// Send the trigger pulse.
166+
if (trigger_duration > 0) {
167+
gpio_set_function(self->pin ,GPIO_FUNC_SIO);
168+
gpio_set_dir(self->pin,true);
169+
gpio_put(self->pin, !self->idle_state);
170+
common_hal_mcu_delay_us((uint32_t)trigger_duration);
171+
gpio_set_function(self->pin ,GPIO_FUNC_PIO0);
172+
common_hal_mcu_delay_us(225);
173+
}
174+
175+
// Reconfigure the pin for PIO
176+
gpio_set_function(self->pin, GPIO_FUNC_PIO0);
177+
pio_sm_set_enabled(self->state_machine.pio, self->state_machine.state_machine, true);
178+
}
179+
180+
void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t* self) {
181+
self->start = 0;
182+
self->len = 0;
183+
}
184+
185+
uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t* self) {
186+
if (self->len == 0) {
187+
mp_raise_IndexError_varg(translate("pop from empty %q"), MP_QSTR_PulseIn);
188+
}
189+
uint16_t value = self->buffer[self->start];
190+
self->start = (self->start + 1) % self->maxlen;
191+
self->len--;
192+
// if we are empty reset buffer pointer and counters
193+
if (self->len == 0 ) {
194+
self->start = 0;
195+
buf_index = 0;
196+
level_count = 0;
197+
}
198+
return value;
199+
}
200+
201+
uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self) {
202+
return self->maxlen;
203+
}
204+
205+
uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) {
206+
return self->len;
207+
}
208+
209+
bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t* self) {
210+
return true;
211+
}
212+
213+
uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self,
214+
int16_t index) {
215+
if (index < 0) {
216+
index += self->len;
217+
}
218+
if (index < 0 || index >= self->len) {
219+
mp_raise_IndexError_varg(translate("%q index out of range"), MP_QSTR_PulseIn);
220+
}
221+
uint16_t value = self->buffer[(self->start + index) % self->maxlen];
222+
return value;
223+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2021 Dave Putz for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEIN_H
28+
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEIN_H
29+
30+
#include "common-hal/microcontroller/Pin.h"
31+
#include "src/rp2_common/hardware_pio/include/hardware/pio.h"
32+
#include "common-hal/rp2pio/StateMachine.h"
33+
34+
#include "py/obj.h"
35+
36+
typedef struct {
37+
mp_obj_base_t base;
38+
uint8_t pin;
39+
uint16_t* buffer;
40+
uint16_t maxlen;
41+
bool idle_state;
42+
volatile uint16_t start;
43+
volatile uint16_t len;
44+
rp2pio_statemachine_obj_t state_machine;
45+
} pulseio_pulsein_obj_t;
46+
47+
void pulsein_reset(void);
48+
void common_hal_pulseio_pulsein_interrupt();
49+
50+
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEIN_H
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2021 Dave Putz for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "common-hal/pulseio/PulseOut.h"
28+
29+
#include <stdint.h>
30+
31+
#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h"
32+
33+
#include "mpconfigport.h"
34+
#include "py/gc.h"
35+
#include "py/runtime.h"
36+
#include "shared-bindings/pulseio/PulseOut.h"
37+
#include "supervisor/shared/translate.h"
38+
39+
static uint8_t refcount = 0;
40+
41+
42+
static uint16_t *pulse_buffer = NULL;
43+
static volatile uint16_t pulse_index = 0;
44+
static uint16_t pulse_length;
45+
static volatile uint32_t current_compare = 0;
46+
47+
void pulse_finish(void) {
48+
pulse_index++;
49+
50+
// Always turn it off.
51+
if (pulse_index >= pulse_length) {
52+
return;
53+
}
54+
current_compare = (current_compare + pulse_buffer[pulse_index] * 3 / 4) & 0xffff;
55+
}
56+
57+
void pulseout_reset() {
58+
refcount = 0;
59+
}
60+
61+
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
62+
const pwmio_pwmout_obj_t* carrier,
63+
const mcu_pin_obj_t* pin,
64+
uint32_t frequency,
65+
uint16_t duty_cycle) {
66+
mp_raise_NotImplementedError(translate("Unsupported operation"));
67+
68+
refcount++;
69+
70+
self->pin = carrier->pin->number;
71+
72+
}
73+
74+
bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) {
75+
return self->pin == NO_PIN;
76+
}
77+
78+
void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) {
79+
if (common_hal_pulseio_pulseout_deinited(self)) {
80+
return;
81+
}
82+
83+
84+
refcount--;
85+
self->pin = NO_PIN;
86+
}
87+
88+
void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pulses, uint16_t length) {
89+
pulse_buffer = pulses;
90+
pulse_index = 0;
91+
pulse_length = length;
92+
93+
current_compare = pulses[0] * 3 / 4;
94+
95+
}

0 commit comments

Comments
 (0)