tm1637: port to STM32F4

This commit is contained in:
King Kévin 2022-10-28 12:52:46 +02:00
parent 5c78aa498e
commit 624006500f
2 changed files with 11 additions and 8 deletions

View File

@ -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

View File

@ -2,7 +2,7 @@
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @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