diff --git a/global.c b/global.c index cfef145..23532bd 100644 --- a/global.c +++ b/global.c @@ -262,6 +262,7 @@ void board_setup(void) // setup button #if defined(BUTTON_PIN) && defined(BUTTON_PRESSED) + rcc_periph_clock_enable(RCC_SYSCFG); // for EXTI port mapping rcc_periph_clock_enable(GPIO_RCC(BUTTON_PIN)); // enable clock for button exti_select_source(GPIO_EXTI(BUTTON_PIN), GPIO_PORT(BUTTON_PIN)); // mask external interrupt of this pin only for this port #if BUTTON_PRESSED // level goes high when pressed diff --git a/lib/led_tm1637.c b/lib/led_tm1637.c index 76f4b48..6d95cbc 100644 --- a/lib/led_tm1637.c +++ b/lib/led_tm1637.c @@ -2,7 +2,7 @@ * @file * @author King Kévin * @copyright SPDX-License-Identifier: GPL-3.0-or-later - * @date 2017-2020 + * @date 2017-2022 * @note peripherals used: GPIO @ref led_tm1637_gpio, timer @ref led_tm1637_timer * @note the protocol is very similar to I2C but incompatible for the following reasons: the capacitance is too large for open-drain type output with weak pull-up resistors (push-pull needs to be used, preventing to get ACKs since no indication of the ACK timing is provided); the devices doesn't use addresses; the STM32 I2C will switch to receiver mode when the first sent byte (the I2C address) has last bit set to 1 (such as for address commands with B7=1 where B7 is transmitted last), preventing to send further bytes (the data byte after the address) * @warning all calls are blocking @@ -173,18 +173,20 @@ void led_tm1637_setup(bool updown) // configure GPIO for CLK and DIO signals rcc_periph_clock_enable(GPIO_RCC(LED_TM1637_CLK_PIN)); // enable clock for GPIO peripheral gpio_set(GPIO_PORT(LED_TM1637_CLK_PIN), GPIO_PIN(LED_TM1637_CLK_PIN)); // idle high - gpio_set_mode(GPIO_PORT(LED_TM1637_CLK_PIN), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_TM1637_CLK_PIN)); // master start the communication (capacitance is to large for open drain), only switch to input for ack from slave + gpio_set_output_options(GPIO_PORT(LED_TM1637_CLK_PIN), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN(LED_TM1637_CLK_PIN)); // set pin output as push-pull (capacitance is to large for open drain) + gpio_mode_setup(GPIO_PORT(LED_TM1637_CLK_PIN), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(LED_TM1637_CLK_PIN)); // set pin as output, master start the communication rcc_periph_clock_enable(GPIO_RCC(LED_TM1637_DIO_PIN)); // enable clock for GPIO peripheral gpio_set(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_PIN(LED_TM1637_DIO_PIN)); // idle high - gpio_set_mode(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_TM1637_DIO_PIN)); // master start the communication (capacitance is to large for open drain), only switch to input for ack from slave + gpio_set_output_options(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN(LED_TM1637_DIO_PIN)); // set pin output as push-pull (capacitance is to large for open drain) + gpio_mode_setup(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(LED_TM1637_DIO_PIN)); // set pin as output, only switch to input for ack from slave // first clock then data high also stands for stop condition // setup timer to create signal timing (each tick is used for a single GPIO transition) rcc_periph_clock_enable(RCC_TIM(LED_TM1637_TIMER)); // enable clock for timer block rcc_periph_reset_pulse(RST_TIM(LED_TM1637_TIMER)); // reset timer state timer_set_mode(TIM(LED_TM1637_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up - timer_set_prescaler(TIM(LED_TM1637_TIMER), 0); // don't prescale to get most precise timing ( 1/(72E6/1/(2**16))=0.91 ms > 0.5 us ) - timer_set_period(TIM(LED_TM1637_TIMER), 500); // set the clock frequency (empirical value until the signal starts to look bad) + timer_set_prescaler(TIM(LED_TM1637_TIMER), 0); // don't prescale to get most precise timing ( 1/(72E6/1/(2**16))=0.78 us > 0.5 us ) + timer_set_period(TIM(LED_TM1637_TIMER), 600); // set the clock frequency (empirical value until the signal starts to look bad) timer_clear_flag(TIM(LED_TM1637_TIMER), TIM_SR_UIF); // clear flag timer_update_on_overflow(TIM(LED_TM1637_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout) } @@ -235,7 +237,7 @@ static bool led_tm1637_write(const uint8_t* data, size_t length) led_tm1637_tick(); // wait for next tick (no DIO transition when CLK is high) gpio_clear(GPIO_PORT(LED_TM1637_CLK_PIN), GPIO_PIN(LED_TM1637_CLK_PIN)); // put CLK low } - gpio_set_mode(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LED_TM1637_DIO_PIN)); // switch DIO as input to read ACK + gpio_mode_setup(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN(LED_TM1637_DIO_PIN)); // switch DIO as input to read ACK led_tm1637_tick(); // wait for next tick (when the slave should ACK) gpio_set(GPIO_PORT(LED_TM1637_CLK_PIN), GPIO_PIN(LED_TM1637_CLK_PIN)); // put CLK high if (gpio_get(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_PIN(LED_TM1637_DIO_PIN))) { // no ACK received @@ -244,11 +246,11 @@ static bool led_tm1637_write(const uint8_t* data, size_t length) } led_tm1637_tick(); // wait for next tick gpio_clear(GPIO_PORT(LED_TM1637_CLK_PIN), GPIO_PIN(LED_TM1637_CLK_PIN)); // put CLK low - gpio_set_mode(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_TM1637_DIO_PIN)); // switch DIO back to output to send next byte + gpio_mode_setup(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(LED_TM1637_DIO_PIN)); // switch DIO back to output to send next byte } // send stop condition - gpio_set_mode(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_TM1637_DIO_PIN)); // ensure DIO is output (in case no ACK as been received + gpio_mode_setup(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(LED_TM1637_DIO_PIN)); // ensure DIO is output (in case no ACK as been received led_tm1637_tick(); // wait for next tick gpio_set(GPIO_PORT(LED_TM1637_CLK_PIN), GPIO_PIN(LED_TM1637_CLK_PIN)); // put CLK high led_tm1637_tick(); // wait for next tick