Skip to content

Commit 0076a3c

Browse files
authored
Merge pull request adafruit#393 from tannewt/m4_neopixel
Now with more blinky!!!
2 parents dc3f13d + f4c8256 commit 0076a3c

File tree

12 files changed

+132
-33
lines changed

12 files changed

+132
-33
lines changed

main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ bool start_mp(safe_mode_t safe_mode) {
146146
// Wait for connection or character.
147147
bool serial_connected_before_animation = false;
148148
rgb_status_animation_t animation;
149-
prep_rgb_status_animation(&result, found_main, &animation);
149+
prep_rgb_status_animation(&result, found_main, safe_mode, &animation);
150150
while (true) {
151151
#ifdef MICROPY_VM_HOOK_LOOP
152152
MICROPY_VM_HOOK_LOOP

ports/atmel-samd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ SRC_COMMON_HAL = \
251251
microcontroller/__init__.c \
252252
microcontroller/Pin.c \
253253
microcontroller/Processor.c \
254+
neopixel_write/__init__.c \
254255
os/__init__.c \
255256
time/__init__.c
256257
#analogio/__init__.c \

ports/atmel-samd/boards/circuitplayground_express/board.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,6 @@ void reset_board(void) {
6161
common_hal_digitalio_digitalinout_construct(&neopixel_pin, &pin_PB23);
6262
common_hal_digitalio_digitalinout_switch_to_output(&neopixel_pin, false,
6363
DRIVE_MODE_PUSH_PULL);
64-
// common_hal_neopixel_write(&neopixel_pin, empty, 30);
64+
common_hal_neopixel_write(&neopixel_pin, empty, 30);
6565
common_hal_digitalio_digitalinout_deinit(&neopixel_pin);
6666
}

ports/atmel-samd/boards/metro_m4_express/board.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,16 @@
2626

2727
#include "boards/board.h"
2828
#include "mpconfigboard.h"
29+
#include "hal/include/hal_gpio.h"
2930

3031
void board_init(void) {
32+
gpio_set_pin_function(MICROPY_HW_LED_TX, GPIO_PIN_FUNCTION_OFF);
33+
gpio_set_pin_direction(MICROPY_HW_LED_TX, GPIO_DIRECTION_OUT);
34+
gpio_set_pin_level(MICROPY_HW_LED_TX, true);
35+
36+
gpio_set_pin_function(MICROPY_HW_LED_RX, GPIO_PIN_FUNCTION_OFF);
37+
gpio_set_pin_direction(MICROPY_HW_LED_RX, GPIO_DIRECTION_OUT);
38+
gpio_set_pin_level(MICROPY_HW_LED_RX, true);
3139
}
3240

3341
bool board_requests_safe_mode(void) {

ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#define MICROPY_HW_LED_TX PIN_PA27
77
#define MICROPY_HW_LED_RX PIN_PB06
88

9-
// #define MICROPY_HW_NEOPIXEL (&pin_PB17)
9+
#define MICROPY_HW_NEOPIXEL (&pin_PB17)
1010

1111
#define SPI_FLASH_BAUDRATE (1000000)
1212

ports/atmel-samd/common-hal/neopixel_write/__init__.c

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,27 @@
2323
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2424
* THE SOFTWARE.
2525
*/
26+
#include "hpl_gpio.h"
2627

27-
#include "mphalport.h"
28+
#include "py/mphal.h"
2829

2930
#include "shared-bindings/neopixel_write/__init__.h"
3031

31-
#include "asf/common2/services/delay/delay.h"
32-
#include "asf/sam0/drivers/port/port.h"
32+
#include "tick.h"
33+
34+
#ifdef SAMD51
35+
static inline void delay_cycles(uint8_t cycles) {
36+
uint32_t start = SysTick->VAL;
37+
uint32_t stop = start - cycles;
38+
if (start < cycles) {
39+
stop = 0xffffff + start - cycles;
40+
}
41+
while (SysTick->VAL > stop) {}
42+
}
43+
#endif
44+
45+
uint64_t next_start_tick_ms = 0;
46+
uint32_t next_start_tick_us = 1000;
3347

3448
void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels, uint32_t numBytes) {
3549
// This is adapted directly from the Adafruit NeoPixel library SAMD21G18A code:
@@ -38,14 +52,21 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout,
3852
uint32_t pinMask;
3953
PortGroup* port;
4054

55+
// This must be called while interrupts are on in case we're waiting for a
56+
// future ms tick.
57+
wait_until(next_start_tick_ms, next_start_tick_us);
58+
4159
// Turn off interrupts of any kind during timing-sensitive code.
4260
mp_hal_disable_all_interrupts();
4361

62+
#ifdef SAMD21
4463
// Make sure the NVM cache is consistently timed.
4564
NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_DETERMINISTIC_Val;
65+
#endif
66+
4667

4768
uint32_t pin = digitalinout->pin->pin;
48-
port = port_get_group_from_gpio_pin(pin);
69+
port = &PORT->Group[GPIO_PORT(pin)]; // Convert GPIO # to port register
4970
pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code.
5071
ptr = pixels;
5172
end = ptr + numBytes;
@@ -57,31 +78,75 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout,
5778

5879
for(;;) {
5980
*set = pinMask;
81+
// This is the time where the line is always high regardless of the bit.
82+
// For the SK6812 its 0.3us +- 0.15us
83+
#ifdef SAMD21
6084
asm("nop; nop;");
85+
#endif
86+
#ifdef SAMD51
87+
delay_cycles(18);
88+
#endif
6189
if(p & bitMask) {
90+
// This is the high delay unique to a one bit.
91+
// For the SK6812 its 0.3us
92+
#ifdef SAMD21
6293
asm("nop; nop; nop; nop; nop; nop; nop;");
94+
#endif
95+
#ifdef SAMD51
96+
delay_cycles(25);
97+
#endif
6398
*clr = pinMask;
6499
} else {
65100
*clr = pinMask;
101+
// This is the low delay unique to a zero bit.
102+
// For the SK6812 its 0.3us
103+
#ifdef SAMD21
66104
asm("nop; nop;");
105+
#endif
106+
#ifdef SAMD51
107+
delay_cycles(25);
108+
#endif
67109
}
68110
if((bitMask >>= 1) != 0) {
111+
// This is the delay between bits in a byte and is the 1 code low
112+
// level time from the datasheet.
113+
// For the SK6812 its 0.6us +- 0.15us
114+
#ifdef SAMD21
69115
asm("nop; nop; nop; nop; nop;");
116+
#endif
117+
#ifdef SAMD51
118+
delay_cycles(44);
119+
#endif
70120
} else {
71121
if(ptr >= end) break;
72122
p = *ptr++;
73123
bitMask = 0x80;
124+
// This is the delay between bytes. Its similar to the other branch
125+
// in the if statement except its tuned to account for the time the
126+
// above operations take.
127+
// For the SK6812 its 0.6us +- 0.15us
128+
#ifdef SAMD51
129+
delay_cycles(50);
130+
#endif
74131
}
75132
}
76133

134+
#ifdef SAMD21
77135
// Speed up! (But inconsistent timing.)
78136
NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_NO_MISS_PENALTY_Val;
137+
#endif
138+
139+
// ticks_ms may be out of date at this point because we stopped the
140+
// interrupt. We'll risk it anyway.
141+
current_tick(&next_start_tick_ms, &next_start_tick_us);
142+
if (next_start_tick_us < 100) {
143+
next_start_tick_ms += 1;
144+
next_start_tick_us = 100 - next_start_tick_us;
145+
} else {
146+
next_start_tick_us -= 100;
147+
}
79148

80149
// Turn on interrupts after timing-sensitive code.
81150
mp_hal_enable_all_interrupts();
82151

83-
// 50us delay to let pixels latch to the data that was just sent.
84-
// This could be optimized to only occur before pixel writes when necessary,
85-
// like in the Arduino library.
86-
delay_us(50);
87152
}

ports/atmel-samd/mpconfigport.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ extern const struct _mp_obj_module_t usb_hid_module;
215215
// { MP_OBJ_NEW_QSTR(MP_QSTR_analogio), (mp_obj_t)&analogio_module },
216216
// { MP_OBJ_NEW_QSTR(MP_QSTR_busio), (mp_obj_t)&busio_module },
217217
// { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module },
218-
// { MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module },
219218
// { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module },
220219
// { MP_OBJ_NEW_QSTR(MP_QSTR_storage), (mp_obj_t)&storage_module },
221220
// { MP_OBJ_NEW_QSTR(MP_QSTR_samd),(mp_obj_t)&samd_module },
@@ -225,6 +224,7 @@ extern const struct _mp_obj_module_t usb_hid_module;
225224
{ MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&board_module }, \
226225
{ MP_OBJ_NEW_QSTR(MP_QSTR_digitalio), (mp_obj_t)&digitalio_module }, \
227226
{ MP_OBJ_NEW_QSTR(MP_QSTR_microcontroller), (mp_obj_t)&microcontroller_module }, \
227+
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module }, \
228228
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \
229229
{ MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, \
230230
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&struct_module }, \

ports/atmel-samd/tick.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,17 @@ void tick_delay(uint32_t us) {
6666
start_ms = ticks_ms;
6767
us_between_ticks = 1000;
6868
}
69-
while (SysTick->VAL > ((1000 - us) * ticks_per_us)) {}
69+
while (SysTick->VAL > ((us_between_ticks - us) * ticks_per_us)) {}
70+
}
71+
72+
// us counts down!
73+
void current_tick(uint64_t* ms, uint32_t* us_until_ms) {
74+
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
75+
*ms = ticks_ms;
76+
*us_until_ms = SysTick->VAL / ticks_per_us;
77+
}
78+
79+
void wait_until(uint64_t ms, uint32_t us_until_ms) {
80+
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
81+
while(ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {}
7082
}

ports/atmel-samd/tick.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,9 @@ void tick_init(void);
3636

3737
void tick_delay(uint32_t us);
3838

39+
void current_tick(uint64_t* ms, uint32_t* us_until_ms);
40+
// Do not call this with interrupts disabled because it may be waiting for
41+
// ticks_ms to increment.
42+
void wait_until(uint64_t ms, uint32_t us_until_ms);
43+
3944
#endif // MICROPY_INCLUDED_ATMEL_SAMD_TICK_H

ports/atmel-samd/usb_mass_storage.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,7 @@ void usb_msc_background(void) {
309309
// Load more blocks from USB if they are needed.
310310
if (active_nblocks > 0) {
311311
int32_t result = mscdf_xfer_blocks(false, sector_buffer, 1);
312-
while (result != ERR_NONE) {}
313-
usb_busy = true;
312+
usb_busy = result != ERR_NONE;
314313
} else {
315314
mscdf_xfer_blocks(false, NULL, 0);
316315
active_write = false;

0 commit comments

Comments
 (0)