Skip to content

Commit 840f88b

Browse files
authored
Merge pull request #2350 from hierophect/stm32-neopixel-fix
Fix for neopixels on <100MHz STM32 boards
2 parents 12f64c7 + c53496a commit 840f88b

File tree

2 files changed

+14
-8
lines changed

2 files changed

+14
-8
lines changed

ports/stm32f4/common-hal/digitalio/DigitalInOut.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct(
4747
GPIO_InitStruct.Pin = pin_mask(self->pin->number);
4848
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
4949
GPIO_InitStruct.Pull = GPIO_NOPULL;
50-
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
50+
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
5151
HAL_GPIO_Init(pin_port(self->pin->port), &GPIO_InitStruct);
5252

5353
return DIGITALINOUT_OK;
@@ -73,7 +73,7 @@ void common_hal_digitalio_digitalinout_switch_to_input(
7373
GPIO_InitStruct.Pin = pin_mask(self->pin->number);
7474
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
7575
GPIO_InitStruct.Pull = GPIO_NOPULL;
76-
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
76+
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
7777
HAL_GPIO_Init(pin_port(self->pin->port), &GPIO_InitStruct);
7878

7979
common_hal_digitalio_digitalinout_set_pull(self, pull);
@@ -114,7 +114,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode(
114114
GPIO_InitStruct.Mode = (drive_mode == DRIVE_MODE_OPEN_DRAIN ?
115115
GPIO_MODE_OUTPUT_OD : GPIO_MODE_OUTPUT_PP);
116116
GPIO_InitStruct.Pull = GPIO_NOPULL;
117-
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
117+
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
118118
HAL_GPIO_Init(pin_port(self->pin->port), &GPIO_InitStruct);
119119
}
120120

ports/stm32f4/common-hal/neopixel_write/__init__.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "shared-bindings/neopixel_write/__init__.h"
2929

3030
#include "tick.h"
31+
#include "py/mperrno.h"
32+
#include "py/runtime.h"
3133
#include "common-hal/microcontroller/Pin.h"
3234
#include "stm32f4xx_hal.h"
3335
#include "stm32f4xx_ll_gpio.h"
@@ -40,6 +42,9 @@ uint32_t next_start_tick_us = 1000;
4042
#define MAGIC_800_T0H 2800000 // ~0.36 us -> 0.44 field
4143
#define MAGIC_800_T1H 1350000 // ~0.74 us -> 0.84 field
4244

45+
#pragma GCC push_options
46+
#pragma GCC optimize ("Os")
47+
4348
void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels,
4449
uint32_t numBytes) {
4550
uint8_t *p = pixels, *end = p + numBytes, pix = *p++, mask = 0x80;
@@ -48,7 +53,7 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
4853

4954
//assumes 800_000Hz frequency
5055
//Theoretical values here are 800_000 -> 1.25us, 2500000->0.4us, 1250000->0.8us
51-
//But they don't work, possibly due to bad optimization? Use tested magic values instead
56+
//TODO: try to get dynamic weighting working again
5257
uint32_t sys_freq = HAL_RCC_GetSysClockFreq();
5358
uint32_t interval = sys_freq/MAGIC_800_INT;
5459
uint32_t t0 = (sys_freq/MAGIC_800_T0H);
@@ -63,23 +68,22 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
6368

6469
__disable_irq();
6570
// Enable DWT in debug core. Useable when interrupts disabled, as opposed to Systick->VAL
66-
//ITM->LAR = 0xC5ACCE55; //this should be required but isn't
6771
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
6872
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
6973
DWT->CYCCNT = 0;
7074

7175
for(;;) {
76+
cyc = (pix & mask) ? t1 : t0;
7277
start = DWT->CYCCNT;
7378
LL_GPIO_SetOutputPin(p_port, p_mask);
74-
cyc = (pix & mask) ? t1 : t0;
75-
while(DWT->CYCCNT - start < cyc);
79+
while((DWT->CYCCNT - start) < cyc);
7680
LL_GPIO_ResetOutputPin(p_port, p_mask);
81+
while((DWT->CYCCNT - start) < interval);
7782
if(!(mask >>= 1)) {
7883
if(p >= end) break;
7984
pix = *p++;
8085
mask = 0x80;
8186
}
82-
while(DWT->CYCCNT - start < interval); //wait for interval to finish
8387
}
8488

8589
// Enable interrupts again
@@ -94,3 +98,5 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
9498
next_start_tick_us -= 100;
9599
}
96100
}
101+
102+
#pragma GCC pop_options

0 commit comments

Comments
 (0)