aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKing Kévin <kingkevin@cuvoodoo.info>2021-03-24 11:16:48 +0100
committerKing Kévin <kingkevin@cuvoodoo.info>2021-03-24 11:16:48 +0100
commitc18e33dbce6bab42e69349190f67882f8640c12d (patch)
tree235791527d2b4267be722521e33cd607ef6bea50
parent02d86702b060d4cb52d5daa9377c62415a40c2e1 (diff)
remove unused librariesswj_finder
-rw-r--r--lib/flash_sdcard.c598
-rw-r--r--lib/flash_sdcard.h35
-rw-r--r--lib/font.c337
-rw-r--r--lib/font.h41
-rw-r--r--lib/i2c_master.c531
-rw-r--r--lib/i2c_master.h112
-rw-r--r--lib/interrupt.c131
-rw-r--r--lib/interrupt.h14
-rw-r--r--lib/ir_nec.c189
-rw-r--r--lib/ir_nec.h27
-rw-r--r--lib/lcd_hd44780.c783
-rw-r--r--lib/lcd_hd44780.h82
-rw-r--r--lib/led_max7219.c254
-rw-r--r--lib/led_max7219.h52
-rw-r--r--lib/led_sk6812rgbw.c115
-rw-r--r--lib/led_sk6812rgbw.h25
-rw-r--r--lib/led_tm1637.c354
-rw-r--r--lib/led_tm1637.h60
-rw-r--r--lib/led_ws2812b.c128
-rw-r--r--lib/led_ws2812b.h24
-rw-r--r--lib/microwire_master.c298
-rw-r--r--lib/microwire_master.h56
-rw-r--r--lib/oled_ssd1306.c121
-rw-r--r--lib/oled_ssd1306.h26
-rw-r--r--lib/oled_text.c146
-rw-r--r--lib/oled_text.h45
-rw-r--r--lib/onewire_master.c507
-rw-r--r--lib/onewire_master.h366
-rw-r--r--lib/onewire_slave.c395
-rw-r--r--lib/onewire_slave.h41
-rw-r--r--lib/radio_esp8266.c162
-rw-r--r--lib/radio_esp8266.h35
-rw-r--r--lib/radio_sx172x.c145
-rw-r--r--lib/radio_sx172x.h162
-rw-r--r--lib/rtc_dcf77.c281
-rw-r--r--lib/rtc_dcf77.h37
-rw-r--r--lib/rtc_ds1307.c384
-rw-r--r--lib/rtc_ds1307.h128
-rw-r--r--lib/sensor_as3935.c558
-rw-r--r--lib/sensor_as3935.h150
-rw-r--r--lib/sensor_dht11.c177
-rw-r--r--lib/sensor_dht11.h29
-rw-r--r--lib/sensor_dht22.c181
-rw-r--r--lib/sensor_dht22.h29
-rw-r--r--lib/sensor_ds18b20.c189
-rw-r--r--lib/sensor_ds18b20.h43
-rw-r--r--lib/sensor_max1247.c82
-rw-r--r--lib/sensor_max1247.h21
-rw-r--r--lib/sensor_mlx90614.c86
-rw-r--r--lib/sensor_mlx90614.h27
-rw-r--r--lib/sensor_pzem.c201
-rw-r--r--lib/sensor_pzem.h48
-rw-r--r--lib/sensor_sdm120.c356
-rw-r--r--lib/sensor_sdm120.h71
-rw-r--r--lib/sensor_sr04.c139
-rw-r--r--lib/sensor_sr04.h26
-rw-r--r--lib/smbus_master.c502
-rw-r--r--lib/smbus_master.h112
-rw-r--r--lib/uart_soft.c434
-rw-r--r--lib/uart_soft.h41
-rw-r--r--lib/usart_enhanced.c167
-rw-r--r--lib/usart_enhanced.h65
-rw-r--r--lib/vfd_hv518.c475
-rw-r--r--lib/vfd_hv518.h40
64 files changed, 0 insertions, 11476 deletions
diff --git a/lib/flash_sdcard.c b/lib/flash_sdcard.c
deleted file mode 100644
index 824d7b8..0000000
--- a/lib/flash_sdcard.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/** library to communicate with an SD card flash memory using the SPI mode (code)
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017
- * @note peripherals used: SPI @ref flash_sdcard_spi
- * @warning all calls are blocking
- * @implements SD Specifications, Part 1, Physical Layer, Simplified Specification, Version 6.00, 10 April 10 2017
- * @todo use SPI unidirectional mode, use DMA, force/wait going to idle state when initializing, filter out reserved values, check sector against size
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/spi.h> // SPI library
-
-#include "global.h" // global utilities
-#include "flash_sdcard.h" // SD card header and definitions
-
-/** @defgroup flash_sdcard_spi SPI used to communication with SD card
- * @{
- */
-#define FLASH_SDCARD_SPI 1 /**< SPI peripheral */
-/** @} */
-
-/** if the card has been initialized successfully */
-static bool initialized = false;
-/** maximum N_AC value (in 8-clock cycles) (time between the response token R1 and data block when reading data (see section 7.5.4)
- * @note this is set to N_CR until we can read CSD (see section 7.2.6)
- */
-static uint32_t n_ac = 8;
-/** is it a Standard Capacity SD card (true), or High Capacity SD cards (false)
- * @note this is indicated in the Card Capacity Status bit or OCR (set for high capacity)
- * @note this is important for addressing: for standard capacity cards the address is the byte number, for high capacity cards it is the 512-byte block number
- */
-static bool sdsc = false;
-/** size of card in bytes */
-static uint64_t sdcard_size = 0;
-/** size of an erase block bytes */
-static uint32_t erase_size = 0;
-
-/** table for CRC-7 calculation for the command messages (see section 4.5)
- * @note faster than calculating the CRC and doesn't cost a lot of space
- * @note generated using pycrc --width=7 --poly=0x09 --reflect-in=false --reflect-out=false --xor-in=0x00 --xor-out=0x00 --generate=table
- */
-static const uint8_t crc7_table[] = {
- 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
- 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
- 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
- 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
- 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
- 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
- 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
- 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
- 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
- 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
- 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
- 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
- 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
- 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
- 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
- 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
-};
-
-/** wait one SPI round (one SPI word)
- */
-static void flash_sdcard_spi_wait(void)
-{
- spi_send(SPI(FLASH_SDCARD_SPI), 0xffff); // send not command token (i.e. starting with 1)
-}
-
-/** read one SPI word
- * @return SPI word read
- */
-static uint16_t flash_sdcard_spi_read(void)
-{
- spi_send(SPI(FLASH_SDCARD_SPI), 0xffff); // send not command token (i.e. starting with 1)
- (void)SPI_DR(SPI(FLASH_SDCARD_SPI)); // clear RXNE flag (by reading previously received data (not done by spi_read or spi_xref)
- while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until Tx buffer is empty before clearing the (previous) RXNE flag
- while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_RXNE)); // wait for next data to be available
- return SPI_DR(SPI(FLASH_SDCARD_SPI)); // return received adat
-}
-
-/** test if card is present
- * @return if card has been detected
- * @note this use the SD card detection mechanism (CD/CS is high card is inserted due to the internal 50 kOhm resistor)
- */
-static bool flash_sdcard_card_detect(void)
-{
- rcc_periph_clock_enable(RCC_SPI_NSS_PORT(FLASH_SDCARD_SPI)); // enable clock for NSS pin port peripheral for SD card CD signal
- gpio_set_mode(SPI_NSS_PORT(FLASH_SDCARD_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set NSS pin as input to read CD signal
- gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // pull pin low to avoid false positive when card in not inserted
- return (0!=gpio_get(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI))); // read CD signal: is card is present the internal 50 kOhm pull-up resistor will override our 1 MOhm pull-down resistor and set the signal high (see section 6.2)
-}
-
-/** transmit command token
- * @param[in] index command index
- * @param[in] argument command argument
- */
-static void flash_sdcard_send_command(uint8_t index, uint32_t argument)
-{
- uint8_t command[5] = { 0x40+(index&0x3f), argument>>24, argument>>16, argument>>8, argument>>0 }; // commands are 5 bytes long, plus 1 bytes of CRC (see section 7.3.1.1)
- uint8_t crc7 = 0x00; // CRC-7 checksum for command message
- // send command
- for (uint8_t i=0; i<LENGTH(command); i++) {
- spi_send(SPI(FLASH_SDCARD_SPI), command[i]); // send data
- crc7 = (crc7_table[((crc7<<1)^command[i])])&0x7f; // update checksum
- }
- spi_send(SPI(FLASH_SDCARD_SPI), (crc7<<1)+0x01); // send CRC value (see section 7.3.1.1)
-}
-
-/** transmit command token and receive response token
- * @param[in] index command index
- * @param[in] argument command argument
- * @param[out] response response data to read (if no error occurred)
- * @param[in] size size of response to read
- * @return response token R1 or 0xff if error occurred or card is not present
- */
-static uint8_t flash_sdcard_command_response(uint8_t index, uint32_t argument, uint8_t* response, size_t size)
-{
- // send command token
- gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS low to select slave and start SPI mode (see section 7.2)
- flash_sdcard_spi_wait(); // wait for N_CS (min. 0, but it works better with 8 clock cycles) before writing command (see section 7.5.1.1)
- flash_sdcard_send_command(index, argument); // send command token
-
- // get response token R1
- uint8_t r1 = 0xff; // response token R1 (see section 7.3.2.1)
- for (uint8_t i=0; i<8 && r1&0x80; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1)
- r1 = flash_sdcard_spi_read(); // get response (see section 7.3.2.1)
- }
- if (0x00==(r1&0xfe) && 0!=size && NULL!=response) { // we have to read a response
- for (size_t i=0; i<size; i++) {
- response[i] = flash_sdcard_spi_read(); // get byte
- }
- }
-
- // end communication
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
- // wait for N_EC (min. 0) before closing communication (see section 7.5.1.1)
- gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
- // wait for N_DS (min. 0) before allowing any further communication (see section 7.5.1.1)
- return r1;
-}
-
-/** read a data block
- * @param[out] data data block to read (if no error occurred)
- * @param[in] size size of response to read (a multiple of 2)
- * @return 0 if succeeded, else control token (0xff for other errors)
- */
-static uint8_t flash_sdcard_read_block(uint8_t* data, size_t size)
-{
- if (size%2 || 0==size || NULL==data) { // can't (and shouldn't) read odd number of bytes
- return 0xff;
- }
-
- uint8_t token = 0xff; // to save the control block token (see section 7.3.3)
- for (uint32_t i=0; i<n_ac && token==0xff; i++) { // wait for N_AC before reading data block (see section 7.5.2.1)
- token = flash_sdcard_spi_read(); // get control token (see section 7.3.3)
- }
- if (0==(token&0xf0)) { // data error token received (see section 7.3.3.3)
- if (0==(token&0x0f)) { // unknown error
- token = 0xff;
- }
- } else if (0xfe==token) { // start block token received (see section 7.3.3.2)
- // switch to 16-bits SPI data frame so we can use use built-in CRC-16
- while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
- spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change format
- spi_set_dff_16bit(SPI(FLASH_SDCARD_SPI)); // set SPI frame to 16 bits
- SPI_CRC_PR(FLASH_SDCARD_SPI) = 0x1021; // set CRC-16-CCITT polynomial for data blocks (x^16+x^12+x^5+1) (see section 7.2.3)
- spi_enable_crc(SPI(FLASH_SDCARD_SPI)); // enable and clear CRC
- spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
- // get block data (ideally use DMA, but switching makes it more complex and this part doesn't take too much time)
- for (size_t i=0; i<size/2; i++) {
- uint16_t word = flash_sdcard_spi_read(); // get word
- data[i*2+0] = (word>>8); // save byte
- data[i*2+1] = (word>>0); // save byte
- }
- flash_sdcard_spi_read(); // read CRC (the CRC after the data block should clear the computed CRC)
- if (SPI_CRC_RXR(FLASH_SDCARD_SPI)) { // CRC is wrong
- token = 0xff;
- } else { // no error occurred
- token = 0;
- }
- // switch back to 8-bit SPI frames
- while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
- spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change format
- spi_disable_crc(SPI(FLASH_SDCARD_SPI)); // disable CRC since we don't use it anymore (and this allows us to clear the CRC next time we use it)
- spi_set_dff_8bit(SPI(FLASH_SDCARD_SPI)); // set SPI frame to 8 bits
- spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
- } else { // start block token not received
- token = 0xff;
- }
-
- return token;
-}
-
-/** write a data block
- * @param[in] data data block to write
- * @param[in] size size of response to read (a multiple of 2)
- * @return data response token (0xff for other errors)
- */
-static uint8_t flash_sdcard_write_block(uint8_t* data, size_t size)
-{
- if (size%2 || 0==size || NULL==data) { // can't (and shouldn't) read odd number of bytes
- return 0xff;
- }
-
- spi_send(SPI(FLASH_SDCARD_SPI), 0xfe); // send start block token (see section 7.3.3.2)
-
- // switch to 16-bits SPI data frame so we can use use built-in CRC-16
- while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
- spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change format
- spi_set_dff_16bit(SPI(FLASH_SDCARD_SPI)); // set SPI frame to 16 bits
- SPI_CRC_PR(FLASH_SDCARD_SPI) = 0x1021; // set CRC-16-CCITT polynomial for data blocks (x^16+x^12+x^5+1) (see section 7.2.3)
- spi_enable_crc(SPI(FLASH_SDCARD_SPI)); // enable and clear CRC
- spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
- // send block data (ideally use DMA, but switching makes it more complex and this part doesn't take too much time)
- for (size_t i=0; i<size/2; i++) {
- uint16_t word = (data[i*2+0]<<8)+data[i*2+1]; // prepare SPI frame
- spi_send(SPI(FLASH_SDCARD_SPI), word); // senf data frame
- }
- spi_set_next_tx_from_crc(SPI(FLASH_SDCARD_SPI)); // send CRC
- // switch back to 8-bit SPI frames
- while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
- spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change format
- spi_set_next_tx_from_buffer(SPI(FLASH_SDCARD_SPI)); // don't send CRC
- spi_disable_crc(SPI(FLASH_SDCARD_SPI)); // disable CRC since we don't use it anymore (and this allows us to clear the CRC next time we use it)
- spi_set_dff_8bit(SPI(FLASH_SDCARD_SPI)); // set SPI frame to 8 bits
- spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
-
- uint8_t token = 0xff;
- while (0x01!=(token&0x11)) {
- token = flash_sdcard_spi_read(); // get data response token (see section 7.3.3.1)
- }
- while (0==flash_sdcard_spi_read()); // wait N_EC while the card is busy programming the data
-
- return token;
-}
-/** get card status
- * @param[out] status SD status (512 bits)
- * @return response token R2 or 0xffff if error occurred or card is not present
- */
-static uint16_t flash_sdcard_status(uint8_t* status)
-{
- // send CMD55 (APP_CMD) to issue following application command (see table 7-4)
- uint8_t r1 = flash_sdcard_command_response(55, 0, NULL, 0); // (see table 7-3)
- if ((r1&0xfe)) { // error occurred, not in idle state
- return false;
- }
-
- // send ACMD13 command
- gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS low to select slave and start SPI mode (see section 7.2)
- flash_sdcard_spi_wait(); // wait for N_CS (min. 0, but it works better with 8 clock cycles) before writing command (see section 7.5.2.1)
- flash_sdcard_send_command(13, 0); // send ACMD13 (SD_STATUS) (see table 7-4)
-
- // get response token R2
- uint16_t r2 = 0xffff; // response token R2 (see section 7.3.2.3)
- for (uint8_t i=0; i<8 && r2&0x8000; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1)
- r2 = (flash_sdcard_spi_read()<<8); // get first byte of response (see section 7.3.2.1)
- }
- if (0==(r2&0x8000)) { // got the first byte
- r2 += flash_sdcard_spi_read(); // read second byte (see 7.3.2.3)
- }
-
- // get data block
- if (0==r2) { // no error
- if (flash_sdcard_read_block(status, 64)) { // read 512 bits data block containing SD status
- r2 |= (1<<11); // set communication error
- }
- }
-
- // end communication
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
- // wait for N_EC (min. 0) before closing communication (see section 7.5.1.1)
- gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
- // wait for N_DS (min. 0) before allowing any further communication (see section 7.5.1.1)
- return r2;
-}
-
-/** transmit command token, receive response token and data block
- * @param[in] index command index
- * @param[in] argument command argument
- * @param[out] data data block to read (if no error occurred)
- * @param[in] size size of data to read (a multiple of 2)
- * @return response token R1 or 0xff if error occurred or card is not present
- */
-static uint8_t flash_sdcard_data_read(uint8_t index, uint32_t argument, uint8_t* data, size_t size)
-{
- if (size%2 || 0==size || NULL==data) { // can't (and shouldn't) read odd number of bytes
- return 0xff;
- }
-
- // send command token
- gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS low to select slave and start SPI mode (see section 7.2)
- flash_sdcard_spi_wait(); // wait for N_CS (min. 0, but it works better with 8 clock cycles) before writing command (see section 7.5.2.1)
- flash_sdcard_send_command(index, argument); // send command token
-
- // get response token R1
- uint8_t r1 = 0xff; // response token R1 (see section 7.3.2.1)
- for (uint8_t i=0; i<8 && r1&0x80; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1)
- r1 = flash_sdcard_spi_read(); // get response (see section 7.3.2.1)
- }
-
- // get data block
- if (0x00==r1) { // we can read a data block
- if (flash_sdcard_read_block(data, size)) { // read data block
- r1 |= (1<<3); // set communication error
- }
- }
-
- // end communication
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
- // wait for N_EC (min. 0) before closing communication (see section 7.5.1.1)
- gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
- // wait for N_DS (min. 0) before allowing any further communication (see section 7.5.1.1)
- return r1;
-}
-
-/** transmit command token, receive response token and write data block
- * @param[in] index command index
- * @param[in] argument command argument
- * @param[out] data data block to write
- * @param[in] size size of data to write (a multiple of 2)
- * @return data response token, or 0xff if error occurred or card is not present
- * @note at the end of a write operation the SD status should be check to ensure no error occurred during programming
- */
-static uint8_t flash_sdcard_data_write(uint8_t index, uint32_t argument, uint8_t* data, size_t size)
-{
- if (size%2 || 0==size || NULL==data) { // can't (and shouldn't) write odd number of bytes
- return 0xff;
- }
-
- // send command token
- gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS low to select slave and start SPI mode (see section 7.2)
- flash_sdcard_spi_wait(); // wait for N_CS (min. 0, but it works better with 8 clock cycles) before writing command (see section 7.5.2.1)
- flash_sdcard_send_command(index, argument); // send command token
-
- // get response token R1
- uint8_t r1 = 0xff; // response token R1 (see section 7.3.2.1)
- for (uint8_t i=0; i<8 && r1&0x80; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1)
- r1 = flash_sdcard_spi_read(); // get response (see section 7.3.2.1)
- }
-
- // write data block
- uint8_t drt = 0xff; // data response token (see section 7.3.3.1)
- if (0x00==r1) { // we have to write the data block
- drt = flash_sdcard_write_block(data, size); // write data block
- }
-
- // end communication
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
- // wait for N_EC (min. 0) before closing communication (see section 7.5.1.1)
- gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
- // wait for N_DS (min. 0) before allowing any further communication (see section 7.5.1.1)
-
- return drt;
-}
-
-bool flash_sdcard_setup(void)
-{
- // reset values
- initialized = false;
- n_ac = 8;
- sdcard_size = 0;
- erase_size = 0;
-
- // check if card is present
- if (!flash_sdcard_card_detect()) {
- return false;
- }
-
- // configure SPI peripheral
- rcc_periph_clock_enable(RCC_SPI_SCK_PORT(FLASH_SDCARD_SPI)); // enable clock for GPIO peripheral for clock signal
- gpio_set_mode(SPI_SCK_PORT(FLASH_SDCARD_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(FLASH_SDCARD_SPI)); // set SCK as output (clock speed will be negotiated later)
- rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(FLASH_SDCARD_SPI)); // enable clock for GPIO peripheral for MOSI signal
- gpio_set_mode(SPI_MOSI_PORT(FLASH_SDCARD_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(FLASH_SDCARD_SPI)); // set MOSI as output
- rcc_periph_clock_enable(RCC_SPI_MISO_PORT(FLASH_SDCARD_SPI)); // enable clock for GPIO peripheral for MISO signal
- gpio_set_mode(SPI_MISO_PORT(FLASH_SDCARD_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SPI_MISO_PIN(FLASH_SDCARD_SPI)); // set MISO as input
- gpio_set(SPI_MISO_PORT(FLASH_SDCARD_SPI), SPI_MISO_PIN(FLASH_SDCARD_SPI)); // pull pin high to detect when the card is not answering (or not present) since responses always start with MSb 0
- rcc_periph_clock_enable(RCC_SPI_NSS_PORT(FLASH_SDCARD_SPI)); // enable clock for GPIO peripheral for NSS (CS) signal
- gpio_set_mode(SPI_NSS_PORT(FLASH_SDCARD_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set NSS (CS) as output
- rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
- rcc_periph_clock_enable(RCC_SPI(FLASH_SDCARD_SPI)); // enable clock for SPI peripheral
- spi_reset(SPI(FLASH_SDCARD_SPI)); // clear SPI values to default
- spi_init_master(SPI(FLASH_SDCARD_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_256, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); // initialise SPI as master, divide clock by 256 (72E6/256=281 kHz) since maximum SD card clock frequency (fOD, see section 7.8/6.6.6) during initial card-identification mode is 400 kHz (maximum SPI PCLK clock is 72 Mhz, depending on which SPI is used), set clock polarity to idle low (not that important), set clock phase to do bit change on falling edge (from SD card spec, polarity depends on clock phase), use 8 bits frames (as per spec), use MSb first
- spi_set_full_duplex_mode(SPI(FLASH_SDCARD_SPI)); // ensure we are in full duplex mode
- spi_enable_software_slave_management(SPI(FLASH_SDCARD_SPI)); // control NSS (CS) manually
- spi_set_nss_high(SPI(FLASH_SDCARD_SPI)); // set NSS high (internally) so we can output
- spi_disable_ss_output(SPI(FLASH_SDCARD_SPI)); // disable NSS output since we control CS manually
- gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
- // sadly we can't use the interrupts as events to sleep (WFE) since sleep disables also communication (e.g. going to sleep until Rx buffer is not empty prevents transmission)
- spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI
-
- // start card-identification (see section 7.2.1/4.2)
- uint8_t r1 = 0;
- // send CMD0 (GO_IDLE_START) to start the card identification (see section 7.2.1)
- r1 = flash_sdcard_command_response(0, 0, NULL, 0); // (see table 7-3)
- if (0x01!=r1) { // error occurred, not in idle state
- return false;
- }
- // send CMD8 (SEND_IF_COND) to inform about voltage (1: 2.7-3.6V, aa: recommended check pattern) (see section 7.2.1)
- uint8_t r7[4] = {0}; // to store response toke R7 (see section 7.3.2.6)
- r1 = flash_sdcard_command_response(8, 0x000001aa, r7, sizeof(r7)); // (see table 7-3)
- if (0x01==r1) { // command supported, in idle state
- if (!(r7[2]&0x1)) { // 2.7-3.6V not supported (see table 5-1)
- return false;
- } else if (0xaa!=r7[3]) { // recommended pattern not returned (see section 4.3.13)
- return false;
- }
- } else if (0x05!=r1) { // illegal command (cards < physical spec v2.0 don't support CMD8) (see section 7.2.1)
- return false;
- }
- // send CMD58 (READ_OCR) to read Operation Conditions Register (see section 7.2.1)
- uint8_t r3[4] = {0}; // to store response token R3 (see section 7.3.2.4)
- r1 = flash_sdcard_command_response(58, 0, r3, sizeof(r3)); // (see table 7-3)
- if (0x01!=r1) { // error occurred, not in idle state
- return false;
- } else if (!(r3[1]&0x30)) { // 3.3V not supported (see table 5-1)
- return false;
- }
- do {
- // send CMD55 (APP_CMD) to issue following application command (see table 7-4)
- r1 = flash_sdcard_command_response(55, 0, NULL, 0); // (see table 7-3)
- if (0x01!=r1) { // error occurred, not in idle state
- return false;
- }
- // send ACMD41 (SD_SEND_OP_COND) with Host Capacity Support (0b: SDSC Only Host, 1b: SDHC or SDXC Supported) (see section 7.2.1)
- r1 = flash_sdcard_command_response(41, 0x40000000, NULL, 0); // (see table 7-4)
- if (r1&0xfe) { // error occurred
- return false;
- }
- } while (0x00!=r1); // wait until card is ready (see section 7.2.1)
- // send CMD58 (READ_OCR) to read Card Capacity Status (CCS) (see section 7.2.1)
- r1 = flash_sdcard_command_response(58, 0, r3, sizeof(r3)); // (see table 7-3)
- if (r1) { // error occurred
- return false;
- }
- // card power up status bit (bit 31) is set when power up is complete (see table 5-1)
- if (0x00==(r3[0]&0x80)) {
- return false;
- }
- sdsc = (0==(r3[0]&0x40)); // CCS is bit 30 in OCR (see table 5-1)
- // now the card identification is complete and we should be in data-transfer mode (see figure 7-1)
-
- // we can switch clock frequency to fPP (max. 25 MHz) (see section 4.3/6.6.6)
- while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
- spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change clock speed
- spi_set_baudrate_prescaler(SPI(FLASH_SDCARD_SPI), SPI_CR1_BR_FPCLK_DIV_4); // set clock speed to 18 MHz (72/4=18, < 25 MHz)
- spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
-
- // send CMD9 (SEND_CSD) to get Card Specific Data (CSD) and calculate N_AC (see section 7.2.6)
- uint8_t csd[16] = {0}; // CSD response (see chapter 7.2.6)
- r1 = flash_sdcard_data_read(9, 0, csd, sizeof(csd)); // (see table 7-3)
- if (r1) { // error occurred
- return false;
- }
- // check if CSD structure version matches capacity (see section 5.3.1)
- if ((sdsc && (csd[0]>>6)) || (!sdsc && 0==(csd[0]>>6))) {
- return false;
- }
- // calculate N_AC value (we use our set minimum frequency 16 MHz to calculate time)
- if (sdsc) { // calculate N_AC using TAAC and NSAC
- static const float TAAC_UNITS[] = {1E-9, 10E-9, 100E-9, 1E-6, 10E-6, 100E-6, 1E-3, 10E-3}; // (see table 5-5)
- static const float TAAC_VALUES[] = {10.0, 1.0, 1.2, 1.3, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 7.0, 8.0}; // (see table 5-5)
- double taac = TAAC_VALUES[(csd[1]>>2)&0xf]*TAAC_UNITS[csd[1]&0x7]; // time in ns
- n_ac=100*((taac*16E6)+(csd[2]*100))/8; // (see section 7.5.4)
- } else { // value is fixed to 100 ms
- n_ac=100E-3*16E6/8;
- }
- // calculate card size
- if (sdsc) { // see section 5.3.2
- uint16_t c_size = (((uint16_t)csd[6]&0x03)<<10)+((uint16_t)csd[7]<<2)+(csd[8]>>6);
- uint8_t c_size_mutl = ((csd[9]&0x03)<<1)+((csd[10]&0x80)>>7);
- uint8_t read_bl_len = (csd[5]&0x0f);
- sdcard_size = ((c_size+1)*(1UL<<(c_size_mutl+2)))*(1UL<<read_bl_len);
- } else { // see section 5.3.3
- uint32_t c_size = ((uint32_t)(csd[7]&0x3f)<<16)+((uint16_t)csd[8]<<8)+csd[9];
- sdcard_size = (c_size+1)*(512<<10);
- }
- // calculate erase size
- if (sdsc) { // see section 5.3.2
- erase_size = (((csd[10]&0x3f)<<1)+((csd[11]&0x80)>>7)+1)<<(((csd[12]&0x03)<<2)+(csd[13]>>6));
- } else {
- uint8_t status[64] = {0}; // SD status (see section 4.10.2)
- uint16_t r2 = flash_sdcard_status(status); // get status (see table 7-4)
- if (r2) { // error occurred
- return false;
- }
- erase_size = (8192UL<<(status[10]>>4)); // calculate erase size (see table 4-44, section 4.10.2.4)
- }
-
- // ensure block length is 512 bytes for SDSC (should be per default) to we match SDHC/SDXC block size
- if (sdsc) {
- r1 = flash_sdcard_command_response(16, 512, NULL, 0); // set block size using CMD16 (SET_BLOCKLEN) (see table 7-3)
- if (r1) { // error occurred
- return false;
- }
- }
-
- // try to switch to high speed mode (see section 7.2.14/4.3.10)
- if (csd[4]&0x40) { // ensure CMD6 is supported by checking if command class 10 is set
- uint32_t n_ac_back = n_ac; // backup N_AC
- n_ac = 100E-3*16E6/8; // temporarily set timeout to 100 ms (see section 4.3.10.1)
- // query access mode (group function 1) to check if high speed is supported (fPP=50MHz at 3.3V, we can be faster)
- uint8_t fnc[64] = {0}; // function status response (see table 4-12)
- r1 = flash_sdcard_data_read(6, 0x00fffff1, fnc, sizeof(fnc)); // check high speed function using CMD6 (SWITCH_FUNC) to check (mode 0) access mode (function group 1) (see table 7-3/4-30)
- if (r1) { // error occurred
- return false;
- }
- if (0x1==(fnc[16]&0x0f)) { // we can to access mode function 1 (see table 4-12)
- r1 = flash_sdcard_data_read(6, 0x80fffff1, fnc, sizeof(fnc)); // switch to high speed function using CMD6 (SWITCH_FUNC) to switch (mode 1) access mode (function group 1) (see table 7-3/4-30)
- if (r1) { // error occurred
- return false;
- }
- if (0x1!=(fnc[16]&0x0f)) { // could not switch to high speed
- return false;
- }
- // we can switch clock frequency to fPP (max. 50 MHz) (see section 6.6.7)
- while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
- while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
- spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change clock speed
- spi_set_baudrate_prescaler(SPI(FLASH_SDCARD_SPI), SPI_CR1_BR_FPCLK_DIV_2); // set clock speed to 36 MHz (72/2=36 < 50 MHz)
- spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
- n_ac_back /= 2; // since we go twice faster the N_AC timeout has to be halved
- }
- n_ac = n_ac_back; // restore N_AC
- }
-
- initialized = true;
-
- return initialized;
-}
-
-uint64_t flash_sdcard_size(void)
-{
- return sdcard_size;
-}
-
-uint32_t flash_sdcard_erase_size(void)
-{
- return erase_size;
-}
-
-bool flash_sdcard_read_data(uint32_t block, uint8_t* data)
-{
- if (NULL==data) {
- return false;
- }
- if (sdsc) { // the address for standard capacity cards must be provided in bytes
- if (block>UINT32_MAX/512) { // check for integer overflow
- return false;
- } else {
- block *= 512; // calculate byte address from block address
- }
- }
- return (0==flash_sdcard_data_read(17, block, data, 512)); // read single data block using CMD17 (READ_SINGLE_BLOCK) (see table 7-3)
-}
-
-bool flash_sdcard_write_data(uint32_t block, uint8_t* data)
-{
- if (NULL==data) {
- return false;
- }
-
- if (sdsc) { // the address for standard capacity cards must be provided in bytes
- if (block>UINT32_MAX/512) { // check for integer overflow
- return false;
- } else {
- block *= 512; // calculate byte address from block address
- }
- }
-
- uint8_t drt = flash_sdcard_data_write(24, block, data, 512); // write single data block using CMD24 (WRITE_SINGLE_BLOCK) (see table 7-3)
- if (0x05!=(drt&0x1f)) { // write block failed
- return false;
- }
-
- // get status to check if programming succeeded
- uint8_t r2[1] = {0}; // to store response token R2 (see section 7.3.2.3)
- uint8_t r1 = flash_sdcard_command_response(13, 0, r2, sizeof(r2)); // get SD status using CMD13 (SEND_STATUS) (see table 7-3)
- if (0x00!=r1) { // error occurred
- return false;
- } else if (r2[0]) { // programming error
- return false;
- }
-
- return true; // programming succeeded
-}
diff --git a/lib/flash_sdcard.h b/lib/flash_sdcard.h
deleted file mode 100644
index 5082275..0000000
--- a/lib/flash_sdcard.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/** library to communicate with an SD card flash memory using the SPI mode
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017
- * @note peripherals used: SPI @ref flash_sdcard_spi
- * @warning all calls are blocking
- */
-#pragma once
-#error not converted for STM32F4
-
-/** setup communication with SD card
- * @return if card has been initialized correctly
- */
-bool flash_sdcard_setup(void);
-/** get size of SD card flash memory
- * @return size of SD card flash memory (in bytes)
- */
-uint64_t flash_sdcard_size(void);
-/** get size of a erase block
- * @return size of a erase block (in bytes)
- */
-uint32_t flash_sdcard_erase_size(void);
-/** read data on flash of SD card
- * @param[in] block address of data to read (in block in 512 bytes unit)
- * @param[out] data data block to read (with a size of 512 bytes)
- * @return if read succeeded
- */
-bool flash_sdcard_read_data(uint32_t block, uint8_t* data);
-/** write data on flash of SD card
- * @param[in] block address of data to write (in block in 512 bytes unit)
- * @param[in] data data block to write (with a size of 512 bytes)
- * @return if write succeeded
- */
-bool flash_sdcard_write_data(uint32_t block, uint8_t* data);
diff --git a/lib/font.c b/lib/font.c
deleted file mode 100644
index a0a9ae6..0000000
--- a/lib/font.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-/** monospace pixel fonts collection (code)
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @date 2018
- */
-#include <stdint.h> // standard integer types
-#include "font.h" // own definitions
-
-/** 8x5 px monospace bitmap font */
-const uint16_t font_king8[FONT_GLYPH_NUMBERS * 5] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, // ' '
- 0x00, 0x00, 0xfa, 0x00, 0x00, // '!'
- 0x00, 0xc0, 0x00, 0xc0, 0x00, // '"'
- 0x28, 0x7c, 0x28, 0x7c, 0x28, // '#'
- 0x24, 0x54, 0xfe, 0x54, 0x48, // '$'
- 0xc6, 0xc8, 0x10, 0x26, 0xc6, // '%'
- 0x6c, 0x92, 0x6a, 0x04, 0x0a, // '&'
- 0x00, 0xc0, 0x00, 0x00, 0x00, // '''
- 0x00, 0x3c, 0x42, 0x81, 0x00, // '('
- 0x00, 0x81, 0x42, 0x3c, 0x00, // ')'
- 0x54, 0x38, 0x7c, 0x38, 0x54, // '*'
- 0x10, 0x10, 0x7c, 0x10, 0x10, // '+'
- 0x00, 0x02, 0x0c, 0x00, 0x00, // ','
- 0x00, 0x10, 0x10, 0x10, 0x00, // '-'
- 0x00, 0x00, 0x0c, 0x00, 0x00, // '.'
- 0x06, 0x08, 0x10, 0x20, 0xc0, // '/'
- 0x7c, 0x8a, 0x92, 0xa2, 0x7c, // '0'
- 0x00, 0x42, 0xfe, 0x02, 0x00, // '1'
- 0x00, 0x86, 0x8a, 0x92, 0x62, // '2'
- 0x00, 0x82, 0x92, 0x92, 0x6c, // '3'
- 0x18, 0x28, 0x48, 0xfe, 0x08, // '4'
- 0xe4, 0xa2, 0xa2, 0xa2, 0x9c, // '5'
- 0x7c, 0x92, 0x92, 0x92, 0x0c, // '6'
- 0x80, 0x8e, 0x90, 0xa0, 0xc0, // '7'
- 0x6c, 0x92, 0x92, 0x92, 0x6c, // '8'
- 0x60, 0x92, 0x92, 0x92, 0x7c, // '9'
- 0x00, 0x00, 0x6c, 0x00, 0x00, // ':'
- 0x00, 0x02, 0x6c, 0x00, 0x00, // ';'
- 0x00, 0x10, 0x28, 0x44, 0x00, // '<'
- 0x00, 0x28, 0x28, 0x28, 0x00, // '='
- 0x00, 0x44, 0x28, 0x10, 0x00, // '>'
- 0x40, 0x80, 0x9a, 0xa0, 0x40, // '?'
- 0x7c, 0x82, 0xba, 0xaa, 0x7a, // '@'
- 0x7e, 0x90, 0x90, 0x90, 0x7e, // 'A'
- 0xfe, 0x92, 0x92, 0x92, 0x6c, // 'B'
- 0x7c, 0x82, 0x82, 0x82, 0x82, // 'C'
- 0xfe, 0x82, 0x82, 0x82, 0x7c, // 'D'
- 0xfe, 0x92, 0x92, 0x92, 0x82, // 'E'
- 0xfe, 0x90, 0x90, 0x90, 0x80, // 'F'
- 0x7c, 0x82, 0x82, 0x92, 0x9c, // 'G'
- 0xfe, 0x10, 0x10, 0x10, 0xfe, // 'H'
- 0x00, 0x82, 0xfe, 0x82, 0x00, // 'I'
- 0x00, 0x82, 0x82, 0xfc, 0x00, // 'J'
- 0xfe, 0x10, 0x28, 0x44, 0x82, // 'K'
- 0xfe, 0x02, 0x02, 0x02, 0x02, // 'L'
- 0xfe, 0x40, 0x20, 0x40, 0xfe, // 'M'
- 0xfe, 0x20, 0x10, 0x08, 0xfe, // 'N'
- 0x7c, 0x82, 0x82, 0x82, 0x7c, // 'O'
- 0xfe, 0x90, 0x90, 0x90, 0x60, // 'P'
- 0x7c, 0x82, 0x8a, 0x84, 0x7a, // 'Q'
- 0xfe, 0x90, 0x98, 0x94, 0x62, // 'R'
- 0x62, 0x92, 0x92, 0x92, 0x8c, // 'S'
- 0x80, 0x80, 0xfe, 0x80, 0x80, // 'T'
- 0xfc, 0x02, 0x02, 0x02, 0xfc, // 'U'
- 0xe0, 0x18, 0x06, 0x18, 0xe0, // 'V'
- 0xf8, 0x06, 0x18, 0x06, 0xf8, // 'W'
- 0xc6, 0x28, 0x10, 0x28, 0xc6, // 'X'
- 0xc0, 0x20, 0x1e, 0x20, 0xc0, // 'Y'
- 0x86, 0x8a, 0x92, 0xa2, 0xc2, // 'Z'
- 0x00, 0xfe, 0x82, 0x82, 0x00, // '['
- 0xc0, 0x20, 0x10, 0x08, 0x06, // '\'
- 0x00, 0x82, 0x82, 0xfe, 0x00, // ']'
- 0x00, 0x20, 0x40, 0x20, 0x00, // '^'
- 0x02, 0x02, 0x02, 0x02, 0x02, // '_'
- 0x00, 0x40, 0x20, 0x00, 0x00, // '`'
- 0x04, 0x2a, 0x2a, 0x1e, 0x00, // 'a'
- 0x7e, 0x12, 0x12, 0x0c, 0x00, // 'b'
- 0x1c, 0x22, 0x22, 0x22, 0x00, // 'c'
- 0x0c, 0x12, 0x12, 0x7e, 0x00, // 'd'
- 0x1c, 0x2a, 0x2a, 0x18, 0x00, // 'e'
- 0x10, 0x3e, 0x50, 0x40, 0x00, // 'f'
- 0x18, 0x25, 0x25, 0x1e, 0x00, // 'g'
- 0x7e, 0x10, 0x10, 0x0e, 0x00, // 'h'
- 0x00, 0x10, 0x5e, 0x00, 0x00, // 'i'
- 0x01, 0x01, 0x5e, 0x00, 0x00, // 'j'
- 0x7e, 0x08, 0x14, 0x22, 0x00, // 'k'
- 0x00, 0x40, 0x7c, 0x02, 0x00, // 'l'
- 0x3e, 0x20, 0x1e, 0x20, 0x1e, // 'm'
- 0x00, 0x3e, 0x20, 0x1e, 0x00, // 'n'
- 0x1c, 0x22, 0x22, 0x1c, 0x00, // 'o'
- 0x3f, 0x24, 0x24, 0x18, 0x00, // 'p'
- 0x18, 0x24, 0x24, 0x3f, 0x00, // 'q'
- 0x3e, 0x10, 0x20, 0x10, 0x00, // 'r'
- 0x12, 0x2a, 0x2a, 0x24, 0x00, // 's'
- 0x7c, 0x12, 0x12, 0x02, 0x00, // 't'
- 0x3c, 0x02, 0x02, 0x3e, 0x00, // 'u'
- 0x38, 0x04, 0x02, 0x04, 0x38, // 'v'
- 0x3c, 0x02, 0x0c, 0x02, 0x3c, // 'w'
- 0x36, 0x08, 0x08, 0x36, 0x00, // 'x'
- 0x30, 0x09, 0x09, 0x3e, 0x00, // 'y'
- 0x26, 0x2a, 0x2a, 0x32, 0x00, // 'z'
- 0x10, 0x6c, 0x82, 0x00, 0x00, // '{'
- 0x00, 0x00, 0xfe, 0x00, 0x00, // '|'
- 0x00, 0x82, 0x6c, 0x10, 0x00, // '}'
- 0x20, 0x40, 0x60, 0x20, 0x40, // '~'
-};
-
-/** 10x6 px monospace bitmap font */
-static const uint16_t font_king10[FONT_GLYPH_NUMBERS * 6] = {
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ' '
- 0x0000, 0x0000, 0x01f6, 0x0000, 0x0000, 0x0000, // '!'
- 0x0000, 0x0180, 0x0000, 0x0180, 0x0000, 0x0000, // '"'
- 0x0028, 0x00fe, 0x0028, 0x00fe, 0x0028, 0x0000, // '#'
- 0x00c4, 0x0124, 0x03fe, 0x0124, 0x0118, 0x0000, // '$'
- 0x00c6, 0x00c8, 0x0010, 0x0020, 0x004c, 0x018c, // '%'
- 0x00dc, 0x0122, 0x0122, 0x00d2, 0x000c, 0x0012, // '&'
- 0x0000, 0x0000, 0x0180, 0x0000, 0x0000, 0x0000, // '''
- 0x0000, 0x0078, 0x0186, 0x0201, 0x0000, 0x0000, // '('
- 0x0000, 0x0201, 0x0186, 0x0078, 0x0000, 0x0000, // ')'
- 0x0090, 0x0060, 0x00f0, 0x0060, 0x0090, 0x0000, // '*'
- 0x0020, 0x0020, 0x00f8, 0x0020, 0x0020, 0x0000, // '+'
- 0x0000, 0x0000, 0x0001, 0x0006, 0x0000, 0x0000, // ','
- 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0000, // '-'
- 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, // '.'
- 0x0003, 0x000c, 0x0030, 0x00c0, 0x0300, 0x0000, // '/'
- 0x01fc, 0x0212, 0x0222, 0x0242, 0x0282, 0x01fc, // '0'
- 0x0000, 0x0040, 0x0080, 0x0100, 0x03fe, 0x0000, // '1'
- 0x0102, 0x0206, 0x020a, 0x0212, 0x0222, 0x01c2, // '2'
- 0x0202, 0x0202, 0x0222, 0x0222, 0x0222, 0x01dc, // '3'
- 0x0030, 0x0050, 0x0090, 0x0110, 0x03fe, 0x0010, // '4'
- 0x03c4, 0x0242, 0x0242, 0x0242, 0x0242, 0x023c, // '5'
- 0x01fc, 0x0222, 0x0222, 0x0222, 0x0222, 0x001c, // '6'
- 0x0200, 0x0200, 0x023e, 0x0240, 0x0280, 0x0300, // '7'
- 0x01dc, 0x0222, 0x0222, 0x0222, 0x0222, 0x01dc, // '8'
- 0x01c0, 0x0222, 0x0222, 0x0222, 0x0222, 0x01fc, // '9'
- 0x0000, 0x0000, 0x00cc, 0x0000, 0x0000, 0x0000, // ':'
- 0x0000, 0x0002, 0x00cc, 0x0000, 0x0000, 0x0000, // ';'
- 0x0000, 0x0020, 0x0050, 0x0088, 0x0104, 0x0000, // '<'
- 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0000, // '='
- 0x0000, 0x0104, 0x0088, 0x0050, 0x0020, 0x0000, // '>'
- 0x0100, 0x0200, 0x021a, 0x0220, 0x0240, 0x0180, // '?'
- 0x0078, 0x0084, 0x0132, 0x014a, 0x014a, 0x00fa, // '@'
- 0x01fe, 0x0220, 0x0220, 0x0220, 0x0220, 0x01fe, // 'A'
- 0x03fe, 0x0222, 0x0222, 0x0222, 0x0222, 0x01dc, // 'B'
- 0x01fc, 0x0202, 0x0202, 0x0202, 0x0202, 0x0202, // 'C'
- 0x03fe, 0x0202, 0x0202, 0x0202, 0x0202, 0x01fc, // 'D'
- 0x03fe, 0x0222, 0x0222, 0x0222, 0x0222, 0x0202, // 'E'
- 0x03fe, 0x0220, 0x0220, 0x0220, 0x0220, 0x0200, // 'F'
- 0x01fc, 0x0202, 0x0202, 0x0202, 0x0222, 0x023c, // 'G'
- 0x03fe, 0x0020, 0x0020, 0x0020, 0x0020, 0x03fe, // 'H'
- 0x0202, 0x0202, 0x03fe, 0x0202, 0x0202, 0x0000, // 'I'
- 0x0202, 0x0202, 0x0202, 0x0204, 0x03f8, 0x0000, // 'J'
- 0x03fe, 0x0020, 0x0050, 0x0088, 0x0104, 0x0202, // 'K'
- 0x03fe, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, // 'L'
- 0x03fe, 0x0100, 0x0080, 0x0080, 0x0100, 0x03fe, // 'M'
- 0x03fe, 0x0080, 0x0040, 0x0020, 0x0010, 0x03fe, // 'N'
- 0x01fc, 0x0202, 0x0202, 0x0202, 0x0202, 0x01fc, // 'O'
- 0x03fe, 0x0220, 0x0220, 0x0220, 0x0220, 0x01c0, // 'P'
- 0x01fc, 0x0202, 0x0202, 0x020a, 0x0204, 0x01fa, // 'Q'
- 0x03fe, 0x0220, 0x0230, 0x0228, 0x0224, 0x01c2, // 'R'
- 0x01c2, 0x0222, 0x0222, 0x0222, 0x0222, 0x021c, // 'S'
- 0x0200, 0x0200, 0x03fe, 0x0200, 0x0200, 0x0000, // 'T'
- 0x03fc, 0x0002, 0x0002, 0x0002, 0x0002, 0x03fc, // 'U'
- 0x03e0, 0x0018, 0x0006, 0x0006, 0x0018, 0x03e0, // 'V'
- 0x03fc, 0x0002, 0x000c, 0x000c, 0x0002, 0x03fc, // 'W'
- 0x038e, 0x0050, 0x0020, 0x0020, 0x0050, 0x038e, // 'X'
- 0x0380, 0x0040, 0x003e, 0x0040, 0x0380, 0x0000, // 'Y'
- 0x020e, 0x0212, 0x0222, 0x0242, 0x0282, 0x0302, // 'Z'
- 0x0000, 0x03fe, 0x0202, 0x0202, 0x0202, 0x0000, // '['
- 0x0000, 0x0300, 0x00c0, 0x0030, 0x000c, 0x0003, // '\'
- 0x0000, 0x0202, 0x0202, 0x0202, 0x03fe, 0x0000, // ']'
- 0x0040, 0x0080, 0x0100, 0x0080, 0x0040, 0x0000, // '^'
- 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, // '_'
- 0x0000, 0x0100, 0x0080, 0x0040, 0x0000, 0x0000, // '`'
- 0x0004, 0x002a, 0x002a, 0x002a, 0x001e, 0x0000, // 'a'
- 0x01fe, 0x0022, 0x0022, 0x0022, 0x001c, 0x0000, // 'b'
- 0x001c, 0x0022, 0x0022, 0x0022, 0x0022, 0x0000, // 'c'
- 0x001c, 0x0022, 0x0022, 0x0022, 0x01fe, 0x0000, // 'd'
- 0x001c, 0x002a, 0x002a, 0x002a, 0x0018, 0x0000, // 'e'
- 0x0020, 0x00fe, 0x0120, 0x0120, 0x0100, 0x0000, // 'f'
- 0x0018, 0x0025, 0x0025, 0x0025, 0x001e, 0x0000, // 'g'
- 0x01fe, 0x0020, 0x0020, 0x0020, 0x001e, 0x0000, // 'h'
- 0x0000, 0x0020, 0x00be, 0x0000, 0x0000, 0x0000, // 'i'
- 0x0000, 0x0001, 0x0021, 0x00be, 0x0000, 0x0000, // 'j'
- 0x01fe, 0x0010, 0x0028, 0x0046, 0x0000, 0x0000, // 'k'
- 0x0000, 0x0100, 0x01fc, 0x0002, 0x0000, 0x0000, // 'l'
- 0x003e, 0x0020, 0x001e, 0x0020, 0x001e, 0x0000, // 'm'
- 0x0000, 0x003e, 0x0020, 0x0020, 0x001e, 0x0000, // 'n'
- 0x001c, 0x0022, 0x0022, 0x0022, 0x001c, 0x0000, // 'o'
- 0x003f, 0x0024, 0x0024, 0x0024, 0x0018, 0x0000, // 'p'
- 0x0018, 0x0024, 0x0024, 0x0024, 0x003f, 0x0000, // 'q'
- 0x003e, 0x0010, 0x0020, 0x0020, 0x0010, 0x0000, // 'r'
- 0x0012, 0x002a, 0x002a, 0x002a, 0x0024, 0x0000, // 's'
- 0x0000, 0x01fc, 0x0042, 0x0042, 0x0002, 0x0000, // 't'
- 0x003c, 0x0002, 0x0002, 0x0002, 0x003e, 0x0000, // 'u'
- 0x0030, 0x000c, 0x0002, 0x000c, 0x0030, 0x0000, // 'v'
- 0x003c, 0x0002, 0x001c, 0x0002, 0x003c, 0x0000, // 'w'
- 0x0022, 0x0014, 0x0008, 0x0014, 0x0022, 0x0000, // 'x'
- 0x0038, 0x0005, 0x0005, 0x0005, 0x003e, 0x0000, // 'y'
- 0x0022, 0x0026, 0x002a, 0x0032, 0x0022, 0x0000, // 'z'
- 0x0000, 0x0020, 0x01dc, 0x0202, 0x0000, 0x0000, // '{'
- 0x0000, 0x0000, 0x03fe, 0x0000, 0x0000, 0x0000, // '|'
- 0x0000, 0x0202, 0x01dc, 0x0020, 0x0000, 0x0000, // '}'
- 0x0020, 0x0040, 0x0040, 0x0020, 0x0020, 0x0040, // '~'
-};
-
-/** 14*9 px monospace bitmap font */
-static const uint16_t font_king14[FONT_GLYPH_NUMBERS * 9] = {
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ' '
- 0x0000, 0x0000, 0x0000, 0x1fe6, 0x1fe6, 0x0000, 0x0000, 0x0000, 0x0000, // '!'
- 0x0000, 0x0e00, 0x0e00, 0x0000, 0x0000, 0x0e00, 0x0e00, 0x0000, 0x0000, // '"'
- 0x0330, 0x0ffc, 0x0ffc, 0x0330, 0x0330, 0x0ffc, 0x0ffc, 0x0330, 0x0000, // '#'
- 0x0718, 0x0f9c, 0x1dce, 0x18c6, 0x3fff, 0x18c6, 0x1cee, 0x0e7c, 0x0638, // '$'
- 0x041e, 0x0e3e, 0x1b70, 0x0ee0, 0x05d0, 0x03b8, 0x076c, 0x3e38, 0x3c10, // '%'
- 0x0e78, 0x1ffe, 0x3186, 0x3186, 0x1fce, 0x0e7c, 0x0038, 0x006c, 0x00c6, // '&'
- 0x0000, 0x0000, 0x0000, 0x0e00, 0x0e00, 0x0000, 0x0000, 0x0000, 0x0000, // '''
- 0x0000, 0x0000, 0x07f8, 0x0ffc, 0x1c0e, 0x3807, 0x3003, 0x0000, 0x0000, // '('
- 0x0000, 0x0000, 0x3003, 0x3807, 0x1c0e, 0x0ffc, 0x03f0, 0x0000, 0x0000, // ')'
- 0x0ccc, 0x06d8, 0x03f0, 0x0ffc, 0x0ffc, 0x03f0, 0x06d8, 0x0ccc, 0x0000, // '*'
- 0x0000, 0x01c0, 0x01c0, 0x07f0, 0x07f0, 0x07f0, 0x01c0, 0x01c0, 0x0000, // '+'
- 0x0000, 0x0000, 0x0003, 0x0007, 0x001e, 0x001c, 0x0000, 0x0000, 0x0000, // ','
- 0x0000, 0x00c0, 0x00c0, 0x00c0, 0x00c0, 0x00c0, 0x00c0, 0x00c0, 0x0000, // '-'
- 0x0000, 0x0000, 0x0000, 0x000c, 0x000c, 0x0000, 0x0000, 0x0000, 0x0000, // '.'
- 0x0003, 0x000f, 0x003c, 0x00f0, 0x03c0, 0x0f00, 0x3c00, 0x3000, 0x0000, // '/'
- 0x0ffc, 0x1ffe, 0x3033, 0x3063, 0x30c3, 0x3183, 0x3303, 0x1ffe, 0x0ffc, // '0'
- 0x0000, 0x0000, 0x0600, 0x0e00, 0x1e00, 0x3fff, 0x3fff, 0x0000, 0x0000, // '1'
- 0x0c07, 0x1c0f, 0x381f, 0x303b, 0x3073, 0x30e3, 0x39c3, 0x1f83, 0x0f03, // '2'
- 0x3003, 0x3003, 0x30c3, 0x30c3, 0x30c3, 0x30c3, 0x39e7, 0x1ffe, 0x0f3c, // '3'
- 0x00f0, 0x01f0, 0x03b0, 0x0730, 0x0e30, 0x1c30, 0x3fff, 0x3fff, 0x0030, // '4'
- 0x3f1c, 0x3f1e, 0x3307, 0x3303, 0x3303, 0x3303, 0x3387, 0x31fe, 0x30fc, // '5'
- 0x0ffc, 0x1ffe, 0x39c7, 0x3183, 0x3183, 0x3183, 0x31c7, 0x30fe, 0x007c, // '6'
- 0x3000, 0x3000, 0x3000, 0x30ff, 0x31ff, 0x3380, 0x3700, 0x3e00, 0x3c00, // '7'
- 0x0f7c, 0x1ffe, 0x39e7, 0x30c3, 0x30c3, 0x30c3, 0x39e7, 0x1ffe, 0x0f3c, // '8'
- 0x0f80, 0x1fc3, 0x38e3, 0x3063, 0x3063, 0x3063, 0x38e7, 0x1ffe, 0x0ffc, // '9'
- 0x0000, 0x0000, 0x0000, 0x071c, 0x071c, 0x0000, 0x0000, 0x0000, 0x0000, // ':'
- 0x0000, 0x0000, 0x0003, 0x0007, 0x071e, 0x071c, 0x0000, 0x0000, 0x0000, // ';'
- 0x0000, 0x01c0, 0x03e0, 0x0770, 0x0e38, 0x1c1c, 0x380e, 0x3006, 0x0000, // '<'
- 0x0000, 0x0318, 0x0318, 0x0318, 0x0318, 0x0318, 0x0318, 0x0318, 0x0000, // '='
- 0x0000, 0x3006, 0x380e, 0x1c1c, 0x0e38, 0x0770, 0x03e0, 0x01c0, 0x0000, // '>'
- 0x0c00, 0x1c00, 0x3800, 0x303b, 0x307b, 0x30e0, 0x39c0, 0x1f80, 0x0f00, // '?'
- 0x07f8, 0x0ffc, 0x1c0e, 0x19e6, 0x1bf6, 0x1b36, 0x1f36, 0x0ff6, 0x07e6, // '@'
- 0x0fff, 0x1fff, 0x38c0, 0x30c0, 0x30c0, 0x30c0, 0x38c0, 0x1fff, 0x0fff, // 'A'
- 0x3fff, 0x3fff, 0x30c3, 0x30c3, 0x30c3, 0x30c3, 0x39e7, 0x1ffe, 0x0f3c, // 'B'
- 0x0ffc, 0x1ffe, 0x3807, 0x3003, 0x3003, 0x3003, 0x3003, 0x3003, 0x3003, // 'C'
- 0x3fff, 0x3fff, 0x3003, 0x3003, 0x3003, 0x3807, 0x1c0e, 0x0ffc, 0x07f8, // 'D'
- 0x3fff, 0x3fff, 0x30c3, 0x30c3, 0x30c3, 0x30c3, 0x30c3, 0x3003, 0x3003, // 'E'
- 0x3fff, 0x3fff, 0x3180, 0x3180, 0x3180, 0x3180, 0x3180, 0x3000, 0x3000, // 'F'
- 0x1ffe, 0x3fff, 0x3807, 0x3003, 0x3003, 0x30c3, 0x30c3, 0x38ff, 0x18fe, // 'G'
- 0x3fff, 0x3fff, 0x00c0, 0x00c0, 0x00c0, 0x00c0, 0x00c0, 0x3fff, 0x3fff, // 'H'
- 0x3003, 0x3003, 0x3003, 0x3fff, 0x3fff, 0x3003, 0x3003, 0x3003, 0x0000, // 'I'
- 0x0000, 0x3003, 0x3007, 0x300e, 0x301c, 0x3ff8, 0x3ff0, 0x0000, 0x0000, // 'J'
- 0x3fff, 0x3fff, 0x01e0, 0x03f0, 0x0738, 0x0e1c, 0x1c0e, 0x3807, 0x3003, // 'K'
- 0x3fff, 0x3fff, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, // 'L'
- 0x3fff, 0x3fff, 0x1c00, 0x0e00, 0x0700, 0x0e00, 0x1c00, 0x3fff, 0x3fff, // 'M'
- 0x3fff, 0x3fff, 0x0700, 0x0380, 0x01c0, 0x00e0, 0x0070, 0x3fff, 0x3fff, // 'N'
- 0x0ffc, 0x1ffe, 0x3807, 0x3003, 0x3003, 0x3003, 0x3807, 0x1ffe, 0x0ffc, // 'O'
- 0x3fff, 0x3fff, 0x3060, 0x3060, 0x3060, 0x3060, 0x38e0, 0x1fc0, 0x0f80, // 'P'
- 0x0ffc, 0x1ffe, 0x3003, 0x3003, 0x301b, 0x301f, 0x300e, 0x1fff, 0x0ffb, // 'Q'
- 0x3fff, 0x3fff, 0x30e0, 0x30f0, 0x30f8, 0x30dc, 0x39ce, 0x1f87, 0x0f03, // 'R'
- 0x0f03, 0x1f83, 0x39c3, 0x30c3, 0x30c3, 0x30c3, 0x30e7, 0x307e, 0x303c, // 'S'
- 0x3000, 0x3000, 0x3000, 0x3fff, 0x3fff, 0x3fff, 0x3000, 0x3000, 0x3000, // 'T'
- 0x3ffc, 0x3ffe, 0x0007, 0x0003, 0x0003, 0x0003, 0x0007, 0x3ffe, 0x3ffc, // 'U'
- 0x3ff0, 0x3ff8, 0x003c, 0x001e, 0x000f, 0x001e, 0x003c, 0x3ff8, 0x3ff0, // 'V'
- 0x3ffc, 0x3ffe, 0x000f, 0x001e, 0x003c, 0x001e, 0x000f, 0x3ffe, 0x3ffc, // 'W'
- 0x3e1f, 0x3f3f, 0x03f0, 0x01e0, 0x00c0, 0x01e0, 0x03f0, 0x3f3f, 0x3e1f, // 'X'
- 0x3f00, 0x3f80, 0x01c0, 0x00ff, 0x007f, 0x00ff, 0x01c0, 0x3f80, 0x3f00, // 'Y'
- 0x300f, 0x301f, 0x303b, 0x3073, 0x30e3, 0x31c3, 0x3383, 0x3f03, 0x3e03, // 'Z'
- 0x0000, 0x0000, 0x3fff, 0x3fff, 0x3003, 0x3003, 0x3003, 0x3003, 0x0000, // '['
- 0x3000, 0x3c00, 0x0f00, 0x03c0, 0x00f0, 0x003c, 0x000f, 0x0003, 0x0000, // '\'
- 0x0000, 0x0000, 0x3003, 0x3003, 0x3003, 0x3003, 0x3fff, 0x3fff, 0x0000, // ']'
- 0x0000, 0x0380, 0x0700, 0x0e00, 0x1c00, 0x0e00, 0x0700, 0x0380, 0x0000, // '^'
- 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, // '_'
- 0x0000, 0x0000, 0x1800, 0x1c00, 0x0e00, 0x0700, 0x0300, 0x0000, 0x0000, // '`'
- 0x0000, 0x001c, 0x01be, 0x01b6, 0x01b6, 0x01b6, 0x01fe, 0x00fe, 0x0000, // 'a'
- 0x0000, 0x0ffe, 0x0ffe, 0x00c6, 0x00c6, 0x00c6, 0x00fe, 0x007c, 0x0000, // 'b'
- 0x0000, 0x00fc, 0x01fe, 0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 0x0000, // 'c'
- 0x0000, 0x007c, 0x00fe, 0x00c6, 0x00c6, 0x00c6, 0x00c6, 0x0ffe, 0x0ffe, // 'd'
- 0x0000, 0x00fc, 0x01fe, 0x01b6, 0x01b6, 0x01b6, 0x01f6, 0x00e0, 0x0000, // 'e'
- 0x0000, 0x00c0, 0x00c0, 0x07fe, 0x0ffe, 0x0cc0, 0x0cc0, 0x0c00, 0x0000, // 'f'
- 0x0000, 0x01e0, 0x03f3, 0x0333, 0x0333, 0x0333, 0x03ff, 0x01fe, 0x0000, // 'g'
- 0x0000, 0x0ffe, 0x0ffe, 0x00c0, 0x00c0, 0x00c0, 0x00fe, 0x007e, 0x0000, // 'h'
- 0x0000, 0x0000, 0x0000, 0x00c0, 0x06fe, 0x06fe, 0x0000, 0x0000, 0x0000, // 'i'
- 0x0000, 0x0000, 0x0003, 0x0187, 0x0dfe, 0x0dfc, 0x0000, 0x0000, 0x0000, // 'j'
- 0x0000, 0x0ffe, 0x0ffe, 0x0078, 0x00fc, 0x01ce, 0x0186, 0x0102, 0x0000, // 'k'
- 0x0000, 0x0800, 0x0ffc, 0x0ffe, 0x0002, 0x0000, 0x0000, 0x0000, 0x0000, // 'l'
- 0x0000, 0x01fe, 0x01fe, 0x0180, 0x00fe, 0x0180, 0x01fe, 0x00fe, 0x0000, // 'm'
- 0x0000, 0x01fe, 0x01fe, 0x0180, 0x0180, 0x0180, 0x01fe, 0x00fe, 0x0000, // 'n'
- 0x0000, 0x00fc, 0x01fe, 0x0186, 0x0186, 0x0186, 0x01fe, 0x00fc, 0x0000, // 'o'
- 0x0000, 0x03ff, 0x03ff, 0x0318, 0x0318, 0x0318, 0x03f8, 0x01f0, 0x0000, // 'p'
- 0x0000, 0x01f0, 0x03f8, 0x0318, 0x0318, 0x0318, 0x03ff, 0x03ff, 0x0000, // 'q'
- 0x0000, 0x01fe, 0x01fe, 0x00c0, 0x0180, 0x0180, 0x01c0, 0x00c0, 0x0000, // 'r'
- 0x0000, 0x00e6, 0x01f6, 0x01b6, 0x01b6, 0x01b6, 0x01be, 0x019c, 0x0000, // 's'
- 0x0000, 0x0000, 0x0ffc, 0x0ffe, 0x00c6, 0x00c6, 0x00c6, 0x0006, 0x0000, // 't'
- 0x0000, 0x01fc, 0x01fe, 0x0006, 0x0006, 0x0006, 0x01fe, 0x01fe, 0x0000, // 'u'
- 0x0000, 0x01f0, 0x01f8, 0x001c, 0x000e, 0x001c, 0x01f8, 0x01f0, 0x0000, // 'v'
- 0x0000, 0x01fc, 0x01fe, 0x0006, 0x007c, 0x0006, 0x01fe, 0x01fc, 0x0000, // 'w'
- 0x0000, 0x01c6, 0x01ee, 0x007c, 0x0038, 0x007c, 0x01ee, 0x01c6, 0x0000, // 'x'
- 0x0000, 0x01f0, 0x01fb, 0x001b, 0x001b, 0x001b, 0x01ff, 0x01fe, 0x0000, // 'y'
- 0x0000, 0x0186, 0x018e, 0x019e, 0x01b6, 0x01e6, 0x01c6, 0x0186, 0x0000, // 'z'
- 0x0000, 0x00c0, 0x01e0, 0x0ffc, 0x1f3e, 0x3807, 0x3003, 0x0000, 0x0000, // '{'
- 0x0000, 0x0000, 0x0000, 0x1fff, 0x1fff, 0x0000, 0x0000, 0x0000, 0x0000, // '|'
- 0x0000, 0x3003, 0x3807, 0x1f3e, 0x0ffc, 0x01e0, 0x00c0, 0x0000, 0x0000, // '}'
- 0x0180, 0x0380, 0x0700, 0x0700, 0x0300, 0x0380, 0x0380, 0x0700, 0x0600, // '~'
-};
-
-/** list of all available fonts */
-const struct font_s fonts[FONT_MAX] = {
- [FONT_KING8] = {
- .width = sizeof(font_king8) / sizeof(font_king8[0]) / FONT_GLYPH_NUMBERS, // 5
- .height = 8,
- .glyphs = font_king8,
- },
- [FONT_KING10] = {
- .width = sizeof(font_king10) / sizeof(font_king10[0]) / FONT_GLYPH_NUMBERS, // 6
- .height = 10,
- .glyphs = font_king10,
- },
- [FONT_KING14] = {
- .width = sizeof(font_king14) / sizeof(font_king14[0]) / FONT_GLYPH_NUMBERS, // 9
- .height = 14,
- .glyphs = font_king14,
- },
-};
diff --git a/lib/font.h b/lib/font.h
deleted file mode 100644
index b70a802..0000000
--- a/lib/font.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-/** monospace pixel fonts collection (API)
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @date 2018
- */
-#pragma once
-
-/** list of available font names */
-enum font_name {
- FONT_KING8, /**< custom 8x5 monospace font */
- FONT_KING10, /**< custom 10x6 monospace font */
- FONT_KING14, /**< custom 14x9 monospace font */
- FONT_MAX, /**< number of fonts available */
-};
-
-/** font structure containing all properties */
-struct font_s {
- uint8_t width; /**< font width in pixels */
- uint8_t height; /**< font height in pixels (max 16) */
- const uint16_t* glyphs; /**< font glyphs: width glyph columns (left to right) times FONT_GLYPH_NUMBERS (MSb is glyph top pixel) */
-};
-
-/** number of available glyphs (starting with ' ' and ending with '~') */
-#define FONT_GLYPH_NUMBERS 95
-
-/** list of all available fonts */
-extern const struct font_s fonts[FONT_MAX];
diff --git a/lib/i2c_master.c b/lib/i2c_master.c
deleted file mode 100644
index bf19c65..0000000
--- a/lib/i2c_master.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/** library to communicate using I²C as master
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: I2C
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/cm3/systick.h> // SysTick library
-#include <libopencm3/cm3/assert.h> // assert utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/i2c.h> // I²C library
-
-/* own libraries */
-#include "global.h" // global utilities
-#include "i2c_master.h" // I²C header and definitions
-
-/** @defgroup i2c_master_i2c I²C peripheral used for I²C communication
- * @{
- */
-#define I2C_MASTER_I2C 1 /**< I²C peripheral ID */
-#define I2C_MASTER_SCL PB6 /**< GPIO pin for I²C SCL */
-#define I2C_MASTER_SDA PB7 /**< GPIO pin for I²C SDA */
-#define I2C_MASTER_AF GPIO_AF4 /**< alternate function for GPIO pin */
-/** @} */
-
-void i2c_master_setup(uint16_t frequency)
-{
- // configure I²C peripheral
- rcc_periph_clock_enable(GPIO_RCC(I2C_MASTER_SCL)); // enable clock for I²C I/O peripheral
- gpio_set(GPIO_PORT(I2C_MASTER_SCL), GPIO_PIN(I2C_MASTER_SCL)); // already put signal high to avoid small pulse
- gpio_mode_setup(GPIO_PORT(I2C_MASTER_SCL), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(I2C_MASTER_SCL)); // set SCL pin to alternate function
- gpio_set_output_options(GPIO_PORT(I2C_MASTER_SCL), GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN(I2C_MASTER_SCL)); // set SCL pin output as open-drain
- gpio_set_af(GPIO_PORT(I2C_MASTER_SCL), I2C_MASTER_AF, GPIO_PIN(I2C_MASTER_SCL)); // set alternate function to I²C SCL pin
- rcc_periph_clock_enable(GPIO_RCC(I2C_MASTER_SDA)); // enable clock for I²C I/O peripheral
- gpio_set(GPIO_PORT(I2C_MASTER_SDA), GPIO_PIN(I2C_MASTER_SDA)); // already put signal high to avoid small pulse
- gpio_mode_setup(GPIO_PORT(I2C_MASTER_SDA), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(I2C_MASTER_SDA)); // set SDA pin to alternate function
- gpio_set_output_options(GPIO_PORT(I2C_MASTER_SDA), GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN(I2C_MASTER_SDA)); // set SDA pin output as open-drain
- gpio_set_af(GPIO_PORT(I2C_MASTER_SDA), I2C_MASTER_AF, GPIO_PIN(I2C_MASTER_SDA)); // set alternate function to I²C SDA pin
- rcc_periph_clock_enable(RCC_I2C(I2C_MASTER_I2C)); // enable clock for I²C peripheral
- i2c_reset(I2C(I2C_MASTER_I2C)); // reset peripheral domain
- i2c_peripheral_disable(I2C(I2C_MASTER_I2C)); // I²C needs to be disable to be configured
- I2C_CR1(I2C(I2C_MASTER_I2C)) |= I2C_CR1_SWRST; // reset peripheral
- I2C_CR1(I2C(I2C_MASTER_I2C)) &= ~I2C_CR1_SWRST; // clear peripheral reset
- if (0 == frequency) { // don't allow null frequency
- frequency = 1;
- } else if (frequency > 400) { // limit frequency to 400 kHz
- frequency = 400;
- }
- i2c_set_clock_frequency(I2C(I2C_MASTER_I2C), rcc_apb1_frequency / 1000000); // configure the peripheral clock to the APB1 freq (where it is connected to)
- if (frequency > 100) { // use fast mode for frequencies over 100 kHz
- i2c_set_fast_mode(I2C(I2C_MASTER_I2C)); // set fast mode (Fm)
- i2c_set_ccr(I2C(I2C_MASTER_I2C), rcc_apb1_frequency / (frequency * 1000 * 2)); // set Thigh/Tlow to generate frequency (fast duty not used)
- i2c_set_trise(I2C(I2C_MASTER_I2C), (300 / (1000 / (rcc_apb1_frequency / 1000000))) + 1); // max rise time for Fm mode (< 400) kHz is 300 ns
- } else { // use fast mode for frequencies below 100 kHz
- i2c_set_standard_mode(I2C(I2C_MASTER_I2C)); // set standard mode (Sm)
- i2c_set_ccr(I2C(I2C_MASTER_I2C), rcc_apb1_frequency / (frequency * 1000 * 2)); // set Thigh/Tlow to generate frequency of 100 kHz
- i2c_set_trise(I2C(I2C_MASTER_I2C), (1000 / (1000 / (rcc_apb1_frequency / 1000000))) + 1); // max rise time for Sm mode (< 100 kHz) is 1000 ns (~1 MHz)
- }
- i2c_peripheral_enable(I2C(I2C_MASTER_I2C)); // enable I²C after configuration completed
-}
-
-void i2c_master_release(void)
-{
- i2c_reset(I2C(I2C_MASTER_I2C)); // reset I²C peripheral configuration
- i2c_peripheral_disable(I2C(I2C_MASTER_I2C)); // disable I²C peripheral
- rcc_periph_clock_disable(RCC_I2C(I2C_MASTER_I2C)); // disable clock for I²C peripheral
- gpio_mode_setup(GPIO_PORT(I2C_MASTER_SCL), GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN(I2C_MASTER_SCL)); // set SCL pin back to input
- gpio_mode_setup(GPIO_PORT(I2C_MASTER_SDA), GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN(I2C_MASTER_SDA)); // set SDA pin back to input
-}
-
-bool i2c_master_check_signals(void)
-{
- // enable GPIOs to read SDA and SCL
- rcc_periph_clock_enable(GPIO_RCC(I2C_MASTER_SDA)); // enable clock for I²C I/O peripheral
- rcc_periph_clock_enable(GPIO_RCC(I2C_MASTER_SCL)); // enable clock for I²C I/O peripheral
-
- // pull SDA and SDC low to check if there are pull-up resistors
- const uint32_t sda_moder = GPIO_MODER(GPIO_PORT(I2C_MASTER_SDA)); // backup port configuration
- const uint32_t sda_pupdr = GPIO_PUPDR(GPIO_PORT(I2C_MASTER_SDA)); // backup port configuration
- const uint32_t scl_moder = GPIO_MODER(GPIO_PORT(I2C_MASTER_SCL)); // backup port configuration
- const uint32_t scl_pupdr = GPIO_PUPDR(GPIO_PORT(I2C_MASTER_SCL)); // backup port configuration
- gpio_mode_setup(GPIO_PORT(I2C_MASTER_SDA), GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN(I2C_MASTER_SDA)); // set SDA to input and pull down (weak) to check if there is an external pull up (strong)
- gpio_mode_setup(GPIO_PORT(I2C_MASTER_SCL), GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN(I2C_MASTER_SCL)); // set SCL to input and pull down (weak) to check if there is an external pull up (strong)
- sleep_us(100); // let signal settle
- const bool to_return = (gpio_get(GPIO_PORT(I2C_MASTER_SCL), GPIO_PIN(I2C_MASTER_SCL)) && gpio_get(GPIO_PORT(I2C_MASTER_SDA), GPIO_PIN(I2C_MASTER_SDA))); // check if the signals are still pulled high by external stronger pull-up resistors
- GPIO_MODER(GPIO_PORT(I2C_MASTER_SDA)) = sda_moder; // restore port configuration
- GPIO_PUPDR(GPIO_PORT(I2C_MASTER_SDA)) = sda_pupdr; // restore port configuration
- GPIO_MODER(GPIO_PORT(I2C_MASTER_SCL)) = scl_moder; // restore port configuration
- GPIO_PUPDR(GPIO_PORT(I2C_MASTER_SCL)) = scl_pupdr; // restore port configuration
-
- return to_return;
-}
-
-void i2c_master_reset(void)
-{
- i2c_peripheral_disable(I2C(I2C_MASTER_I2C)); // disable I²C peripheral
- I2C_CR1(I2C(I2C_MASTER_I2C)) |= I2C_CR1_SWRST; // reset device
- I2C_CR1(I2C(I2C_MASTER_I2C)) &= ~I2C_CR1_SWRST; // reset device
- i2c_peripheral_enable(I2C(I2C_MASTER_I2C)); // re-enable device
-}
-
-enum i2c_master_rc i2c_master_start(void)
-{
- bool retry = true; // retry after reset if first try failed
- enum i2c_master_rc to_return; // return code
- uint16_t sr1; // read register once, since reading/writing other registers or other events clears some flags
-try:
- to_return = I2C_MASTER_RC_NONE; // return code
- // send (re-)start condition
- if (I2C_CR1(I2C(I2C_MASTER_I2C)) & (I2C_CR1_START | I2C_CR1_STOP)) { // ensure start or stop operations are not in progress
- return I2C_MASTER_RC_START_STOP_IN_PROGESS;
- }
- // prepare timer in case the peripheral hangs on sending stop condition (see errata 2.14.4 Wrong behavior of I²C peripheral in master mode after a misplaced Stop)
- systick_counter_disable(); // disable SysTick to reconfigure it
- systick_set_frequency(500, rcc_ahb_frequency); // set timer to 2 ms (that should be long enough to send a start condition)
- systick_clear(); // reset SysTick (set to 0)
- systick_interrupt_disable(); // disable interrupt to prevent ISR to read the flag
- systick_get_countflag(); // reset flag (set when counter is going for 1 to 0)
- i2c_send_start(I2C(I2C_MASTER_I2C)); // send start condition to start transaction
- bool timeout = false; // remember if the timeout has been reached
- systick_counter_enable(); // start timer
- while ((I2C_CR1(I2C(I2C_MASTER_I2C)) & I2C_CR1_START) && !((sr1 = I2C_SR1(I2C(I2C_MASTER_I2C))) & (I2C_SR1_BERR | I2C_SR1_ARLO)) && !timeout) { // wait until start condition has been accepted and cleared
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- sr1 = I2C_SR1(I2C(I2C_MASTER_I2C)); // be sure to get the current value
- if (sr1 & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- to_return = I2C_MASTER_RC_BUS_ERROR;
- }
- while (!((sr1 = I2C_SR1(I2C(I2C_MASTER_I2C))) & (I2C_SR1_SB | I2C_SR1_BERR | I2C_SR1_ARLO)) && !timeout && I2C_MASTER_RC_NONE == to_return) { // wait until start condition is transmitted
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- sr1 = I2C_SR1(I2C(I2C_MASTER_I2C)); // be sure to get the current value
- if (sr1 & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
- to_return = I2C_MASTER_RC_BUS_ERROR;
- } else if (!(sr1 & I2C_SR1_SB)) { // the start bit has not been set although we the peripheral is not busy anymore
- to_return = I2C_MASTER_RC_BUS_ERROR;
- } else if (!(sr1 & I2C_SR2_MSL)) { // verify if in master mode
- to_return = I2C_MASTER_RC_NOT_MASTER;
- } else if (timeout) { // timeout has been reached, i.e. the peripheral hangs
- to_return = I2C_MASTER_RC_NOT_MASTER;
- }
-
- if (I2C_MASTER_RC_NOT_MASTER == to_return && retry) { // error happened
- retry = false; // don't retry a second time
- I2C_CR1(I2C(I2C_MASTER_I2C)) |= I2C_CR1_SWRST; // assert peripheral reset
- I2C_CR1(I2C(I2C_MASTER_I2C)) &= ~I2C_CR1_SWRST; // release peripheral reset
- goto try;
- }
- systick_counter_disable(); // we don't need to timer anymore
- return to_return;
-}
-
-/** wait until stop is sent and bus is released
- * @return I²C return code
- */
-static enum i2c_master_rc i2c_master_wait_stop(void)
-{
- enum i2c_master_rc to_return = I2C_MASTER_RC_NONE; // return code
- // prepare timer in case the peripheral hangs on sending stop condition (see errata 2.14.4 Wrong behavior of I²C peripheral in master mode after a misplaced Stop)
- systick_counter_disable(); // disable SysTick to reconfigure it
- systick_set_frequency(500, rcc_ahb_frequency); // set timer to 2 ms (that should be long enough to send a stop condition)
- systick_clear(); // reset SysTick (set to 0)
- systick_interrupt_disable(); // disable interrupt to prevent ISR to read the flag
- systick_get_countflag(); // reset flag (set when counter is going for 1 to 0)
- bool timeout = false; // remember if the timeout has been reached
- systick_counter_enable(); // start timer
- while ((I2C_CR1(I2C(I2C_MASTER_I2C)) & I2C_CR1_STOP) && !(I2C_SR1(I2C(I2C_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) && !timeout) { // wait until stop condition is accepted and cleared
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- if (I2C_SR1(I2C(I2C_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- to_return = I2C_MASTER_RC_BUS_ERROR;
- }
- while ((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) && !(I2C_SR1(I2C(I2C_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) && !timeout) { // wait until bus released (non master mode)
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- if (I2C_SR1(I2C(I2C_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- to_return = I2C_MASTER_RC_BUS_ERROR;
- }
- while ((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY) && !(I2C_SR1(I2C(I2C_MASTER_I2C)) & (I2C_SR1_BERR)) && !timeout) { // wait until peripheral is not busy anymore
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- if (I2C_SR1(I2C(I2C_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- to_return = I2C_MASTER_RC_BUS_ERROR;
- }
- while ((0 == gpio_get(GPIO_PORT(I2C_MASTER_SCL), GPIO_PIN(I2C_MASTER_SCL)) || 0 == gpio_get(GPIO_PORT(I2C_MASTER_SDA), GPIO_PIN(I2C_MASTER_SDA))) && !timeout) { // wait until lines are really high again
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
-
- if (timeout) { // I2C_CR1_STOP could also be used to detect a timeout, but I'm not sure when
- if (I2C_MASTER_RC_NONE == to_return) {
- to_return = I2C_MASTER_RC_TIMEOUT; // indicate timeout only when no more specific error has occurred
- }
- I2C_CR1(I2C(I2C_MASTER_I2C)) |= I2C_CR1_SWRST; // assert peripheral reset
- I2C_CR1(I2C(I2C_MASTER_I2C)) &= ~I2C_CR1_SWRST; // release peripheral reset
- }
- systick_counter_disable(); // we don't need to timer anymore
- return to_return;
-}
-
-enum i2c_master_rc i2c_master_stop(void)
-{
- // sanity check
- if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY)) { // release is not busy
- return I2C_MASTER_RC_NONE; // bus has probably already been released
- }
- if (I2C_CR1(I2C(I2C_MASTER_I2C)) & (I2C_CR1_START)) { // ensure start is not in progress
- return I2C_MASTER_RC_START_STOP_IN_PROGESS;
- }
-
- if (!((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_TRA))) { // if we are in receiver mode
- i2c_disable_ack(I2C(I2C_MASTER_I2C)); // disable ACK to be able to close the communication
- }
-
- if (!(I2C_CR1(I2C(I2C_MASTER_I2C)) & (I2C_CR1_STOP))) { // ensure stop operations is not in progress
- i2c_send_stop(I2C(I2C_MASTER_I2C)); // send stop to release bus
- }
- return i2c_master_wait_stop();
-}
-
-enum i2c_master_rc i2c_master_select_slave(uint16_t slave, bool address_10bit, bool write)
-{
- enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I²C return codes
- uint16_t sr1, sr2; // read register once, since reading/writing other registers or other events clears some flags
-
- if (!((sr1 = I2C_SR1(I2C(I2C_MASTER_I2C))) & I2C_SR1_SB)) { // start condition has not been sent
- rc = i2c_master_start(); // send start condition
- if (I2C_MASTER_RC_NONE != rc) {
- return rc;
- }
- }
- if (!((sr2 = I2C_SR2(I2C(I2C_MASTER_I2C))) & I2C_SR2_MSL)) { // I²C device is not in master mode
- return I2C_MASTER_RC_NOT_MASTER;
- }
-
- // select slave
- I2C_SR1(I2C(I2C_MASTER_I2C)) &= ~(I2C_SR1_AF); // clear acknowledgement failure
- if (!address_10bit) { // 7-bit address
- i2c_send_7bit_address(I2C(I2C_MASTER_I2C), slave, write ? I2C_WRITE : I2C_READ); // select slave, with read/write flag
- while (!((sr1 = I2C_SR1(I2C(I2C_MASTER_I2C))) & (I2C_SR1_ADDR | I2C_SR1_AF | I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until address is transmitted
- if (sr1 & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- return I2C_MASTER_RC_BUS_ERROR;
- }
- if (sr1 & I2C_SR1_AF) { // address has not been acknowledged
- return I2C_MASTER_RC_NAK;
- }
- } else { // 10-bit address
- // send first part of address
- I2C_DR(I2C(I2C_MASTER_I2C)) = 11110000 | (((slave >> 8 ) & 0x3) << 1); // send first header (11110xx0, where xx are 2 MSb of slave address)
- while (!((sr1 = I2C_SR1(I2C(I2C_MASTER_I2C))) & (I2C_SR1_ADD10 | I2C_SR1_AF | I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until first part of address is transmitted
- if (sr1 & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- return I2C_MASTER_RC_BUS_ERROR;
- }
- if (sr1 & I2C_SR1_AF) { // address has not been acknowledged
- return I2C_MASTER_RC_NAK;
- }
- // send second part of address
- I2C_SR1(I2C(I2C_MASTER_I2C)) &= ~(I2C_SR1_AF); // clear acknowledgement failure
- I2C_DR(I2C(I2C_MASTER_I2C)) = (slave & 0xff); // send remaining of address
- while (!((sr1 = I2C_SR1(I2C(I2C_MASTER_I2C))) & (I2C_SR1_ADDR | I2C_SR1_AF | I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until remaining part of address is transmitted
- if (sr1 & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- return I2C_MASTER_RC_BUS_ERROR;
- }
- if (sr1 & I2C_SR1_AF) { // address has not been acknowledged
- return I2C_MASTER_RC_NAK;
- }
- // go into receive mode if necessary
- if (!write) {
- rc = i2c_master_start(); // send start condition
- if (I2C_MASTER_RC_NONE != rc) {
- return rc;
- }
- // send first part of address with receive flag
- I2C_SR1(I2C(I2C_MASTER_I2C)) &= ~(I2C_SR1_AF); // clear acknowledgement failure
- I2C_DR(I2C(I2C_MASTER_I2C)) = 11110001 | (((slave >> 8) & 0x3) << 1); // send header (11110xx1, where xx are 2 MSb of slave address)
- while (!((sr1 = I2C_SR1(I2C(I2C_MASTER_I2C))) & (I2C_SR1_ADDR | I2C_SR1_AF | I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until remaining part of address is transmitted
- if (sr1 & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- return I2C_MASTER_RC_BUS_ERROR;
- }
- if (sr1 & I2C_SR1_AF) { // address has not been acknowledged
- return I2C_MASTER_RC_NAK;
- }
- }
- }
- // do not check I2C_SR2_TRA to verify if we really are in transmit or receive mode since reading SR2 also clears ADDR and starting the read/write transaction
- return I2C_MASTER_RC_NONE;
-}
-
-enum i2c_master_rc i2c_master_read(uint8_t* data, size_t data_size)
-{
- // sanity check
- if (NULL == data || 0 == data_size) { // no data to read
- return I2C_MASTER_RC_NONE;
- }
-
- // I²C start condition check
- uint16_t sr1 = I2C_SR1(I2C(I2C_MASTER_I2C)); // read once
- if (!(sr1 & I2C_SR1_ADDR)) { // no slave have been selected
- return I2C_MASTER_RC_NOT_READY;
- }
- if (sr1 & I2C_SR1_AF) { // check if the previous transaction went well
- return I2C_MASTER_RC_NOT_READY;
- }
-
- // prepare (N)ACK (EV6_3 in RM0008)
- if (1 == data_size) {
- i2c_disable_ack(I2C(I2C_MASTER_I2C)); // NACK after first byte
- } else {
- i2c_enable_ack(I2C(I2C_MASTER_I2C)); // NAK after next byte
- }
- uint16_t sr2 = I2C_SR2(I2C(I2C_MASTER_I2C)); // reading SR2 will also also clear ADDR in SR1 and start the transaction
- if (!(sr2 & I2C_SR2_MSL)) { // I²C device is not master
- return I2C_MASTER_RC_NOT_MASTER;
- }
- if ((sr2 & I2C_SR2_TRA)) { // I²C device not in receiver mode
- return I2C_MASTER_RC_NOT_RECEIVE;
- }
-
- // read data
- for (size_t i = 0; i < data_size; i++) { // read bytes
- // set (N)ACK (EV6_3, EV6_1)
- if (1 == data_size - i) { // prepare to sent NACK for last byte
- i2c_send_stop(I2C(I2C_MASTER_I2C)); // already indicate we will send a stop (required to not send an ACK, and this must happen before the byte is transferred, see errata)
- i2c_nack_current(I2C(I2C_MASTER_I2C)); // (N)ACK current byte
- i2c_disable_ack(I2C(I2C_MASTER_I2C)); // NACK received to stop slave transmission
- } else if (2 == data_size - i) { // prepare to sent NACK for second last byte
- i2c_nack_next(I2C(I2C_MASTER_I2C)); // NACK next byte
- i2c_disable_ack(I2C(I2C_MASTER_I2C)); // NACK received to stop slave transmission
- } else {
- i2c_enable_ack(I2C(I2C_MASTER_I2C)); // ACK received byte to continue slave transmission
- }
- while (!((sr1 = I2C_SR1(I2C(I2C_MASTER_I2C))) & (I2C_SR1_RxNE | I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until byte has been received
- if (sr1 & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
- return I2C_MASTER_RC_BUS_ERROR;
- }
- data[i] = i2c_get_data(I2C(I2C_MASTER_I2C)); // read received byte
- }
-
- return i2c_master_wait_stop();
-}
-
-enum i2c_master_rc i2c_master_write(const uint8_t* data, size_t data_size)
-{
- // sanity check
- if (NULL == data || 0 == data_size) { // no data to write
- return I2C_MASTER_RC_NONE;
- }
-
- // I²C start condition check
- uint16_t sr1 = I2C_SR1(I2C(I2C_MASTER_I2C)); // read once
- if (!(sr1 & I2C_SR1_ADDR)) { // no slave have been selected
- return I2C_MASTER_RC_NOT_READY;
- }
- if (sr1 & I2C_SR1_AF) { // check if the previous transaction went well
- return I2C_MASTER_RC_NOT_READY;
- }
-
- // master check
- uint16_t sr2 = I2C_SR2(I2C(I2C_MASTER_I2C)); // reading SR2 will also also clear ADDR in SR1 and start the transaction
- if (!(sr2 & I2C_SR2_MSL)) { // I²C device is not master
- return I2C_MASTER_RC_NOT_MASTER;
- }
- if (!(sr2 & I2C_SR2_TRA)) { // I²C device not in transmitter mode
- return I2C_MASTER_RC_NOT_TRANSMIT;
- }
-
- // write data
- for (size_t i = 0; i < data_size; i++) { // write bytes
- I2C_SR1(I2C(I2C_MASTER_I2C)) &= ~(I2C_SR1_AF); // clear acknowledgement failure
- i2c_send_data(I2C(I2C_MASTER_I2C), data[i]); // send byte to be written in memory
- while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & (I2C_SR1_TxE | I2C_SR1_AF)) && !(I2C_SR1(I2C(I2C_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until byte has been transmitted
- if (I2C_SR1(I2C(I2C_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- return I2C_MASTER_RC_BUS_ERROR;
- }
- if (I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_AF) { // data has not been acknowledged
- return I2C_MASTER_RC_NAK;
- }
- }
-
- return I2C_MASTER_RC_NONE;
-}
-
-enum i2c_master_rc i2c_master_slave_read(uint16_t slave, bool address_10bit, uint8_t* data, size_t data_size)
-{
- enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I²C return codes
- rc = i2c_master_start(); // send (re-)start condition
- if (I2C_MASTER_RC_NONE != rc) {
- return rc;
- }
- rc = i2c_master_select_slave(slave, address_10bit, false); // select slave to read
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
- if (NULL != data && data_size > 0) { // only read data if needed
- rc = i2c_master_read(data, data_size); // read data (includes stop)
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
- } else {
- i2c_master_stop(); // sent stop condition
- }
-
- rc = I2C_MASTER_RC_NONE; // all went well
-error:
- if (I2C_MASTER_RC_NONE != rc) {
- i2c_master_stop(); // sent stop condition
- }
- return rc;
-}
-
-enum i2c_master_rc i2c_master_slave_write(uint16_t slave, bool address_10bit, const uint8_t* data, size_t data_size)
-{
- enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I²C return codes
- rc = i2c_master_start(); // send (re-)start condition
- if (I2C_MASTER_RC_NONE != rc) {
- return rc;
- }
- rc = i2c_master_select_slave(slave, address_10bit, true); // select slave to write
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
- if (NULL != data && data_size > 0) { // write data only is some is available
- rc = i2c_master_write(data, data_size); // write data
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
- }
-
- rc = I2C_MASTER_RC_NONE; // all went well
-error:
- i2c_master_stop(); // sent stop condition
- return rc;
-}
-
-enum i2c_master_rc i2c_master_address_read(uint16_t slave, bool address_10bit, const uint8_t* address, size_t address_size, uint8_t* data, size_t data_size)
-{
- enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I²C return codes
- rc = i2c_master_start(); // send (re-)start condition
- if (I2C_MASTER_RC_NONE != rc) {
- return rc;
- }
- rc = i2c_master_select_slave(slave, address_10bit, true); // select slave to write
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
-
- // write address
- if (NULL != address && address_size > 0) {
- rc = i2c_master_write(address, address_size); // send memory address
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
- }
- // read data
- if (NULL != data && data_size > 0) {
- rc = i2c_master_start(); // send re-start condition
- if (I2C_MASTER_RC_NONE != rc) {
- return rc;
- }
- rc = i2c_master_select_slave(slave, address_10bit, false); // select slave to read
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
- rc = i2c_master_read(data, data_size); // read memory (includes stop)
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
- } else {
- i2c_master_stop(); // sent stop condition
- }
-
- rc = I2C_MASTER_RC_NONE;
-error:
- if (I2C_MASTER_RC_NONE != rc) { // only send stop on error
- i2c_master_stop(); // sent stop condition
- }
- return rc;
-}
-
-enum i2c_master_rc i2c_master_address_write(uint16_t slave, bool address_10bit, const uint8_t* address, size_t address_size, const uint8_t* data, size_t data_size)
-{
- if (SIZE_MAX - address_size < data_size) { // prevent integer overflow
- return I2C_MASTER_RC_OTHER;
- }
- if (address_size + data_size > 10 * 1024) { // we won't enough RAM
- return I2C_MASTER_RC_OTHER;
- }
- if (address_size > 0 && NULL == address) {
- return I2C_MASTER_RC_OTHER;
- }
- if (data_size > 0 && NULL == data) {
- return I2C_MASTER_RC_OTHER;
- }
-
- uint8_t buffer[address_size + data_size];
- enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I²C return codes
- rc = i2c_master_start(); // send (re-)start condition
- if (I2C_MASTER_RC_NONE != rc) {
- return rc;
- }
- rc = i2c_master_select_slave(slave, address_10bit, true); // select slave to write
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
-
- // we can't send the address then the data size short address will cause a stop (because of how crappy the STM32F10x I²C peripheral is)
- if (address) {
- for (size_t i = 0; i < address_size; i++) {
- buffer[i] = address[i];
- }
- }
- if (data) {
- for (size_t i = 0; i < data_size; i++) {
- buffer[address_size + i] = data[i];
- }
- }
- rc = i2c_master_write(buffer, address_size + data_size); // send memory address
- if (I2C_MASTER_RC_NONE != rc) {
- goto error;
- }
-
-error:
- rc = i2c_master_stop(); // sent stop condition
- return rc;
-}
diff --git a/lib/i2c_master.h b/lib/i2c_master.h
deleted file mode 100644
index 654b19c..0000000
--- a/lib/i2c_master.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/** library to communicate using I²C as master
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: I²C @ref i2c_master_i2c
- */
-#pragma once
-
-/** I²C return codes */
-enum i2c_master_rc {
- I2C_MASTER_RC_NONE = 0, /**< no error */
- I2C_MASTER_RC_START_STOP_IN_PROGESS, /**< a start or stop condition is already in progress */
- I2C_MASTER_RC_NOT_MASTER, /**< not in master mode */
- I2C_MASTER_RC_NOT_TRANSMIT, /**< not in transmit mode */
- I2C_MASTER_RC_NOT_RECEIVE, /**< not in receive mode */
- I2C_MASTER_RC_NOT_READY, /**< slave is not read (previous operations has been NACKed) */
- I2C_MASTER_RC_NAK, /**< not acknowledge received */
- I2C_MASTER_RC_BUS_ERROR, /**< an error on the I²C bus occurred */
- I2C_MASTER_RC_TIMEOUT, /**< a timeout has occurred because an operation has not completed in the expected time */
- I2C_MASTER_RC_OTHER, /** any other error (does not have to be I²C related) */
-};
-
-/** setup I²C peripheral
- * @param[in] frequency frequency to use in kHz (1-400)
- * @note Standard mode (Sm) is used for frequencies up to 100 kHz, and Fast mode (Fm) is used for frequencies up to 400 kHz
- */
-void i2c_master_setup(uint16_t frequency);
-/** release I²C peripheral
- */
-void i2c_master_release(void);
-/** reset I2C peripheral, fixing any locked state
- * @warning the I2C peripheral needs to be re-setup
- * @note to be used after failed start or stop, and bus error
- */
-void i2c_master_reset(void);
-/** check if SDA and SCL signals are pulled up externally
- * @return SDA and SCL signals are pulled up externally
- */
-bool i2c_master_check_signals(void);
-/** send start condition
- * @return I2C return code
- */
-enum i2c_master_rc i2c_master_start(void);
-/** select I²C slave device
- * @warning a start condition should be sent before this operation
- * @param[in] slave I²C address of slave device to select
- * @param[in] address_10bit if the I²C slave address is 10 bits wide
- * @param[in] write this transaction will be followed by a read (false) or write (true) operation
- * @return I²C return code
- */
-enum i2c_master_rc i2c_master_select_slave(uint16_t slave, bool address_10bit, bool write);
-/** read data over I²C
- * @param[out] data array to store bytes read
- * @param[in] data_size number of bytes to read
- * @return I²C return code
- * @warning the slave device must be selected before this operation
- * @note a stop condition will be sent at the end (I²C does not permit multiple reads, and this is necessary for 1-byte transfer)
- */
-enum i2c_master_rc i2c_master_read(uint8_t* data, size_t data_size);
-/** write data over I²C
- * @param[in] data array of byte to write to slave
- * @param[in] data_size number of bytes to write
- * @return I²C return code
- * @warning the slave device must be selected before this operation
- * @note no stop condition is sent at the end, allowing multiple writes
- */
-enum i2c_master_rc i2c_master_write(const uint8_t* data, size_t data_size);
-/** sent stop condition
- * @return I²C return code
- */
-enum i2c_master_rc i2c_master_stop(void);
-/** read data from slave device
- * @param[in] slave I²C address of slave device to select
- * @param[in] address_10bit if the I²C slave address is 10 bits wide
- * @param[out] data array to store bytes read
- * @param[in] data_size number of bytes to read
- * @return I²C return code
- * @note start and stop conditions are included
- */
-enum i2c_master_rc i2c_master_slave_read(uint16_t slave, bool address_10bit, uint8_t* data, size_t data_size);
-/** write data to slave device
- * @param[in] slave I²C address of slave device to select
- * @param[in] address_10bit if the I²C slave address is 10 bits wide
- * @param[in] data array of byte to write to slave
- * @param[in] data_size number of bytes to write
- * @return I²C return code
- * @note start and stop conditions are included
- */
-enum i2c_master_rc i2c_master_slave_write(uint16_t slave, bool address_10bit, const uint8_t* data, size_t data_size);
-/** read data at specific address from an I²C memory slave
- * @param[in] slave I²C address of slave device to select
- * @param[in] address_10bit if the I²C slave address is 10 bits wide
- * @param[in] address memory address of slave to read from
- * @param[in] address_size address size in bytes
- * @param[out] data array to store bytes read
- * @param[in] data_size number of bytes to read
- * @return I²C return code
- * @note start and stop conditions are included
- */
-enum i2c_master_rc i2c_master_address_read(uint16_t slave, bool address_10bit, const uint8_t* address, size_t address_size, uint8_t* data, size_t data_size);
-/** write data at specific address on an I²C memory slave
- * @param[in] slave I²C address of slave device to select
- * @param[in] address_10bit if the I²C slave address is 10 bits wide
- * @param[in] address memory address of slave to write to
- * @param[in] address_size address size in bytes
- * @param[in] data array of byte to write to slave
- * @param[in] data_size number of bytes to write
- * @return I²C return code
- * @note start and stop conditions are included
- */
-enum i2c_master_rc i2c_master_address_write(uint16_t slave, bool address_10bit, const uint8_t* address, size_t address_size, const uint8_t* data, size_t data_size);
diff --git a/lib/interrupt.c b/lib/interrupt.c
deleted file mode 100644
index c3f9714..0000000
--- a/lib/interrupt.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/** runtime interrupt table
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2018-2020
- */
-#include "interrupt.h" // own definitions
-
-vector_table_entry_t interrupt_table[NVIC_IRQ_COUNT] = {0};
-
-/** handler intercepting interrupts and running the function provided in the table */
-static void isr_handler(void)
-{
- // get current IRQ number
- uint8_t irq = 0;
- if (NVIC_IABR(0)) {
- irq = __builtin_ffs(NVIC_IABR(0)) - 1;
- } else if (NVIC_IABR(1)) {
- irq = __builtin_ffs(NVIC_IABR(1)) + 31;
- } else if (NVIC_IABR(2)) {
- irq = __builtin_ffs(NVIC_IABR(2)) + 64;
- } else {
- while (true);
- }
- // check if the it's a valid IRQ number
- if (irq >= NVIC_IRQ_COUNT) {
- while (true);
- }
- // run user provided ISR
- if (interrupt_table[irq]) {
- (*(void(*)(void))(interrupt_table[irq]))();
- } else {
- while (true);
- }
-}
-
-/** use the isr_handler as default ISR
- * @note the ISR can still point to other defined function
- * @remark from libopencm3/lib/stm32/f4/vector_nvic.c
- */
-void nvic_wwdg_isr(void) __attribute__((weak, alias("isr_handler")));
-void pvd_isr(void) __attribute__((weak, alias("isr_handler")));
-void tamp_stamp_isr(void) __attribute__((weak, alias("isr_handler")));
-void rtc_wkup_isr(void) __attribute__((weak, alias("isr_handler")));
-void flash_isr(void) __attribute__((weak, alias("isr_handler")));
-void rcc_isr(void) __attribute__((weak, alias("isr_handler")));
-void exti0_isr(void) __attribute__((weak, alias("isr_handler")));
-void exti1_isr(void) __attribute__((weak, alias("isr_handler")));
-void exti2_isr(void) __attribute__((weak, alias("isr_handler")));
-void exti3_isr(void) __attribute__((weak, alias("isr_handler")));
-void exti4_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma1_stream0_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma1_stream1_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma1_stream2_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma1_stream3_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma1_stream4_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma1_stream5_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma1_stream6_isr(void) __attribute__((weak, alias("isr_handler")));
-void adc_isr(void) __attribute__((weak, alias("isr_handler")));
-void can1_tx_isr(void) __attribute__((weak, alias("isr_handler")));
-void can1_rx0_isr(void) __attribute__((weak, alias("isr_handler")));
-void can1_rx1_isr(void) __attribute__((weak, alias("isr_handler")));
-void can1_sce_isr(void) __attribute__((weak, alias("isr_handler")));
-void exti9_5_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim1_brk_tim9_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim1_up_tim10_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim1_trg_com_tim11_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim1_cc_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim2_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim3_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim4_isr(void) __attribute__((weak, alias("isr_handler")));
-void i2c1_ev_isr(void) __attribute__((weak, alias("isr_handler")));
-void i2c1_er_isr(void) __attribute__((weak, alias("isr_handler")));
-void i2c2_ev_isr(void) __attribute__((weak, alias("isr_handler")));
-void i2c2_er_isr(void) __attribute__((weak, alias("isr_handler")));
-void spi1_isr(void) __attribute__((weak, alias("isr_handler")));
-void spi2_isr(void) __attribute__((weak, alias("isr_handler")));
-void usart1_isr(void) __attribute__((weak, alias("isr_handler")));
-void usart2_isr(void) __attribute__((weak, alias("isr_handler")));
-void usart3_isr(void) __attribute__((weak, alias("isr_handler")));
-void exti15_10_isr(void) __attribute__((weak, alias("isr_handler")));
-void rtc_alarm_isr(void) __attribute__((weak, alias("isr_handler")));
-void usb_fs_wkup_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim8_brk_tim12_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim8_up_tim13_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim8_trg_com_tim14_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim8_cc_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma1_stream7_isr(void) __attribute__((weak, alias("isr_handler")));
-void fsmc_isr(void) __attribute__((weak, alias("isr_handler")));
-void sdio_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim5_isr(void) __attribute__((weak, alias("isr_handler")));
-void spi3_isr(void) __attribute__((weak, alias("isr_handler")));
-void uart4_isr(void) __attribute__((weak, alias("isr_handler")));
-void uart5_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim6_dac_isr(void) __attribute__((weak, alias("isr_handler")));
-void tim7_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma2_stream0_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma2_stream1_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma2_stream2_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma2_stream3_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma2_stream4_isr(void) __attribute__((weak, alias("isr_handler")));
-void eth_isr(void) __attribute__((weak, alias("isr_handler")));
-void eth_wkup_isr(void) __attribute__((weak, alias("isr_handler")));
-void can2_tx_isr(void) __attribute__((weak, alias("isr_handler")));
-void can2_rx0_isr(void) __attribute__((weak, alias("isr_handler")));
-void can2_rx1_isr(void) __attribute__((weak, alias("isr_handler")));
-void can2_sce_isr(void) __attribute__((weak, alias("isr_handler")));
-void otg_fs_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma2_stream5_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma2_stream6_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma2_stream7_isr(void) __attribute__((weak, alias("isr_handler")));
-void usart6_isr(void) __attribute__((weak, alias("isr_handler")));
-void i2c3_ev_isr(void) __attribute__((weak, alias("isr_handler")));
-void i2c3_er_isr(void) __attribute__((weak, alias("isr_handler")));
-void otg_hs_ep1_out_isr(void) __attribute__((weak, alias("isr_handler")));
-void otg_hs_ep1_in_isr(void) __attribute__((weak, alias("isr_handler")));
-void otg_hs_wkup_isr(void) __attribute__((weak, alias("isr_handler")));
-void otg_hs_isr(void) __attribute__((weak, alias("isr_handler")));
-void dcmi_isr(void) __attribute__((weak, alias("isr_handler")));
-void cryp_isr(void) __attribute__((weak, alias("isr_handler")));
-void hash_rng_isr(void) __attribute__((weak, alias("isr_handler")));
-void fpu_isr(void) __attribute__((weak, alias("isr_handler")));
-void uart7_isr(void) __attribute__((weak, alias("isr_handler")));
-void uart8_isr(void) __attribute__((weak, alias("isr_handler")));
-void spi4_isr(void) __attribute__((weak, alias("isr_handler")));
-void spi5_isr(void) __attribute__((weak, alias("isr_handler")));
-void spi6_isr(void) __attribute__((weak, alias("isr_handler")));
-void sai1_isr(void) __attribute__((weak, alias("isr_handler")));
-void lcd_tft_isr(void) __attribute__((weak, alias("isr_handler")));
-void lcd_tft_err_isr(void) __attribute__((weak, alias("isr_handler")));
-void dma2d_isr(void) __attribute__((weak, alias("isr_handler")));
diff --git a/lib/interrupt.h b/lib/interrupt.h
deleted file mode 100644
index 02ea9ab..0000000
--- a/lib/interrupt.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/** runtime interrupt table
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2018-2020
- */
-#pragma once
-#include "libopencm3/cm3/nvic.h"
-#include "libopencm3/cm3/vector.h"
-
-/** table of interrupts which can set to user functions
- * @note only interrupt using the default handler can be intercepted
- */
-extern vector_table_entry_t interrupt_table[NVIC_IRQ_COUNT];
diff --git a/lib/ir_nec.c b/lib/ir_nec.c
deleted file mode 100644
index 93de983..0000000
--- a/lib/ir_nec.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/** library to decode InfraRed NEC code
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2018-2020
- * @note peripherals used: timer channel @ref ir_nec_timer
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdbool.h> // standard boolean type
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/timer.h> // timer utilities
-
-/* own libraries */
-#include "ir_nec.h" // own definitions
-#include "global.h" // common methods
-
-/** @defgroup ir_nec_timer timer peripheral used to measure signal timing for code decoding
- * @{
- */
-#define IR_NEC_TIMER 4 /**< timer peripheral */
-#define IR_NEC_CHANNEL 3 /**< channel used as input capture */
-#define IR_NEC_JITTER 40 /**< signal timing jitter in % tolerated in timing */
-/** @} */
-
-volatile bool ir_nec_code_received_flag = false;
-struct ir_nec_code_t ir_nec_code_received;
-
-/** if the extended address in the code is used
- * the extended address uses all 16-bits instead of having redundant/robust 2x8-bits address
- */
-static bool ir_nec_extended = false;
-
-void ir_nec_setup(bool extended)
-{
- ir_nec_extended = extended; // remember setting
-
- // setup timer to measure signal timing for bit decoding (use timer channel as input capture)
- rcc_periph_clock_enable(RCC_TIM_CH(IR_NEC_TIMER, IR_NEC_CHANNEL)); // enable clock for GPIO peripheral
- rcc_periph_clock_enable(RCC_TIM(IR_NEC_TIMER)); // enable clock for timer peripheral
- rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternative functions
- gpio_set(TIM_CH_PORT(IR_NEC_TIMER, IR_NEC_CHANNEL), TIM_CH_PIN(IR_NEC_TIMER, IR_NEC_CHANNEL)); // idle is high (using pull-up resistor)
- gpio_set_mode(TIM_CH_PORT(IR_NEC_TIMER, IR_NEC_CHANNEL), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, TIM_CH_PIN(IR_NEC_TIMER, IR_NEC_CHANNEL)); // setup GPIO pin as input
- rcc_periph_reset_pulse(RST_TIM(IR_NEC_TIMER)); // reset timer state
- timer_set_mode(TIM(IR_NEC_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
- // codes are repeated every 110 ms, thus we need to measure at least this duration to detect repeats correctly
- // the 16-bit timer is by far precise enough to measure the smallest 560 us burst
- timer_set_prescaler(TIM(IR_NEC_TIMER), (110 * (100 + IR_NEC_JITTER) / 100 * (rcc_ahb_frequency / 1000) / (1 << 16)) + 1 - 1); // set the prescaler so this 16 bits timer allows to wait for 110 ms (+ jitter) from the start signal
- timer_ic_set_input(TIM(IR_NEC_TIMER), TIM_IC(IR_NEC_CHANNEL), TIM_IC_IN_TI(IR_NEC_CHANNEL)); // configure ICx to use TIn
- timer_ic_set_filter(TIM(IR_NEC_TIMER), TIM_IC(IR_NEC_CHANNEL), TIM_IC_CK_INT_N_8); // use small filter (noise reduction is more important than timing)
- timer_ic_set_polarity(TIM(IR_NEC_TIMER), TIM_IC(IR_NEC_CHANNEL), TIM_IC_FALLING); // capture on falling edge (IR bursts are active low on IR demodulators)
- timer_ic_set_prescaler(TIM(IR_NEC_TIMER), TIM_IC(IR_NEC_CHANNEL), TIM_IC_PSC_OFF); // don't use any prescaler since we want to capture every pulse
-
- timer_clear_flag(TIM(IR_NEC_TIMER), TIM_SR_UIF); // clear flag
- timer_update_on_overflow(TIM(IR_NEC_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout)
- timer_enable_irq(TIM(IR_NEC_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
-
- timer_clear_flag(TIM(IR_NEC_TIMER), TIM_SR_CCIF(IR_NEC_CHANNEL)); // clear input compare flag
- timer_ic_enable(TIM(IR_NEC_TIMER), TIM_IC(IR_NEC_CHANNEL)); // enable capture interrupt only when IR burst
- timer_enable_irq(TIM(IR_NEC_TIMER), TIM_DIER_CCIE(IR_NEC_CHANNEL)); // enable capture interrupt
-
- nvic_enable_irq(NVIC_TIM_IRQ(IR_NEC_TIMER)); // catch interrupt in service routine
- timer_enable_counter(TIM(IR_NEC_TIMER)); // enable timer
-}
-
-/** interrupt service routine called for timer
- *
- * @remark normally we want to keep the ISR as short as possible, and do the processing in the main loop,
- * @remark but because the code needs to be decoded in order to detect repeat burst correctly,
- * @remark we do the decoding in the ISR and don't trust the user to run the decoding within 42.42 ms (time until the next code is sent)
- *
- * @note we don't enforce 110 ms between codes (they can be received earlier), but recognize repeat code after 110 ms
- */
-void TIM_ISR(IR_NEC_TIMER)(void)
-{
- static uint8_t burst_count = 0; // the mark or space count
- static uint32_t burst_start = 0; // time of current mark/space start
- static uint32_t bits = 0; // the received code bits
- static struct ir_nec_code_t code; // the last code received (don't trust the user exposed ir_nec_code_received)
- static bool valid = false; // if the last IR activity is a valid code
-
- if (timer_get_flag(TIM(IR_NEC_TIMER), TIM_SR_UIF)) { // overflow update event happened
- timer_clear_flag(TIM(IR_NEC_TIMER), TIM_SR_UIF); // clear flag
- goto error; // no code or repeat code has been received in time
- } else if (timer_get_flag(TIM(IR_NEC_TIMER), TIM_SR_CCIF(IR_NEC_CHANNEL))) { // edge detected on input capture
- uint32_t time = TIM_CCR(IR_NEC_TIMER, IR_NEC_CHANNEL); // save captured bit timing (this also clears the flag)
- time = (time * (TIM_PSC(TIM(IR_NEC_TIMER)) + 1)) / (rcc_ahb_frequency / 1000000); // calculate time in us
- if (time < burst_start) { // this should not happen
- goto error;
- }
- time -= burst_start; // calculate mark/space burst time
- if (0 == burst_count) { // start of very first IR mark for the AGC burst
- timer_set_counter(TIM(IR_NEC_TIMER), 0); // reset timer counter
- burst_start = 0; // reset code timer
- time = 0; // ignore first burst
- } else if (1 == burst_count) { // end of AGC mark
- if (time > 9000 * (100 - IR_NEC_JITTER) / 100 && time < 9000 * (100 + IR_NEC_JITTER) / 100) { // AGC mark
- } else {
- goto error;
- }
- } else if (2 == burst_count) { // end of AGC space
- if (time > 4500 * (100 - IR_NEC_JITTER) / 100 && time < 4500 * (100 + IR_NEC_JITTER) / 100) { // AGC code space
- bits = 0; // reset previously received bits
- valid = false; // invalidate previously received code (since this is not a repeat)
- } else if (time > 2250 * (100 - IR_NEC_JITTER) / 100 && time < 2250 * (100 + IR_NEC_JITTER) / 100) { // AGC repeat space
- if (valid) {
- code.repeat = true;
- ir_nec_code_received.repeat = code.repeat;
- ir_nec_code_received.address = code.address;
- ir_nec_code_received.command = code.command;
- ir_nec_code_received_flag = true;
- goto reset; // wait for next code
- } else {
- goto error;
- }
- } else {
- goto reset; // not the correct header
- }
- } else if (burst_count <= (1 + 32) * 2) { // the code bits
- if (burst_count % 2) { // bit mark end
- if (time > 560 * (100 - IR_NEC_JITTER) / 100 && time < 560 * (100 + IR_NEC_JITTER) / 100) { // bit mark
- } else {
- goto error;
- }
- } else { // bit space end
- bits <<= 1;
- if (time > (2250 - 560) * (100 - IR_NEC_JITTER) / 100 && time < (2250 - 560) * (100 + IR_NEC_JITTER) / 100) { // bit 1space
- bits |= 1; // save bit
- } else if (time > (1125 - 560) * (100 - IR_NEC_JITTER) / 100 && time < (1125 - 560) * (100 + IR_NEC_JITTER) / 100) { // bit 0 space
- bits |= 0; // save bit
- } else {
- goto error;
- }
- }
- if ((1 + 32) * 2 == burst_count) { // the code is complete
- uint8_t address = (bits >> 24) & 0xff; // get 8 address bits
- uint8_t naddress = (bits >> 16) & 0xff; // get negated 8 address bits
- uint8_t command = (bits >> 8) & 0xff; // get 8 command bits
- uint8_t ncommand = (bits >> 0) & 0xff; // get negate 8 commend bits
- if (!ir_nec_extended) { // the 8-bits address has its inverse
- if (0xff != (address ^ naddress)) { // the address and its inverse do not match
- goto error;
- }
- }
- if (0xff != (command ^ ncommand)) { // the command and its inverse do not match
- goto error;
- }
- valid = true; // remember we have a valid signal
- code.repeat = false; // this is not a repeat code
- if (ir_nec_extended) {
- code.address = (address << 8) + naddress;
- } else {
- code.address = address; // save decoded address
- }
- code.command = command; // save decoded command
- ir_nec_code_received.repeat = code.repeat; // transfer code to user
- ir_nec_code_received.address = code.address; // transfer code to user
- ir_nec_code_received.command = code.command; // transfer code to user
- ir_nec_code_received_flag = true;
- ir_nec_code_received_flag = true; // notify user about the new code
- goto reset; // wait for next code
- }
- } else { // this should not happen
- goto error;
- }
- if (burst_count % 2) {
- timer_ic_set_polarity(TIM(IR_NEC_TIMER), TIM_IC(IR_NEC_CHANNEL), TIM_IC_FALLING); // wait for end of space
- } else {
- timer_ic_set_polarity(TIM(IR_NEC_TIMER), TIM_IC(IR_NEC_CHANNEL), TIM_IC_RISING); // wait for end of mark
- }
- burst_count++; // wait for next burst
- burst_start += time; // save current burst start
- } else { // no other interrupt should occur
- while (true); // unhandled exception: wait for the watchdog to bite
- }
- return;
-error:
- valid = false; // invalidate previously received code
-reset:
- timer_ic_set_polarity(TIM(IR_NEC_TIMER), TIM_IC(IR_NEC_CHANNEL), TIM_IC_FALLING); // wait for next IR mark burst
- burst_count = 0; // reset state
- burst_start = 0; // reset state
-}
diff --git a/lib/ir_nec.h b/lib/ir_nec.h
deleted file mode 100644
index 2716a01..0000000
--- a/lib/ir_nec.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/** library to decode InfraRed NEC code
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2018-2020
- * @note peripherals used: timer channel @ref ir_nec_timer
- */
-#pragma once
-#error not converted for STM32F4
-
-/** set when an IR NEC code has been received */
-extern volatile bool ir_nec_code_received_flag;
-
-/** IR NEC code */
-struct ir_nec_code_t {
- bool repeat; /**< if this is only a code repeat (received 42.42 ms after the code, 98.75 ms after a repeat) */
- uint16_t address; /**< code address (8-bit for non-extended, 16-bit for extended) */
- uint8_t command; /**< code command */
-};
-
-/** last IR NEC code received */
-extern struct ir_nec_code_t ir_nec_code_received;
-
-/** setup peripherals to receive IR NEC codes
- * @param[in] extended if the command address is extended (using 16 bits instead of 8, at the cost of error checking)
- */
-void ir_nec_setup(bool extended);
diff --git a/lib/lcd_hd44780.c b/lib/lcd_hd44780.c
deleted file mode 100644
index 90d301e..0000000
--- a/lib/lcd_hd44780.c
+++ /dev/null
@@ -1,783 +0,0 @@
-/** library to communication with Hitacho HD44780 LCD controller
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2019-2020
- * @note peripherals used: GPIO @ref lcd_hd44780_gpio
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <stdbool.h> // boolean utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-
-/* own libraries */
-#include "global.h" // common methods
-#include "lcd_hd44780.h" // own definitions
-#if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
-#include "i2c_master.h" // I²C utilities
-#endif
-
-/** include busy time waiting in writes
- * @note this removes the need to call lcd_hd44780_wait_busy but prevents you to do something else meanwhile, particularly when reading is enabled
- * @note because I²C is already slow enough, there is no need to wait further
- */
-#if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
-#define LCD_HD44780_BUSY_WAIT_INCLUDE 1 // lcd_hd44780_wait_busy works, but the I²C bus is often slower
-#else // LCD_HD44780_I2C
-#define LCD_HD44780_BUSY_WAIT_INCLUDE 1 // you can change this value
-#endif // LCD_HD44780_I2C
-/** busy wait time for most short writes (37 us with margin) */
-#define LCD_HD44780_BUSY_WAIT_SHORT (37 + 5)
-/** busy wait time for some long writes (1520 us, but experience shows it's more)
- * @note I have no idea why, but longer times increase the contrast darkness
- */
-#define LCD_HD44780_BUSY_WAIT_LONG (1520 + 500)
-
-/* usual HD44780 pinout:
- * - 1 GND: ground
- * - 2 VCC: 5V (3.3V versions also exist, but a less common)
- * - 3 V0 : LCD bias voltage, connect to 10-20k potentiometer (VCC to GND)
- * - 4 RS : Register Select (high = data, low = instruction)
- * - 5 R/W: Read/Write (high = read, low = write)
- * - 6 E : enable (falling edge to latch data, high to output register)
- * - 7 DB0: Data Bit 0 (for 8-bit transfer)
- * - 8 DB1: Data Bit 1 (for 8-bit transfer)
- * - 9 DB2: Data Bit 2 (for 8-bit transfer)
- * - 10 DB3: Data Bit 3 (for 8-bit transfer)
- * - 11 DB4: Data Bit 4 (for 4-bit transfer)
- * - 12 DB5: Data Bit 5 (for 4-bit transfer)
- * - 13 DB6: Data Bit 6 (for 4-bit transfer)
- * - 14 DB7: Data Bit 7 (for 4-bit transfer)
- * - 15 BLA: Backlight Anode
- * - 16 BLK: Backlight Cathode
- */
-
-/** @defgroup lcd_hd44780_signals HD44780 signals
- * @note can be combined using OR
- * @{
- */
-#define LCD_HD44780_RS (1 << 0) /**< RS : Register Select (high = data, low = instruction) */
-#define LCD_HD44780_RnW (1 << 1) /**< R/W: Read/Write (high = read, low = write) */
-#define LCD_HD44780_E (1 << 2) /**< enable (falling edge to latch data, high to output register) */
-#define LCD_HD44780_DB0 (1 << 3) /**< Data Bit 0 */
-#define LCD_HD44780_DB1 (1 << 4) /**< Data Bit 1 */
-#define LCD_HD44780_DB2 (1 << 5) /**< Data Bit 2 */
-#define LCD_HD44780_DB3 (1 << 6) /**< Data Bit 3 */
-#define LCD_HD44780_DB4 (1 << 7) /**< Data Bit 4 */
-#define LCD_HD44780_DB5 (1 << 8) /**< Data Bit 5 */
-#define LCD_HD44780_DB6 (1 << 9) /**< Data Bit 6 */
-#define LCD_HD44780_DB7 (1 << 10) /**< Data Bit 7 */
-#define LCD_HD44780_LED (1 << 11) /**< Backlight Cathode */
-/** @} */
-
-#if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
-/* I²C backpack PCF8574 GPIO expander pinout:
- * - P0: RS
- * - P1: RnW
- * - P2: E
- * - P3: LED
- * - P4: D4
- * - P5: D5
- * - P6: D6
- * - P7: D7
- */
-/** register select */
-#define LCD_HD44780_I2C_RS (1 << 0)
-/** select read or write */
-#define LCD_HD44780_I2C_RnW (1 << 1)
-/** enable pin */
-#define LCD_HD44780_I2C_E (1 << 2)
-/** enable LED backlight */
-#define LCD_HD44780_I2C_LED (1 << 3)
-/** data bit 4 */
-#define LCD_HD44780_I2C_DB4 (1 << 4)
-/** data bit 5 */
-#define LCD_HD44780_I2C_DB5 (1 << 5)
-/** data bit 6 */
-#define LCD_HD44780_I2C_DB6 (1 << 6)
-/** data bit 7 */
-#define LCD_HD44780_I2C_DB7 (1 << 7)
-/** I²C peripheral base address */
-#define LCD_HD44780_I2C_PERIPH I2C1
-/** I2C address of I²C backpack adapter (7 bits are LSB) */
-uint8_t lcd_hd44780_i2c_addr = 0x3f; // default PCF8574A I²C backpack slave address
-/** I2C GPIO output state */
-static uint8_t lcd_hd44780_i2c_output = 0xff;
-#else // LCD_HD44780_I2C
-/** @defgroup lcd_hd44780_gpio GPIO used to control the HD44780
- * @{
- */
-/** register select
- * @note pulled up by HD44780
- */
-#define LCD_HD44780_GPIO_RS PB9
-/** pin allowing writing data bits (on low) or reading them (on high)
- * @note remove definition if tied to ground
- * @note this enables read back data, but more importantly read the busy flag to know when the controller finished processing the command. Tying R/nW to ground instead of a GPIO saves a pin, but no data can be read back. Also every command needs to wait a minimum time before being able to send the next one, even if the controlled might actually already have processed it and is not busy anymore.
- * @note is pulled up by HD44780
- */
-#define LCD_HD44780_GPIO_RnW PB10
-/** enable pin
- * @warning needs an external 10k pull-up resistor
- */
-#define LCD_HD44780_GPIO_E PB11
-/** data bit 7
- * @note pulled up by HD44780
- */
-#define LCD_HD44780_GPIO_DB7 PB12
-/** data bit 6
- * @note pulled up by HD44780
- */
-#define LCD_HD44780_GPIO_DB6 PB13
-/** data bit 5
- * @note pulled up by HD44780
- */
-#define LCD_HD44780_GPIO_DB5 PB14
-/** data bit 4
- * @note pulled up by HD44780
- */
-#define LCD_HD44780_GPIO_DB4 PB15
-/** data bit 3
- * @note pulled up by HD44780
- * @note leave undefined when only 4-bit mode is used
- */
-//#define LCD_HD44780_GPIO_DB3 P
-/** data bit 2
- * @note pulled up by HD44780
- * @note leave undefined when only 4-bit mode is used
- */
-//#define LCD_HD44780_GPIO_DB2 P
-/** data bit 1
- * @note pulled up by HD44780
- * @note leave undefined when only 4-bit mode is used
- */
-//#define LCD_HD44780_GPIO_DB1 P
-/** data bit 0
- * @note pulled up by HD44780
- * @note leave undefined when only 4-bit mode is used
- */
-//#define LCD_HD44780_GPIO_DB0 P
-/** @} */
-#endif // LCD_HD44780_I2C
-
-/** set for 8-bit interface data
- * @note I²C implies 4-bit
- */
-#if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
-#define LCD_HD44780_INTERFACE_DL 0
-#elif defined(LCD_HD44780_GPIO_DB3) && defined(LCD_HD44780_GPIO_DB2) && defined(LCD_HD44780_GPIO_DB1) && defined(LCD_HD44780_GPIO_DB0)
-#define LCD_HD44780_INTERFACE_DL 1
-#else
-#define LCD_HD44780_INTERFACE_DL 0
-#endif
-
-/** if the display is configured having 2 lines */
-static bool lcd_hd44780_n_2lines = true;
-
-/** set signals
- * @param[in] signals
- */
-static void lcd_hd44780_set_signal(uint16_t signals)
-{
-#if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
- if (signals & LCD_HD44780_RS) {
- lcd_hd44780_i2c_output |= LCD_HD44780_I2C_RS;
- }
- if (signals & LCD_HD44780_RnW) {
- lcd_hd44780_i2c_output |= LCD_HD44780_I2C_RnW;
- }
- if (signals & LCD_HD44780_E) {
- lcd_hd44780_i2c_output |= LCD_HD44780_I2C_E;
- }
- if (signals & LCD_HD44780_DB4) {
- lcd_hd44780_i2c_output |= LCD_HD44780_I2C_DB4;
- }
- if (signals & LCD_HD44780_DB5) {
- lcd_hd44780_i2c_output |= LCD_HD44780_I2C_DB5;
- }
- if (signals & LCD_HD44780_DB6) {
- lcd_hd44780_i2c_output |= LCD_HD44780_I2C_DB6;
- }
- if (signals & LCD_HD44780_DB7) {
- lcd_hd44780_i2c_output |= LCD_HD44780_I2C_DB7;
- }
- if (signals & LCD_HD44780_LED) {
- lcd_hd44780_i2c_output |= LCD_HD44780_I2C_LED;
- }
-#else // LCD_HD44780_I2C
- if (signals & LCD_HD44780_RS) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_RS), GPIO_PIN(LCD_HD44780_GPIO_RS));
- }
-#ifdef LCD_HD44780_GPIO_RnW
- if (signals & LCD_HD44780_RnW) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_RnW), GPIO_PIN(LCD_HD44780_GPIO_RnW));
- }
-#endif // LCD_HD44780_GPIO_RnW
- if (signals & LCD_HD44780_E) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_E), GPIO_PIN(LCD_HD44780_GPIO_E));
- }
-#if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
- if (signals & LCD_HD44780_DB0) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB0), GPIO_PIN(LCD_HD44780_GPIO_DB0));
- }
- if (signals & LCD_HD44780_DB1) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB1), GPIO_PIN(LCD_HD44780_GPIO_DB1));
- }
- if (signals & LCD_HD44780_DB2) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB2), GPIO_PIN(LCD_HD44780_GPIO_DB2));
- }
- if (signals & LCD_HD44780_DB3) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB3), GPIO_PIN(LCD_HD44780_GPIO_DB3));
- }
-#endif // LCD_HD44780_INTERFACE_DL
- if (signals & LCD_HD44780_DB4) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB4), GPIO_PIN(LCD_HD44780_GPIO_DB4));
- }
- if (signals & LCD_HD44780_DB5) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB5), GPIO_PIN(LCD_HD44780_GPIO_DB5));
- }
- if (signals & LCD_HD44780_DB6) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB6), GPIO_PIN(LCD_HD44780_GPIO_DB6));
- }
- if (signals & LCD_HD44780_DB7) {
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB7), GPIO_PIN(LCD_HD44780_GPIO_DB7));
- }
- if (signals & LCD_HD44780_LED) {
- // no LED GPIO defined
- }
-#endif // LCD_HD44780_I2C
-}
-/** clear signals
- * @param[in] signals
- */
-static void lcd_hd44780_clear_signal(uint16_t signals)
-{
-#if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
- if (signals & LCD_HD44780_RS) {
- lcd_hd44780_i2c_output &= ~LCD_HD44780_I2C_RS;
- }
- if (signals & LCD_HD44780_RnW) {
- lcd_hd44780_i2c_output &= ~LCD_HD44780_I2C_RnW;
- }
- if (signals & LCD_HD44780_E) {
- lcd_hd44780_i2c_output &= ~LCD_HD44780_I2C_E;
- }
- if (signals & LCD_HD44780_DB4) {
- lcd_hd44780_i2c_output &= ~LCD_HD44780_I2C_DB4;
- }
- if (signals & LCD_HD44780_DB5) {
- lcd_hd44780_i2c_output &= ~LCD_HD44780_I2C_DB5;
- }
- if (signals & LCD_HD44780_DB6) {
- lcd_hd44780_i2c_output &= ~LCD_HD44780_I2C_DB6;
- }
- if (signals & LCD_HD44780_DB7) {
- lcd_hd44780_i2c_output &= ~LCD_HD44780_I2C_DB7;
- }
- if (signals & LCD_HD44780_LED) {
- lcd_hd44780_i2c_output &= ~LCD_HD44780_I2C_LED;
- }
-#else // LCD_HD44780_I2C
- if (signals & LCD_HD44780_RS) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_RS), GPIO_PIN(LCD_HD44780_GPIO_RS));
- }
-#ifdef LCD_HD44780_GPIO_RnW
- if (signals & LCD_HD44780_RnW) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_RnW), GPIO_PIN(LCD_HD44780_GPIO_RnW));
- }
-#endif // LCD_HD44780_GPIO_RnW
- if (signals & LCD_HD44780_E) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_E), GPIO_PIN(LCD_HD44780_GPIO_E));
- }
-#if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
- if (signals & LCD_HD44780_DB0) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_DB0), GPIO_PIN(LCD_HD44780_GPIO_DB0));
- }
- if (signals & LCD_HD44780_DB1) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_DB1), GPIO_PIN(LCD_HD44780_GPIO_DB1));
- }
- if (signals & LCD_HD44780_DB2) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_DB2), GPIO_PIN(LCD_HD44780_GPIO_DB2));
- }
- if (signals & LCD_HD44780_DB3) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_DB3), GPIO_PIN(LCD_HD44780_GPIO_DB3));
- }
-#endif // LCD_HD44780_INTERFACE_DL
- if (signals & LCD_HD44780_DB4) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_DB4), GPIO_PIN(LCD_HD44780_GPIO_DB4));
- }
- if (signals & LCD_HD44780_DB5) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_DB5), GPIO_PIN(LCD_HD44780_GPIO_DB5));
- }
- if (signals & LCD_HD44780_DB6) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_DB6), GPIO_PIN(LCD_HD44780_GPIO_DB6));
- }
- if (signals & LCD_HD44780_DB7) {
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_DB7), GPIO_PIN(LCD_HD44780_GPIO_DB7));
- }
- if (signals & LCD_HD44780_LED) {
- // no LED GPIO defined
- }
-#endif // LCD_HD44780_I2C
-}
-
-/** flush the set and cleared signals
- * @note this only applies to I²C and helps gain time
- */
-static void lcd_hd44780_flush_signal(void)
-{
-#if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
- i2c_master_slave_write(LCD_HD44780_I2C_PERIPH, lcd_hd44780_i2c_addr, false, &lcd_hd44780_i2c_output, 1); // write the set signals
-#endif
-}
-
-/** read from controller
- * @param[in] data read data (true) or busy flag and address counter (false)
- * @return data/AC read
- */
-static uint8_t lcd_hd44780_read(bool data)
-{
-#if defined(LCD_HD44780_GPIO_RnW) || defined(LCD_HD44780_I2C)
- lcd_hd44780_set_signal(LCD_HD44780_RnW | LCD_HD44780_DB7 | LCD_HD44780_DB6 | LCD_HD44780_DB5 | LCD_HD44780_DB4); // switch DB direction to input to read data
-
- if (data) {
- lcd_hd44780_set_signal(LCD_HD44780_RS); // set high to read data
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_RS); // set low to read busy flag and AC
- }
- lcd_hd44780_flush_signal();
- // no need to wait tAS = 40 ns before next step since the instructions are slower
-
- lcd_hd44780_set_signal(LCD_HD44780_E); // set high to have data output
- lcd_hd44780_flush_signal();
- sleep_us(0); // wait t_DDR = 160 ns before reading
- // read data bits
- uint8_t input = 0; // to store read data
-#if defined(LCD_HD44780_I2C)
- uint8_t i2c_data;
- if (I2C_MASTER_RC_NONE == i2c_master_slave_read(LCD_HD44780_I2C_PERIPH, lcd_hd44780_i2c_addr, false, &i2c_data, 1)) {
- if (i2c_data & LCD_HD44780_I2C_DB7) {
- input |= 0x80;
- }
- if (i2c_data & LCD_HD44780_I2C_DB6) {
- input |= 0x40;
- }
- if (i2c_data & LCD_HD44780_I2C_DB5) {
- input |= 0x20;
- }
- if (i2c_data & LCD_HD44780_I2C_DB4) {
- input |= 0x10;
- }
- }
-#else // LCD_HD44780_I2C
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB7), GPIO_PIN(LCD_HD44780_GPIO_DB7))) {
- input |= 0x80;
- }
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB6), GPIO_PIN(LCD_HD44780_GPIO_DB6))) {
- input |= 0x40;
- }
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB5), GPIO_PIN(LCD_HD44780_GPIO_DB5))) {
- input |= 0x20;
- }
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB4), GPIO_PIN(LCD_HD44780_GPIO_DB4))) {
- input |= 0x10;
- }
-#endif // LCD_HD44780_I2C
-#if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB3), GPIO_PIN(LCD_HD44780_GPIO_DB3))) {
- input |= 0x08;
- }
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB2), GPIO_PIN(LCD_HD44780_GPIO_DB2))) {
- input |= 0x04;
- }
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB1), GPIO_PIN(LCD_HD44780_GPIO_DB1))) {
- input |= 0x02;
- }
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB0), GPIO_PIN(LCD_HD44780_GPIO_DB0))) {
- input |= 0x01;
- }
-#else // LCD_HD44780_INTERFACE_DL
- // get second nibble
- // don't wait PW_EH = 230 ns since reading took longer
- lcd_hd44780_clear_signal(LCD_HD44780_E); // end current data read
- lcd_hd44780_flush_signal();
- sleep_us(1); // wait t_cycE = 500 ns
- lcd_hd44780_set_signal(LCD_HD44780_E); // have next data output
- lcd_hd44780_flush_signal();
- sleep_us(0); // wait t_DDR = 160 ns before reading
-
- // read second nibble
-#if defined(LCD_HD44780_I2C)
- if (I2C_MASTER_RC_NONE == i2c_master_slave_read(LCD_HD44780_I2C_PERIPH, lcd_hd44780_i2c_addr, false, &i2c_data, 1)) {
- if (i2c_data & LCD_HD44780_I2C_DB7) {
- input |= 0x08;
- }
- if (i2c_data & LCD_HD44780_I2C_DB6) {
- input |= 0x04;
- }
- if (i2c_data & LCD_HD44780_I2C_DB5) {
- input |= 0x02;
- }
- if (i2c_data & LCD_HD44780_I2C_DB4) {
- input |= 0x01;
- }
- }
-#else // LCD_HD44780_I2C
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB7), GPIO_PIN(LCD_HD44780_GPIO_DB7))) {
- input |= 0x80;
- }
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB6), GPIO_PIN(LCD_HD44780_GPIO_DB6))) {
- input |= 0x40;
- }
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB5), GPIO_PIN(LCD_HD44780_GPIO_DB5))) {
- input |= 0x20;
- }
- if (gpio_get(GPIO_PORT(LCD_HD44780_GPIO_DB4), GPIO_PIN(LCD_HD44780_GPIO_DB4))) {
- input |= 0x10;
- }
-#endif // LCD_HD44780_I2C
-#endif // LCD_HD44780_INTERFACE_DL
- // don't wait PW_EH = 230 ns since reading took longer
- lcd_hd44780_clear_signal(LCD_HD44780_E); // end data read
- lcd_hd44780_flush_signal();
-
- return input;
-#else // LCD_HD44780_GPIO_RnW || LCD_HD44780_I2C
- return 0; // read is not supported
-#endif
-}
-
-uint8_t lcd_hd44780_read_data(void)
-{
- return lcd_hd44780_read(true);
-}
-
-/** write to controller
- * @param[in] command true if it is an command, false if it is data
- * @param[in] data data bit to write
- * @param[in] first_nibble_only if only the first nibble of the data should be written (only applies to 4-bit mode)
- */
-static void lcd_hd44780_write(bool command, uint8_t data, bool first_nibble_only)
-{
- lcd_hd44780_clear_signal(LCD_HD44780_RnW); // switch DB direction to output to write data
- if (command) {
- lcd_hd44780_clear_signal(LCD_HD44780_RS);
- } else {
- lcd_hd44780_set_signal(LCD_HD44780_RS);
- }
- lcd_hd44780_flush_signal();
- // no need to wait tAS = 40 ns before next step since the instructions are slower
-
- // write data
- if (data & 0x80) {
- lcd_hd44780_set_signal(LCD_HD44780_DB7);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB7);
- }
- if (data & 0x40) {
- lcd_hd44780_set_signal(LCD_HD44780_DB6);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB6);
- }
- if (data & 0x20) {
- lcd_hd44780_set_signal(LCD_HD44780_DB5);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB5);
- }
- if (data & 0x10) {
- lcd_hd44780_set_signal(LCD_HD44780_DB4);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB4);
- }
-#if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
- if (data & 0x08) {
- lcd_hd44780_set_signal(LCD_HD44780_DB3);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB3);
- }
- if (data & 0x04) {
- lcd_hd44780_set_signal(LCD_HD44780_DB2);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB2);
- }
- if (data & 0x02) {
- lcd_hd44780_set_signal(LCD_HD44780_DB1);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB1);
- }
- if (data & 0x01) {
- lcd_hd44780_set_signal(LCD_HD44780_DB0);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB0);
- }
-#else // LCD_HD44780_INTERFACE_DL
- if (!first_nibble_only) { // write second nibble
- // pulse E to send data
- sleep_us(1); // wait t_cycE = 500 ns
- lcd_hd44780_set_signal(LCD_HD44780_E); // set high change output data
- lcd_hd44780_flush_signal();
- sleep_us(1); // wait PW_EH = 230 ns
- lcd_hd44780_clear_signal(LCD_HD44780_E); // set low to latch data
- lcd_hd44780_flush_signal();
- // no need to wait t_H = 10 ns before next step since next instructions are slower
-
- // send second nibble
- if (data & 0x08) {
- lcd_hd44780_set_signal(LCD_HD44780_DB7);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB7);
- }
- if (data & 0x04) {
- lcd_hd44780_set_signal(LCD_HD44780_DB6);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB6);
- }
- if (data & 0x02) {
- lcd_hd44780_set_signal(LCD_HD44780_DB5);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB5);
- }
- if (data & 0x01) {
- lcd_hd44780_set_signal(LCD_HD44780_DB4);
- } else {
- lcd_hd44780_clear_signal(LCD_HD44780_DB4);
- }
- }
-#endif // LCD_HD44780_INTERFACE_DL
- // pulse E to send data
- sleep_us(1); // wait t_cycE = 500 ns
- lcd_hd44780_set_signal(LCD_HD44780_E); // set high change output data
- lcd_hd44780_flush_signal();
- sleep_us(1); // wait PW_EH = 230 ns
- lcd_hd44780_clear_signal(LCD_HD44780_E); // set low to latch data
- lcd_hd44780_flush_signal();
- // no need to wait t_H = 10 ns before next step since next instructions are slower
- // no need to wait t_AH = 10 ns before next step since next instructions are slower
-}
-
-/** wait until controller is not busy anymore
- * @param[in] timeout maximum time to wait in us
- * @return address count, or >= 0x80 if timeout expired
- */
-static uint8_t lcd_hd44780_wait_busy(uint16_t timeout)
-{
-#if defined(LCD_HD44780_GPIO_RnW)
- uint8_t ac = 0x80; // address counter to return
- while (timeout && ((ac = lcd_hd44780_read(false)) >= 0x80)) { // wait until busy flag is low or timeout
- // wait a bit
- sleep_us(100);
- if (timeout > 100) {
- timeout -= 100;
- } else {
- timeout = 0;
- }
- }
- return ac;
-#else // I²C is also to slow to read (at least 6400 us per read)
- sleep_us(timeout); // just wait
- return 0;
-#endif
-}
-
-/** write function set command
- * @param[in] dl_8bit 8-bit (true) or 4-bit (false) data length
- * @param[in] n_2lines 2 (true) or 1 (false) lines
- * @param[in] f_5x10 5x10 (true) or 5x8 (false) dots font
- */
-static void lcd_hd44780_function_set(bool dl_8bit, bool n_2lines, bool f_5x10)
-{
- uint8_t data = 0x20;
- if (dl_8bit) {
- data |= 0x10;
- }
- if (n_2lines) {
- data |= 0x08;
- }
- if (f_5x10) {
- data |= 0x04;
- }
- lcd_hd44780_write(true, data, false);
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_SHORT);
-}
-
-bool lcd_hd44780_setup(bool n_2lines, bool f_5x10)
-{
- sleep_ms(40 + 2); // wait for display to initialise after power on: 15 ms for VCC > 4.5 V, 40 ms for VCC > 2.7 V
-#if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
- // configure I²C peripheral
- if (!i2c_master_check_signals(LCD_HD44780_I2C_PERIPH)) { // check if there are pull-ups to operator I²C
- return false;
- }
- i2c_master_setup(LCD_HD44780_I2C_PERIPH, 100); // setup I²C bus (PCF8574 supports an I²C clock up to 100 kHz)
- lcd_hd44780_i2c_output = 0xff; // put GPIO to input (sort of open drain output)
- if (I2C_MASTER_RC_NONE != i2c_master_slave_write(LCD_HD44780_I2C_PERIPH, lcd_hd44780_i2c_addr, false, &lcd_hd44780_i2c_output, 1)) { // check if the device is present and set inputs
- return false;
- }
-#else // LCD_HD44780_I2C
- // enable all GPIO
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_E)); // enable clock for GPIO port
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_E), GPIO_PIN(LCD_HD44780_GPIO_E)); // start idle low
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_E), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_E)); // set GPIO as output
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_DB7)); // enable clock for GPIO port
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB7), GPIO_PIN(LCD_HD44780_GPIO_DB7)); // idle high
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB7), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_DB7)); // open drain allows to read and write
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_DB6)); // enable clock for GPIO port
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB6), GPIO_PIN(LCD_HD44780_GPIO_DB6)); // idle high
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB6), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_DB6)); // open drain allows to read and write
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_DB5)); // enable clock for GPIO port
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB5), GPIO_PIN(LCD_HD44780_GPIO_DB5)); // idle high
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB5), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_DB5)); // open drain allows to read and write
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_DB4)); // enable clock for GPIO port
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB4), GPIO_PIN(LCD_HD44780_GPIO_DB4)); // idle high
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB4), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_DB4)); // open drain allows to read and write
-#if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_DB3)); // enable clock for GPIO port
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB3), GPIO_PIN(LCD_HD44780_GPIO_DB3)); // idle high
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB3), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_DB3)); // open drain allows to read and write
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_DB2)); // enable clock for GPIO port
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB2), GPIO_PIN(LCD_HD44780_GPIO_DB2)); // idle high
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB2), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_DB2)); // open drain allows to read and write
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_DB1)); // enable clock for GPIO port
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB1), GPIO_PIN(LCD_HD44780_GPIO_DB1)); // idle high
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB1), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_DB1)); // open drain allows to read and write
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_DB0)); // enable clock for GPIO port
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_DB0), GPIO_PIN(LCD_HD44780_GPIO_DB0)); // idle high
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB0), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_DB0)); // open drain allows to read and write
-#endif // LCD_HD44780_INTERFACE_DL
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_RS)); // enable clock for GPIO port
- gpio_clear(GPIO_PORT(LCD_HD44780_GPIO_RS), GPIO_PIN(LCD_HD44780_GPIO_RS)); // set low to read busy flag
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_RS), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_RS)); // set GPIO as output
-#ifdef LCD_HD44780_GPIO_RnW
- rcc_periph_clock_enable(GPIO_RCC(LCD_HD44780_GPIO_RnW)); // enable clock for GPIO port
- gpio_set(GPIO_PORT(LCD_HD44780_GPIO_RnW), GPIO_PIN(LCD_HD44780_GPIO_RnW)); // set high to read
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_RnW), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LCD_HD44780_GPIO_RnW)); // set GPIO as output
-#endif // LCD_HD44780_GPIO_RnW
-#endif // LCD_HD44780_I2C
- // initialize device
- lcd_hd44780_write(true, 0x30, true); // 1st function write set to go to state 1 (8-bit) or 2 (4-bit first nibble) (BF cannot be checked)
- sleep_ms(4 + 1); // wait 4.1 ms
- lcd_hd44780_write(true, 0x30, true); // 2st function write set to go to state 1 (8-bit) or 3 (4-bit second nibble) (BF cannot be checked)
- sleep_us(100 + 10); // wait 100 us
- lcd_hd44780_write(true, 0x30, true); // 3rd function write set to go to state 1 (8-bit) (BF cannot be checked)
- sleep_us(LCD_HD44780_BUSY_WAIT_SHORT); // wait 37 us
-#if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
- lcd_hd44780_function_set(1, n_2lines, f_5x10); // function set
-#else
- lcd_hd44780_write(true, 0x20, true); // switch to 4-bit mode
- sleep_us(LCD_HD44780_BUSY_WAIT_SHORT); // wait 37 us
- lcd_hd44780_function_set(0, n_2lines, f_5x10); // function set
-#endif
- lcd_hd44780_n_2lines = n_2lines; // remember number of lines
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_SHORT);
- lcd_hd44780_display_control(false, false, false); // display off
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_SHORT);
- lcd_hd44780_clear_display(); // display clear
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_LONG);
- lcd_hd44780_entry_mode_set(true, false); // entry mode set
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_SHORT);
-
- return true; // I²C configuration succeeded
-}
-
-void lcd_hd44780_release(void)
-{
-#if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
- i2c_master_release(LCD_HD44780_I2C_PERIPH); // release I²C peripheral
-#else // LCD_HD44780_I2C
- // switch back GPIO back to input
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB7), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_DB7));
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB6), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_DB6));
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB5), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_DB5));
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB4), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_DB4));
-#if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB3), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_DB3));
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB2), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_DB2));
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB1), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_DB1));
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_DB0), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_DB0));
-#endif // LCD_HD44780_INTERFACE_DL
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_RS), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_RS));
-#ifdef LCD_HD44780_GPIO_RnW
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_RnW), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_RnW));
-#endif // LCD_HD44780_GPIO_RnW
- gpio_set_mode(GPIO_PORT(LCD_HD44780_GPIO_E), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LCD_HD44780_GPIO_E));
-#endif // LCD_HD44780_I2C:
-}
-
-void lcd_hd44780_write_data(uint8_t data)
-{
- lcd_hd44780_write(false, data, false);
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_SHORT);
-}
-
-void lcd_hd44780_write_command(uint8_t data)
-{
- lcd_hd44780_write(true, data, false);
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_SHORT);
-}
-
-void lcd_hd44780_clear_display(void)
-{
- lcd_hd44780_write_command(0x01);
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_LONG);
-}
-
-void lcd_hd44780_return_home(void)
-{
- lcd_hd44780_write_command(0x02);
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_LONG);
-}
-
-void lcd_hd44780_entry_mode_set(bool increment, bool shift)
-{
- uint8_t command = 0x04;
- if (increment) {
- command |= 0x02;
- }
- if (shift) {
- command |= 0x01;
- }
- lcd_hd44780_write_command(command);
-}
-
-void lcd_hd44780_display_control(bool d, bool c, bool b)
-{
- uint8_t command = 0x08;
- if (d) {
- command |= 0x04;
- }
- if (c) {
- command |= 0x02;
- }
- if (b) {
- command |= 0x01;
- }
- lcd_hd44780_write_command(command);
-}
-
-void lcd_hd44780_set_cgram_address(uint8_t acg)
-{
- lcd_hd44780_write_command(0x40 | (acg & 0x3f));
-}
-
-void lcd_hd44780_set_ddram_address(uint8_t add)
-{
- lcd_hd44780_write_command(0x80 | (add & 0x7f));
-}
-
-void lcd_hd44780_write_line(bool line2, const char* data, uint8_t length)
-{
- if (line2 && !lcd_hd44780_n_2lines) { // writing line 2 when it does not exists is not possible
- return;
- }
- lcd_hd44780_set_ddram_address(line2 ? 0x40 : 0x00); // set start of line
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_SHORT);
- for (uint8_t i = 0; i < length && i < (lcd_hd44780_n_2lines ? 0x27 : 0x4f); i++) { // write line
- lcd_hd44780_write_data(data[i]); // write character
- lcd_hd44780_wait_busy(LCD_HD44780_BUSY_WAIT_SHORT);
- }
-}
diff --git a/lib/lcd_hd44780.h b/lib/lcd_hd44780.h
deleted file mode 100644
index 2f8a0a7..0000000
--- a/lib/lcd_hd44780.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/** library to communication with Hitacho HD44780 LCD controller
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2019-2020
- * @note peripherals used: GPIO @ref lcd_hd44780_gpio, I²C @ref lcd_hd44780_i2c
- */
-#pragma once
-#error not converted for STM32F4
-#include <libopencm3/stm32/i2c.h> // I²C definitions
-
-/** @defgroup lcd_hd44780_i2c I²C peripheral used to control backpack adapter for the HD44780
- * @{
- */
-/** set I²C peripheral if I²C backpack adapter(s) is(/are) used */
-//#define LCD_HD44780_I2C I2C1
-/** @} */
-
-#ifdef LCD_HD44780_I2C
-/** I²C address of I²C backpack adapter (7 bits are LSb) */
-extern uint8_t lcd_hd44780_i2c_addr;
-#endif
-
-/** setup peripherals to start communicating with HD4478
- * @param[in] n_2lines 2 (true) or 1 (false) lines
- * @param[in] f_5x10 5x10 (true) or 5x8 (false) dots font
- * @return if the display setup is successful, else the display is probably not on the I²C bus (or the I²C bus does not work)
- */
-bool lcd_hd44780_setup(bool n_2lines, bool f_5x10);
-/** release peripherals */
-void lcd_hd44780_release(void);
-/** read data (from CG or DDRAM)
- * @return read data
- */
-uint8_t lcd_hd44780_read_data(void);
-/** write data (to CG or DDRAM)
- * @param[in] data data to write
- * @warning does not wait for operation to complete: use lcd_hd44780_wait_busy(37)
- */
-void lcd_hd44780_write_data(uint8_t data);
-/** write command
- * @param[in] data instruction to write
- * @warning does not wait for operation to complete: use lcd_hd44780_wait_busy(37)
- */
-void lcd_hd44780_write_command(uint8_t data);
-/** clears entire display and sets DDRAM address 0 in address counter
- * @warning does not wait for operation to complete: use lcd_hd44780_wait_busy(1520)
- */
-void lcd_hd44780_clear_display(void);
-/** sets DDRAM address 0 in address counter, also returns display from being shifted to original position
- * @warning does not wait for operation to complete: use lcd_hd44780_wait_busy(1520);
- */
-void lcd_hd44780_return_home(void);
-/** sets cursor move direction and specifies display shift
- * @param[in] increment true = increment, false = decrement
- * @param[in] shift true = accompanies display shift
- * @warning does not wait for operation to complete: use lcd_hd44780_wait_busy(37);
- */
-void lcd_hd44780_entry_mode_set(bool increment, bool shift);
-/** set display control
- * @param[in] d entire display on (true) / off (false)
- * @param[in] c cursor on (true) / off (false)
- * @param[in] b blinking of cursor position character on (true) / off (false)
- * @warning does not wait for operation to complete: use lcd_hd44780_wait_busy(37);
- */
-void lcd_hd44780_display_control(bool d, bool c, bool b);
-/** sets CGRAM address. CGRAM data is sent and received after this setting.
- * @param[in] acg CGRAM address
- * @warning does not wait for operation to complete: use lcd_hd44780_wait_busy(37);
- */
-void lcd_hd44780_set_cgram_address(uint8_t acg);
-/** sets DDRAM address. DDRAM data is sent and received after this setting.
- * @param[in] add DDRAM address
- * @warning does not wait for operation to complete: use lcd_hd44780_wait_busy(37);
- */
-void lcd_hd44780_set_ddram_address(uint8_t add);
-/** utility to write entire line
- * @param[in] line2 write line 1 (false) or 2 (true)
- * @param[in] data characters to write on the line
- * @param[in] length number of characters to write
- */
-void lcd_hd44780_write_line(bool line2, const char* data, uint8_t length);
diff --git a/lib/led_max7219.c b/lib/led_max7219.c
deleted file mode 100644
index 80eceea..0000000
--- a/lib/led_max7219.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/** library to communicate with a Titan Micro MAX7219 IC attached to a 4-digit 7-segment (code)
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017
- * @note peripherals used: GPIO @ref led_max7219_gpio, timer @ref led_tm1637_timer
- * @warning all calls are blocking
- *
- * bit vs segment: 0bpabcdefg
- * +a+
- * f b
- * +g+
- * e c p
- * +d+
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <string.h> // string utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/spi.h> // SPI library
-#include <libopencm3/stm32/timer.h> // timer library
-
-#include "global.h" // global utilities
-#include "led_max7219.h" // MAX7219 header and definitions
-
-/** @defgroup led_max7219_gpio GPIO used to control MAX7219 IC load line
- * @{
- */
-#define LED_MAX7219_LOAD_PORT B /**< port for load line */
-#define LED_MAX7219_LOAD_PIN 12 /**< pin for load line */
-/** @} */
-
-/** @defgroup led_max7219_spi SPI used to communication with MAX7219 IC
- * @{
- */
-#define LED_MAX7219_SPI 2 /**< SPI to send data */
-/** @} */
-
-/** ASCII characters encoded for the 7 segments digit block
- * @note starts with space
- */
-static const uint8_t ascii_7segments[] = {
- 0x00, // space
- 0x06, // ! (I)
- 0x22, // "
- 0x1d, // # (o)
- 0x5b, // $ (s)
- 0x25, // % (/)
- 0x5f, // & (6)
- 0x02, // '
- 0x4e, // ( ([)
- 0x78, // )
- 0x07, // *
- 0x31, // +
- 0x04, // ,
- 0x01, // -
- 0x04, // . (,)
- 0x25, // /
- 0x7e, // 0
- 0x30, // 1
- 0x6d, // 2
- 0x79, // 3
- 0x33, // 4
- 0x5b, // 5
- 0x5f, // 6
- 0x70, // 7
- 0x7f, // 8
- 0x7b, // 9
- 0x09, // : (=)
- 0x09, // ; (=)
- 0x0d, // <
- 0x09, // =
- 0x19, // >
- 0x65, // ?
- 0x6f, // @
- 0x77, // A
- 0x7f, // B
- 0x4e, // C
- 0x3d, // D
- 0x4f, // E
- 0x47, // F
- 0x5e, // G
- 0x37, // H
- 0x06, // I
- 0x3c, // J
- 0x37, // K
- 0x0e, // L
- 0x76, // M
- 0x76, // N
- 0x7e, // O
- 0x67, // P
- 0x6b, // Q
- 0x66, // R
- 0x5b, // S
- 0x0f, // T
- 0x3e, // U
- 0x3e, // V (U)
- 0x3e, // W (U)
- 0x37, // X (H)
- 0x3b, // Y
- 0x6d, // Z
- 0x4e, // [
- 0x13, // '\'
- 0x78, // /
- 0x62, // ^
- 0x08, // _
- 0x20, // `
- 0x7d, // a
- 0x1f, // b
- 0x0d, // c
- 0x3d, // d
- 0x6f, // e
- 0x47, // f
- 0x7b, // g
- 0x17, // h
- 0x04, // i
- 0x18, // j
- 0x37, // k
- 0x06, // l
- 0x15, // m
- 0x15, // n
- 0x1d, // o
- 0x67, // p
- 0x73, // q
- 0x05, // r
- 0x5b, // s
- 0x0f, // t
- 0x1c, // u
- 0x1c, // v (u)
- 0x1c, // w (u)
- 0x37, // x
- 0x3b, // y
- 0x6d, // z
- 0x4e, // { ([)
- 0x06, // |
- 0x78, // } ([)
- 0x01, // ~
-};
-
-/** number of display in the chain */
-uint8_t lex_max7219_displays = 0;
-
-/** write data on SPI bus and handle load signal
- * @param[in] data bytes to write
- * @param[in] display display number in chain (0xff for all)
- */
-static void led_max7219_write(uint16_t data, uint8_t display)
-{
- if (lex_max7219_displays<=display && 0xff!=display) { // display no in chain
- return;
- }
-
- gpio_clear(GPIO(LED_MAX7219_LOAD_PORT), GPIO(LED_MAX7219_LOAD_PIN)); // ensure load pin is low (data is put in MAX7219 register on rising edge)
- for (uint8_t i=lex_max7219_displays; i>0; i--) { // go though all displays
- while (SPI_SR(SPI(LED_MAX7219_SPI))&SPI_SR_BSY); // wait until not busy
- if (0xff==display || i==(display+1)) { // right display or broadcast message
- spi_send(SPI(LED_MAX7219_SPI), data); // send data
- } else {
- spi_send(SPI(LED_MAX7219_SPI), 0x0000); // send no-op command to shift command to correct display or out
- }
- while (!(SPI_SR(SPI(LED_MAX7219_SPI))&SPI_SR_TXE)); // wait until Tx is empty (reference manual says BSY should also cover this, but it doesn't)
- while (SPI_SR(SPI(LED_MAX7219_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
- }
- gpio_set(GPIO(LED_MAX7219_LOAD_PORT), GPIO(LED_MAX7219_LOAD_PIN)); // create rising edge on load pin for data to be set in MAX7219 register
-}
-
-void led_max7219_setup(uint8_t displays)
-{
- // saved number of displays
- lex_max7219_displays = displays;
-
- // configure GPIO for load line
- rcc_periph_clock_enable(RCC_GPIO(LED_MAX7219_LOAD_PORT)); // enable clock for GPIO peripheral
- gpio_clear(GPIO(LED_MAX7219_LOAD_PORT), GPIO(LED_MAX7219_LOAD_PIN)); // idle low (load on rising edge)
- gpio_set_mode(GPIO(LED_MAX7219_LOAD_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(LED_MAX7219_LOAD_PIN)); // set as output
-
- // configure SPI peripheral
- rcc_periph_clock_enable(RCC_SPI_SCK_PORT(LED_MAX7219_SPI)); // enable clock for GPIO peripheral for clock signal
- gpio_set_mode(SPI_SCK_PORT(LED_MAX7219_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(LED_MAX7219_SPI)); // set as output (max clock speed for MAX7219 is 10 MHz)
- rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(LED_MAX7219_SPI)); // enable clock for GPIO peripheral for MOSI signal
- gpio_set_mode(SPI_MOSI_PORT(LED_MAX7219_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(LED_MAX7219_SPI)); // set as output
- rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
- rcc_periph_clock_enable(RCC_SPI(LED_MAX7219_SPI)); // enable clock for SPI peripheral
- spi_reset(SPI(LED_MAX7219_SPI)); // clear SPI values to default
- spi_init_master(SPI(LED_MAX7219_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_16BIT, SPI_CR1_MSBFIRST); // initialise SPI as master, divide clock by 8 since max MAX7219 clock is 10 MHz and max SPI PCLK clock is 72 Mhz, depending on which SPI is used, set clock polarity to idle low (as in the datasheet of the MAX7219, but not that important), set clock phase to go high when bit is set (depends on polarity) as data is stored on MAX7219 on rising edge), use 16 bits frames (as used by MAX7219), use MSB first
- spi_set_unidirectional_mode(SPI(LED_MAX7219_SPI)); // we only need to transmit data
- spi_enable(SPI(LED_MAX7219_SPI)); // enable SPI
-}
-
-void led_max7219_on(uint8_t display)
-{
- led_max7219_write(0x0C01, display); // put in normal operation more (registers remain as set)
-}
-
-void led_max7219_off(uint8_t display)
-{
- led_max7219_write(0x0C00, display); // put in shutdown mode (registers remain as set)
-}
-
-void led_max7219_test(bool test, uint8_t display)
-{
- if (test) {
- led_max7219_write(0x0F01, display); // go into display test mode
- } else {
- led_max7219_write(0x0F00, display); // go into normal operation mode
- }
-}
-
-void led_max7219_intensity(uint8_t intensity, uint8_t digits, uint8_t display)
-{
- if (intensity>15) { // intensity must be 0-15 (corresponds to (2*brightness+1)/32)
- return;
- }
- if (digits<1 || digits>8) { // scan limit must bit 0-7
- return;
- }
- led_max7219_write(0x0A00+intensity, display); // set brightness
- led_max7219_write(0x0B00+digits-1, display); // set scan limit to display digits
-}
-
-bool led_max7219_text(char* text, uint8_t display)
-{
- for (uint8_t i=0; i<8; i++) { // input text should only contain printable character (8th bit is used for dots)
- if ((text[i]&0x7f)<' ' || (text[i]&0x7f)>=' '+LENGTH(ascii_7segments)) {
- return false;
- }
- }
- led_max7219_write(0x0900, display); // disable BCD decoding on all 7 digits
- for (uint8_t i=0; i<8; i++) { // display text
- led_max7219_write(((i+1)<<8)+(ascii_7segments[(text[7-i]&0x7f)-' '])+(text[7-i]&0x80), display); // send digit (in reverse order)
- }
- return true;
-}
-
-void led_max7219_number(uint32_t number, uint8_t dots, uint8_t display)
-{
- led_max7219_write(0x09FF, display); // enable BCD decoding on all 7 digits
- for (uint8_t digit=0; digit<8; digit++) { // go through digits
- if (0==digit) { // display 0 on 0 only to first digit
- led_max7219_write(((digit+1)<<8) + (number%10) + (((dots>>digit)&0x01)<<7), display); // display digit
- } else if (0==number) { // display blank on other digits
- led_max7219_write(((digit+1)<<8) + 0x0F + (((dots>>digit)&0x01)<<7), display); // display blank
- } else {
- led_max7219_write(((digit+1)<<8) + (number%10) + (((dots>>digit)&0x01)<<7), display); // display digit
- }
- number /= 10; // get next digit
- }
-}
diff --git a/lib/led_max7219.h b/lib/led_max7219.h
deleted file mode 100644
index 1dc9b4f..0000000
--- a/lib/led_max7219.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/** library to communicate with a Maxim MAX7219 IC attached to a 8-digit 7-segment
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017
- * @note peripherals used: GPIO @ref led_max7219_gpio, SPI @ref led_max7219_spi
- * @warning all calls are blocking
- */
-#pragma once
-#error not converted for STM32F4
-
-/** setup communication with MAX7219 IC
- * @param[in] displays number of displays in the chain
- */
-void led_max7219_setup(uint8_t displays);
-/** do nothing (no operation)
- * @param[in] display display number in chain (0xff for all)
- * @note send it to the last display in the chain to clear the previous command from the chain
- */
-void led_max7219_nop(uint8_t display);
-/** switch display on
- * @param[in] display display number in chain (0xff for all)
- */
-void led_max7219_on(uint8_t display);
-/** switch display off
- * @param[in] display display number in chain (0xff for all)
- */
-void led_max7219_off(uint8_t display);
-/** switch display in test or normal operation mode
- * @param[in] test switch in test mode (else normal operation)
- * @param[in] display display number in chain (0xff for all)
- */
-void led_max7219_test(bool test, uint8_t display);
-/** set display intensity
- * @param[in] intensity level to set (0-15)
- * @param[in] digits number of digits to display (1-8)
- * @param[in] display display number in chain (0xff for all)
- */
-void led_max7219_intensity(uint8_t intensity, uint8_t digits, uint8_t display);
-/** display text
- * @param[in] text text to display (8 characters)
- * @param[in] display display number in chain (0xff for all)
- * @note use first bit of each character to enable dot
- * @return false if string has unsupported characters
- */
-bool led_max7219_text(char* text, uint8_t display);
-/** display number
- * @param[in] number number to display (8 digits max)
- * @param[in] dots set bit if dot on corresponding digit should be displayed
- * @param[in] display display number in chain (0xff for all)
- */
-void led_max7219_number(uint32_t number, uint8_t dots, uint8_t display);
diff --git a/lib/led_sk6812rgbw.c b/lib/led_sk6812rgbw.c
deleted file mode 100644
index d42d5ed..0000000
--- a/lib/led_sk6812rgbw.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/** library to drive a SK6812RGBW LED chain
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: SPI @ref led_sk6812rgbw_spi, DMA
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/spi.h> // SPI library
-#include <libopencm3/stm32/dma.h> // DMA library
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-
-#include "led_sk6812rgbw.h" // LED SK6812RGBW library API
-#include "global.h" // common methods
-
-/** peripheral configuration */
-/** @defgroup led_sk6812rgbw_spi SPI peripheral used to control the SK6812RGBW LEDs
- * @{
- */
-/** SPI peripheral
- * @note SPI2 is 5V tolerant and can be operated in open-drain mode with 1-10 kO pull-up resistor to 5V to get 5V signal level
- */
-#define LED_SK6812RGBW_SPI 2 /**< SPI peripheral */
-/** @} */
-
-/** bit template to encode one byte to be shifted out by SPI to the SK6812RGBW LEDs
- * @details For each SK6812RGBW bit which needs to be transferred we require to transfer 3 SPI bits.
- * The first SPI bit is the high start of the SK6812RGBW bit frame.
- * The second SPI bit determines if the SK6812RGBW bit is a 0 or 1.
- * The third SPI bit is the last part of the SK6812RGBW bit frame, which is always low.
- * The binary pattern is 0b100100100100100100100100
- * Since we encode it LSb first (for easy bit banding across bytes): 01001001 10010010 00100100 = 0x499224
- */
-#define LED_SK6812RGBW_SPI_TEMPLATE 0x499224
-
-/** data encoded to be shifted out by SPI for the SK6812RGBW, plus the 50us reset (~40 data bits) */
-static uint8_t led_sk6812rgbw_data[LED_SK6812RGBW_LEDS * 3 * 4 + 40 * 3 / 8 + 1] = {0};
-
-void led_sk6812rgbw_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
-{
- // verify the led exists
- if (led >= LED_SK6812RGBW_LEDS) {
- return;
- }
-
- // we use bit-banding to set the bit. I did not test if it is more efficient than setting the bit directly, but I wanted to use this cool feature
- uint32_t data_bitband = 0x22000000 + ((uint32_t)&led_sk6812rgbw_data[0] - 0x20000000) * 32; // get base address of data to bit band
- data_bitband += led * 4 * 24 * 4; // get address for current LED (there are 4 colors per LED, each color uses 24 bits, each bit is encoded in one 32-bit word)
- for (uint8_t bit = 0; bit < 8; bit++) { // bit from the color to set/clear
- const uint8_t byte_bit = (1 << bit); // which bit to check
- const uint8_t data_bit = (7 - bit) * 3 + 1; // the bit in the data stream
- // set the bitband bit to the corresponding color bit
- *(uint32_t*)(data_bitband + (0 * 24 + data_bit) * 4) = ((green & byte_bit) ? 1 : 0);
- *(uint32_t*)(data_bitband + (1 * 24 + data_bit) * 4) = ((red & byte_bit) ? 1 : 0);
- *(uint32_t*)(data_bitband + (2 * 24 + data_bit) * 4) = ((blue & byte_bit) ? 1 : 0);
- *(uint32_t*)(data_bitband + (3 * 24 + data_bit) * 4) = ((white & byte_bit) ? 1 : 0);
- }
-}
-
-void led_sk6812rgbw_setup(void)
-{
- // fill buffer with bit pattern
- for (uint16_t led = 0; led < LED_SK6812RGBW_LEDS; led++) {
- for (uint8_t color = 0; color < 4; color++) {
- led_sk6812rgbw_data[led * 3 * 4 + color * 3 + 0] = (uint8_t)(LED_SK6812RGBW_SPI_TEMPLATE >> 16);
- led_sk6812rgbw_data[led * 3 * 4 + color * 3 + 1] = (uint8_t)(LED_SK6812RGBW_SPI_TEMPLATE >> 8);
- led_sk6812rgbw_data[led * 3 * 4 + color * 3 + 2] = (uint8_t)(LED_SK6812RGBW_SPI_TEMPLATE >> 0);
- }
- }
- // fill remaining with with 0 to encode the reset code
- for (uint16_t i = LED_SK6812RGBW_LEDS * 3 * 4; i < LENGTH(led_sk6812rgbw_data); i++) {
- led_sk6812rgbw_data[i] = 0;
- }
-
- // setup SPI to transmit data
- rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(LED_SK6812RGBW_SPI)); // enable clock for SPI output peripheral
- gpio_set_mode(SPI_MOSI_PORT(LED_SK6812RGBW_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(LED_SK6812RGBW_SPI)); // set MOSI as output (push-pull needs to be shifted to 5V, open-drain consumes up to 5 mA with pull-up resistor of 1 kO)
- rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
- rcc_periph_clock_enable(RCC_SPI(LED_SK6812RGBW_SPI)); // enable clock for SPI peripheral
- spi_reset(SPI(LED_SK6812RGBW_SPI)); // clear SPI values to default
- spi_set_master_mode(SPI(LED_SK6812RGBW_SPI)); // set SPI as master since we generate the clock
- spi_set_baudrate_prescaler(SPI(LED_SK6812RGBW_SPI), SPI_CR1_BR_FPCLK_DIV_16); // set clock to 0.44 us per bit
- spi_set_clock_polarity_1(SPI(LED_SK6812RGBW_SPI)); // clock is high when idle
- spi_set_clock_phase_1(SPI(LED_SK6812RGBW_SPI)); // output data on second edge (rising)
- spi_set_dff_8bit(SPI(LED_SK6812RGBW_SPI)); // use 8 bits for simpler encoding (but there will be more interrupts)
- spi_send_lsb_first(SPI(LED_SK6812RGBW_SPI)); // send least significant bit first (helps during bit banding)
- spi_set_bidirectional_transmit_only_mode(SPI(LED_SK6812RGBW_SPI)); // we won't receive data
- spi_set_unidirectional_mode(SPI(LED_SK6812RGBW_SPI)); // we only need to transmit data
- spi_enable_software_slave_management(SPI(LED_SK6812RGBW_SPI)); // control the slave select in software (so we can start transmission)
- spi_set_nss_high(SPI(LED_SK6812RGBW_SPI)); // set NSS high so we can output
- spi_enable(SPI(LED_SK6812RGBW_SPI)); // enable SPI
-
- // configure DMA to provide the pattern to be shifted out from SPI to the SK6812RGBW LEDs
- rcc_periph_clock_enable(RCC_DMA_SPI(LED_SK6812RGBW_SPI)); // enable clock for DMA peripheral
- dma_channel_reset(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI)); // start with fresh channel configuration
- dma_set_read_from_memory(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI)); // set direction from memory to peripheral
- dma_set_memory_size(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI), DMA_CCR_MSIZE_8BIT); // read 8 bits from memory
- dma_set_memory_address(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI), (uint32_t)led_sk6812rgbw_data); // set bit pattern as source address
- dma_enable_memory_increment_mode(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI)); // go through bit pattern
- dma_set_number_of_data(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI), LENGTH(led_sk6812rgbw_data)); // set the size of the data to transmit
- dma_set_peripheral_address(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI), (uint32_t)&SPI_DR(SPI(LED_SK6812RGBW_SPI))); // set SPI as peripheral destination address
- dma_set_peripheral_size(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI), DMA_CCR_PSIZE_8BIT); // write 8 bits to peripheral
- dma_set_priority(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI), DMA_CCR_PL_HIGH); // set priority to high since time is crucial for the peripheral
- dma_enable_circular_mode(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI)); // always send the data
- dma_enable_channel(DMA_SPI(LED_SK6812RGBW_SPI), DMA_CHANNEL_SPI_TX(LED_SK6812RGBW_SPI)); // enable DMA channel
- spi_enable_tx_dma(SPI(LED_SK6812RGBW_SPI)); // use DMA to provide data stream to be transferred
-}
diff --git a/lib/led_sk6812rgbw.h b/lib/led_sk6812rgbw.h
deleted file mode 100644
index f38dcef..0000000
--- a/lib/led_sk6812rgbw.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/** library to drive a SK6812RGBW LED chain
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: SPI @ref led_sk6812rgbw_spi, DMA
- */
-#pragma once
-#error not converted for STM32F4
-
-/** number of LEDs on the SK6812RGBW strip */
-#define LED_SK6812RGBW_LEDS (16 * 2)
-
-/** setup SK6812RGBW LED driver
- * @note this starts the continuous transmission
- */
-void led_sk6812rgbw_setup(void);
-/** set color of a single LED
- * @param[in] led the LED number to set the color
- * @param[in] red the red color value to set on the LED
- * @param[in] green the green color value to set on the LED
- * @param[in] blue the blue color value to set on the LED
- * @param[in] white the white color value to set on the LED
- */
-void led_sk6812rgbw_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue, uint8_t white);
diff --git a/lib/led_tm1637.c b/lib/led_tm1637.c
deleted file mode 100644
index 76f4b48..0000000
--- a/lib/led_tm1637.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/** library to communicate with a Titan Micro TM1637 IC attached to a 4-digit 7-segment
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @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
- *
- * bit vs segment: 0bpgfedcba
- * +a+
- * f b p
- * +g+
- * e c p
- * +d+
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <string.h> // string utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/timer.h> // timer library
-
-#include "global.h" // global utilities
-#include "led_tm1637.h" // TM1637 header and definitions
-
-/** @defgroup led_tm1637_gpio GPIO used to communication with TM1637 IC
- * @{
- */
-#define LED_TM1637_CLK_PIN PB6 /**< pin for CLK signal */
-#define LED_TM1637_DIO_PIN PB7 /**< pin for DIO signal */
-/** @} */
-
-/** @defgroup led_tm1637_timer timer used to communication with TM1637 IC
- * @{
- */
-#define LED_TM1637_TIMER 3 /**< timer to create signal */
-/** @} */
-
-/** display brightness */
-static enum led_tm1637_brightness_t display_brightness = LED_TM1637_14DIV16;
-/** if display is on */
-static bool display_on = false;
-/** display buffer */
-static uint8_t led_tm1637_digits[4] = {0};
-/** if the display is upside down */
-bool led_tm1637_updown = false;
-
-/** ASCII characters encoded for the 7 segments digit block
- * @note starts with space
- */
-static const uint8_t ascii_7segments[] = {
- 0x00, // 0b00000000 space
- 0x30, // 0b00110000 ! (I)
- 0x22, // 0b00100010 "
- 0x5c, // 0b01011100 # (o)
- 0x6d, // 0b01101101 $ (s)
- 0x52, // 0b01010010 % (/)
- 0x7d, // 0b01111101 & (6)
- 0x20, // 0b00100000 '
- 0x39, // 0b00111001 ( ([)
- 0x0f, // 0b00001111 )
- 0x70, // 0b01110000 *
- 0x46, // 0b01000110 +
- 0x10, // 0b00010000 ,
- 0x40, // 0b01000000 -
- 0x10, // 0b00010000 . (,)
- 0x52, // 0b01010010 /
- 0x3f, // 0b00111111 0
- 0x06, // 0b00000110 1
- 0x5b, // 0b01011011 2
- 0x4f, // 0b01001111 3
- 0x66, // 0b01100110 4
- 0x6d, // 0b01101101 5
- 0x7d, // 0b01111101 6
- 0x07, // 0b00000111 7
- 0x7f, // 0b01111111 8
- 0x6f, // 0b01101111 9
- 0x48, // 0b01001000 : (=)
- 0x48, // 0b01001000 ; (=)
- 0x58, // 0b01011000 <
- 0x48, // 0b01001000 =
- 0x4c, // 0b01001100 >
- 0x53, // 0b01010011 ?
- 0x7b, // 0b01111011 @
- 0x77, // 0b01110111 A
- 0x7f, // 0b01111111 B
- 0x39, // 0b00111001 C
- 0x5e, // 0b01011110 D
- 0x79, // 0b01111001 E
- 0x71, // 0b01110001 F
- 0x3d, // 0b00111101 G
- 0x76, // 0b01110110 H
- 0x30, // 0b00110000 I
- 0x1e, // 0b00011110 J
- 0x76, // 0b01110110 K
- 0x38, // 0b00111000 L
- 0x37, // 0b00110111 M
- 0x37, // 0b00110111 N
- 0x3f, // 0b00111111 O
- 0x73, // 0b01110011 P
- 0x6b, // 0b01101011 Q
- 0x33, // 0b00110011 R
- 0x6d, // 0b01101101 S
- 0x78, // 0b01111000 T
- 0x3e, // 0b00111110 U
- 0x3e, // 0b00111110 V (U)
- 0x3e, // 0b00111110 W (U)
- 0x76, // 0b01110110 X (H)
- 0x6e, // 0b01101110 Y
- 0x5b, // 0b01011011 Z
- 0x39, // 0b00111001 [
- 0x64, // 0b01100100 '\'
- 0x0f, // 0b00001111 /
- 0x23, // 0b00100011 ^
- 0x08, // 0b00001000 _
- 0x02, // 0b00000010 `
- 0x5f, // 0b01011111 a
- 0x7c, // 0b01111100 b
- 0x58, // 0b01011000 c
- 0x5e, // 0b01011110 d
- 0x7b, // 0b01111011 e
- 0x71, // 0b01110001 f
- 0x6f, // 0b01101111 g
- 0x74, // 0b01110100 h
- 0x10, // 0b00010000 i
- 0x0c, // 0b00001100 j
- 0x76, // 0b01110110 k
- 0x30, // 0b00110000 l
- 0x54, // 0b01010100 m
- 0x54, // 0b01010100 n
- 0x5c, // 0b01011100 o
- 0x73, // 0b01110011 p
- 0x67, // 0b01100111 q
- 0x50, // 0b01010000 r
- 0x6d, // 0b01101101 s
- 0x78, // 0b01111000 t
- 0x1c, // 0b00011100 u
- 0x1c, // 0b00011100 v (u)
- 0x1c, // 0b00011100 w (u)
- 0x76, // 0b01110110 x
- 0x6e, // 0b01101110 y
- 0x5b, // 0b01011011 z
- 0x39, // 0b00111001 { ([)
- 0x30, // 0b00110000 |
- 0x0f, // 0b00001111 } ([)
- 0x40, // 0b01000000 ~
-};
-
-
-/** convert the data for upside down displays
- * @param[in] data the data to be converted
- * @return the upside down data
- */
-static uint8_t led_tm1637_rotate(uint8_t data)
-{
- uint8_t converted = 0;
- converted |= (data & 0xc0); // keep g and dot
- converted |= (data << 3) & 0x38; // rotate abc
- converted |= (data >> 3) & 0x07; // rotate def
- return converted;
-}
-
-void led_tm1637_setup(bool updown)
-{
- led_tm1637_updown = updown; // remember if the display is upside down
-
- // 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
- 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
- // 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_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)
-}
-
-/** wait until clock tick (timer overflow) occurred
- */
-static inline void led_tm1637_tick(void)
-{
- while (!timer_get_flag(TIM(LED_TM1637_TIMER), TIM_SR_UIF)); // wait until counter overflow update event happens
- timer_clear_flag(TIM(LED_TM1637_TIMER), TIM_SR_UIF); // clear event flag
-}
-
-/** write data on bus
- * @param[in] data bytes to write
- * @param[in] length number of bytes to write
- * @return if write succeeded
- * @note includes start and stop conditions
- */
-static bool led_tm1637_write(const uint8_t* data, size_t length)
-{
- bool to_return = true; // return if write succeeded
- if (NULL == data || 0 == length) { // verify there it data to be read
- return false;
- }
-
- // enable timer for signal generation
- timer_set_counter(TIM(LED_TM1637_TIMER), 0); // reset timer counter
- timer_enable_counter(TIM(LED_TM1637_TIMER)); // enable timer to generate timing
- led_tm1637_tick(); // wait to enforce minimum time since last write
-
- // send start condition (DIO then CLK low)
- gpio_clear(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_PIN(LED_TM1637_DIO_PIN)); // put DIO low
- led_tm1637_tick(); // wait for next tick
- gpio_clear(GPIO_PORT(LED_TM1637_CLK_PIN), GPIO_PIN(LED_TM1637_CLK_PIN)); // put CLK low
-
- // send data bytes (MSb first)
- for (size_t i = 0; i < length; i++) { // send all bytes
- uint8_t byte = data[i];
- for (uint8_t b = 0; b < 8; b++) { // send all bits
- if (byte & 0x1) { // send a 1
- gpio_set(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_PIN(LED_TM1637_DIO_PIN)); // put DIO high
- } else {
- gpio_clear(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_PIN(LED_TM1637_DIO_PIN)); // put DIO low
- }
- byte >>= 1; // shift data
- 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 (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
- 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
- to_return = false; // remember there was an error
- break; // stop sending bytes
- }
- 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
- }
-
- // 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
- 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
- gpio_set(GPIO_PORT(LED_TM1637_DIO_PIN), GPIO_PIN(LED_TM1637_DIO_PIN)); // put DIO high
- timer_disable_counter(TIM(LED_TM1637_TIMER)); // stop timer since it's not used anymore
-
- return to_return;
-}
-
-/** write all data to SRAM (automatic address adding, normal) and control display
- * @return if write succeeded
- */
-static bool led_tm1637_update(void)
-{
- const uint8_t write[] = { 0x40 }; // command: write data, automatic address adding, normal
- uint8_t data[] = { 0xc0, led_tm1637_digits[0], led_tm1637_digits[1], led_tm1637_digits[2], led_tm1637_digits[3] }; // set digits (start at address 0)
- if (led_tm1637_updown) { // rotate data
- data[1] = led_tm1637_rotate(led_tm1637_digits[3]);
- data[2] = led_tm1637_rotate(led_tm1637_digits[2]) | (led_tm1637_digits[1] & 0x80); // keep the : for the time
- data[3] = led_tm1637_rotate(led_tm1637_digits[1]) & 0x7f; // remove the : for the time
- data[4] = led_tm1637_rotate(led_tm1637_digits[0]);
- }
- const uint8_t control[] = { (display_on ? 0x88 : 0x80) + (display_brightness & 0x7) }; // command to turn display on/off and set brightness
- return led_tm1637_write(write, LENGTH(write)) && led_tm1637_write(data, LENGTH(data)) && led_tm1637_write(control, LENGTH(control)); // send commands
-}
-
-bool led_tm1637_on(void)
-{
- display_on = true; // remember display is on
- return led_tm1637_update();
-}
-
-bool led_tm1637_off(void)
-{
- display_on = false; // remember display is off
- return led_tm1637_update();
-}
-
-bool led_tm1637_brightness(enum led_tm1637_brightness_t brightness)
-{
- display_brightness = brightness; // save brightness
- return led_tm1637_update();
-}
-
-bool led_tm1637_number(uint16_t number, bool zero)
-{
- const uint8_t digits[] = { // digits to display
- (number / 1000) % 10,
- (number / 100) % 10,
- (number / 10) % 10,
- (number / 1) % 10,
- };
- // convert digits to text to be displayed
- if (0 == digits[0] && !zero) {
- led_tm1637_digits[0] = ascii_7segments[' ' - ' '];
- } else {
- led_tm1637_digits[0] = ascii_7segments[digits[0] + '0' - ' '];
- }
- if (0 == digits[0] && 0 == digits[1] && !zero) {
- led_tm1637_digits[1] = ascii_7segments[' ' - ' '];
- } else {
- led_tm1637_digits[1] = ascii_7segments[digits[1] + '0' - ' '];
- }
- if (0 == digits[0] && 0 == digits[1] && 0 == digits[2] && !zero) {
- led_tm1637_digits[2] = ascii_7segments[' ' - ' '];
- } else {
- led_tm1637_digits[2] = ascii_7segments[digits[2] + '0' - ' '];
- }
- led_tm1637_digits[3] = ascii_7segments[digits[3] + '0' - ' '];
-
- return led_tm1637_update(); // display number
-}
-
-bool led_tm1637_time(uint8_t hours, uint8_t minutes)
-{
- // set digits
- led_tm1637_digits[0] = ascii_7segments[((hours / 10) % 10) + '0' - ' '];
- led_tm1637_digits[1] = ascii_7segments[((hours / 1) % 10) + '0' - ' '] | 0x80;
- led_tm1637_digits[2] = ascii_7segments[((minutes / 10) % 10) + '0' - ' '];
- led_tm1637_digits[3] = ascii_7segments[((minutes / 1) % 10) + '0' - ' '];
-
- return led_tm1637_update(); // display time
-}
-
-bool led_tm1637_text(char* text)
-{
- if (strlen(text) != 4) { // input text should have exactly 4 characters
- return false;
- }
- for (uint8_t i = 0; i < 4; i++) { // input text should only contain printable character (8th bit is used for dots)
- if ((text[i] & 0x7f) < ' ' || (text[i] & 0x7f) >= ' ' + LENGTH(ascii_7segments)) {
- return false;
- }
- }
-
- // set digits
- led_tm1637_digits[0] = ascii_7segments[(text[0] & 0x7f) - ' '] | (text[0] & 0x80);
- led_tm1637_digits[1] = ascii_7segments[(text[1] & 0x7f) - ' '] | (text[1] & 0x80);
- led_tm1637_digits[2] = ascii_7segments[(text[2] & 0x7f) - ' '] | (text[2] & 0x80);
- led_tm1637_digits[3] = ascii_7segments[(text[3] & 0x7f) - ' '] | (text[3] & 0x80);
-
- return led_tm1637_update(); // display test
-}
diff --git a/lib/led_tm1637.h b/lib/led_tm1637.h
deleted file mode 100644
index 6559234..0000000
--- a/lib/led_tm1637.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/** library to communicate with a Titan Micro TM1637 IC attached to a 4-digit 7-segment
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: GPIO @ref led_tm1637_gpio, timer @ref led_tm1637_timer
- * @warning all calls are blocking
- */
-#pragma once
-#error not converted for STM32F4
-
-/** display brightness levels
- */
-enum led_tm1637_brightness_t {
- LED_TM1637_1DIV16 = 0,
- LED_TM1637_2DIV16 = 1,
- LED_TM1637_4DIV16 = 2,
- LED_TM1637_10DIV16 = 3,
- LED_TM1637_11DIV16 = 4,
- LED_TM1637_12DIV16 = 5,
- LED_TM1637_13DIV16 = 6,
- LED_TM1637_14DIV16 = 7,
-};
-
-/** setup communication with TM1637 IC
- * @param[in] updown if the display is upside down
- */
-void led_tm1637_setup(bool updown);
-/** switch display on
- * @return if transmission succeeded
- */
-bool led_tm1637_on(void);
-/** switch display off
- * @return if transmission succeeded
- */
-bool led_tm1637_off(void);
-/** set display brightness
- * @param[in] brightness brightness level to set
- * @return if transmission succeeded
- */
-bool led_tm1637_brightness(enum led_tm1637_brightness_t brightness);
-/** display number
- * @param[in] number number to display (0-9999)
- * @param[in] zero pad number with zero on the left
- * @return if transmission succeeded
- */
-bool led_tm1637_number(uint16_t number, bool zero);
-/** display time
- * @param[in] hours hours to display (0-99)
- * @param[in] minutes minutes to display (0-99)
- * @note display separator between hours and minutes
- * @return if transmission succeeded
- */
-bool led_tm1637_time(uint8_t hours, uint8_t minutes);
-/** display text
- * @param[in] text text to display (4 characters)
- * @note use first bit of each character to enable dot
- * @return if transmission succeeded
- */
-bool led_tm1637_text(char* text);
diff --git a/lib/led_ws2812b.c b/lib/led_ws2812b.c
deleted file mode 100644
index f80e7cf..0000000
--- a/lib/led_ws2812b.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/** library to drive a WS2812B LED chain
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: SPI @ref led_ws2812b_spi, DMA
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/spi.h> // SPI library
-#include <libopencm3/stm32/dma.h> // DMA library
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-
-#include "led_ws2812b.h" // LED WS2812B library API
-#include "global.h" // common methods
-
-/** peripheral configuration */
-/** @defgroup led_ws2812b_spi SPI peripheral used to control the WS2812B LEDs
- * @{
- */
-/** SPI peripheral
- * @note SPI2 is 5V tolerant and can be operated in open-drain mode will 1 kO pull-up resistor to 5V to get 5V signal level
- */
-#define LED_WS2812B_SPI 2 /**< SPI peripheral */
-/** @} */
-
-/** bit template to encode one byte to be shifted out by SPI to the WS2812B LEDs
- * @details For each WS2812B bit which needs to be transferred we require to transfer 3 SPI bits.
- * The first SPI bit is the high start of the WS2812B bit frame.
- * The second SPI bit determines if the WS2812B bit is a 0 or 1.
- * The third SPI bit is the last part of the WS2812B bit frame, which is always low.
- * The binary pattern is 0b100100100100100100100100
- */
-#define LED_WS2812B_SPI_TEMPLATE 0x924924
-
-/** data encoded to be shifted out by SPI for the WS2812B, plus the 50us reset (~40 data bits) */
-uint8_t led_ws2812b_data[LED_WS2812B_LEDS * 3 * 3 + 40 * 3 / 8 + 1] = {0};
-
-void led_ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue)
-{
- // verify the led exists
- if (led >= LED_WS2812B_LEDS) {
- return;
- }
-
- // convert RGB bit to SPI bit (each bit is encoded in 3 bits)
- uint32_t red_spi = LED_WS2812B_SPI_TEMPLATE, green_spi = LED_WS2812B_SPI_TEMPLATE, blue_spi = LED_WS2812B_SPI_TEMPLATE;
- uint32_t bit_spi = 0x2; // the bit to set in the SPI stream
- for (uint8_t bit = 0; bit < 8; bit++) { // bit from the color to set/clear
- const uint8_t byte_bit = (1 << bit); // which bit to check
- if (red & byte_bit) {
- red_spi |= bit_spi;
- }
- if (green & byte_bit) {
- green_spi |= bit_spi;
- }
- if (blue & byte_bit) {
- blue_spi |= bit_spi;
- }
- bit_spi <<= 3; // go to next SPI bit
- }
-
- // set calculated pattern in stream (GRB)
- // we don't stop the DMA, instead we set LSB to MSB for gradient transition
- led_ws2812b_data[led * 3 * 3 + 0 + 2] = (green_spi >> 0);
- led_ws2812b_data[led * 3 * 3 + 3 + 2] = (red_spi >> 0);
- led_ws2812b_data[led * 3 * 3 + 6 + 2] = (blue_spi >> 0);
- led_ws2812b_data[led * 3 * 3 + 0 + 1] = (green_spi >> 8);
- led_ws2812b_data[led * 3 * 3 + 3 + 1] = (red_spi >> 8);
- led_ws2812b_data[led * 3 * 3 + 6 + 1] = (blue_spi >> 8);
- led_ws2812b_data[led * 3 * 3 + 0 + 0] = (green_spi >> 16);
- led_ws2812b_data[led * 3 * 3 + 3 + 0] = (red_spi >> 16);
- led_ws2812b_data[led * 3 * 3 + 6 + 0] = (blue_spi >> 16);
-}
-
-void led_ws2812b_setup(void)
-{
- // fill buffer with bit pattern
- for (uint16_t i = 0; i < LED_WS2812B_LEDS * 3; i++) {
- led_ws2812b_data[i * 3 + 0] = (uint8_t)(LED_WS2812B_SPI_TEMPLATE >> 16);
- led_ws2812b_data[i * 3 + 1] = (uint8_t)(LED_WS2812B_SPI_TEMPLATE >> 8);
- led_ws2812b_data[i * 3 + 2] = (uint8_t)(LED_WS2812B_SPI_TEMPLATE >> 0);
- }
- // fill remaining with with 0 to encode the reset code
- for (uint16_t i = LED_WS2812B_LEDS * 3 * 3; i < LENGTH(led_ws2812b_data); i++) {
- led_ws2812b_data[i] = 0;
- }
-
- // setup SPI to transmit data
- rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(LED_WS2812B_SPI)); // enable clock for SPI output peripheral
- gpio_set_mode(SPI_MOSI_PORT(LED_WS2812B_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, SPI_MOSI_PIN(LED_WS2812B_SPI)); // set MOSI as output (push-pull needs to be shifted to 5V, open-drain consumes up to 5 mA with pull-up resistor of 1 kO)
- rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
- rcc_periph_clock_enable(RCC_SPI(LED_WS2812B_SPI)); // enable clock for SPI peripheral
- spi_reset(SPI(LED_WS2812B_SPI)); // clear SPI values to default
- spi_set_master_mode(SPI(LED_WS2812B_SPI)); // set SPI as master since we generate the clock
- spi_set_baudrate_prescaler(SPI(LED_WS2812B_SPI), SPI_CR1_BR_FPCLK_DIV_16); // set clock to 0.44 us per bit
- spi_set_clock_polarity_1(SPI(LED_WS2812B_SPI)); // clock is high when idle
- spi_set_clock_phase_1(SPI(LED_WS2812B_SPI)); // output data on second edge (rising)
- spi_set_dff_8bit(SPI(LED_WS2812B_SPI)); // use 8 bits for simpler encoding (but there will be more interrupts)
- spi_send_msb_first(SPI(LED_WS2812B_SPI)); // send most significant bit first
- spi_set_bidirectional_transmit_only_mode(SPI(LED_WS2812B_SPI)); // we won't receive data
- spi_set_unidirectional_mode(SPI(LED_WS2812B_SPI)); // we only need to transmit data
- spi_enable_software_slave_management(SPI(LED_WS2812B_SPI)); // control the slave select in software (so we can start transmission)
- spi_set_nss_high(SPI(LED_WS2812B_SPI)); // set NSS high so we can output
- spi_enable(SPI(LED_WS2812B_SPI)); // enable SPI
-
- // configure DMA to provide the pattern to be shifted out from SPI to the WS2812B LEDs
- rcc_periph_clock_enable(RCC_DMA_SPI(LED_WS2812B_SPI)); // enable clock for DMA peripheral
- dma_channel_reset(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI)); // start with fresh channel configuration
- dma_set_read_from_memory(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI)); // set direction from memory to peripheral
- dma_set_memory_size(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI), DMA_CCR_MSIZE_8BIT); // read 8 bits from memory
- dma_set_memory_address(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI), (uint32_t)led_ws2812b_data); // set bit pattern as source address
- dma_enable_memory_increment_mode(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI)); // go through bit pattern
- dma_set_number_of_data(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI), LENGTH(led_ws2812b_data)); // set the size of the data to transmit
- dma_set_peripheral_address(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI), (uint32_t)&SPI_DR(SPI(LED_WS2812B_SPI))); // set SPI as peripheral destination address
- dma_set_peripheral_size(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI), DMA_CCR_PSIZE_8BIT); // write 8 bits to peripheral
- dma_set_priority(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI), DMA_CCR_PL_HIGH); // set priority to high since time is crucial for the peripheral
- dma_enable_circular_mode(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI)); // always send the data
- dma_enable_channel(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI)); // enable DMA channel
- spi_enable_tx_dma(SPI(LED_WS2812B_SPI)); // use DMA to provide data stream to be transferred
-}
diff --git a/lib/led_ws2812b.h b/lib/led_ws2812b.h
deleted file mode 100644
index ed1f726..0000000
--- a/lib/led_ws2812b.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/** library to drive a WS2812B LED chain
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: SPI @ref led_ws2812b_spi, DMA
- */
-#pragma once
-#error not converted for STM32F4
-
-/** number of LEDs on the WS2812B strip */
-#define LED_WS2812B_LEDS 48
-
-/** setup WS2812B LED driver
- * @note this starts the continuous transmission
- */
-void led_ws2812b_setup(void);
-/** set color of a single LED
- * @param[in] led the LED number to set the color
- * @param[in] red the red color value to set on the LED
- * @param[in] green the green color value to set on the LED
- * @param[in] blue the blue color value to set on the LED
- */
-void led_ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue);
diff --git a/lib/microwire_master.c b/lib/microwire_master.c
deleted file mode 100644
index 350ab93..0000000
--- a/lib/microwire_master.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/** library to communicate using microwore as master
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: GPIO @ref microwire_master_gpio, timer @ref microwire_master_timer
- * microwire is a 3-Wire half-duplex synchronous bus. It is very similar to SPI without fixed length messages (bit-wised).
- * @note the user has to handle the slave select pin (high during operations) so to be able to handle multiple slaves.
- * @warning this library implements the M93Cx8 EEPROM operation codes. Other microwire-based ICs might use different ones.
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/timer.h> // timer utilities
-
-#include "global.h" // global utilities
-#include "microwire_master.h" // microwire header and definitions
-
-/** @defgroup microwire_master_gpio GPIO peripheral used to communicate
- * @{
- */
-#define MICROWIRE_MASTER_SDO_PIN PA0 /**< SDO output signal pin (to be connected on D slave signal) */
-#define MICROWIRE_MASTER_SDI_PIN PA2 /**< SDO input signal pin (to be connected on Q slave signal) */
-#define MICROWIRE_MASTER_SCK_PIN PA4 /**< SCK output signal pin (to be connected on C slave signal) */
-/** @} */
-
-/** @defgroup microwire_master_timer timer peripheral used to generate timing for the signal
- * @{
- */
-#define MICROWIRE_MASTER_TIMER 4 /**< timer peripheral */
-/** @} */
-
-/** address size used in operations (slave specific) */
-uint8_t mirowire_master_address_size = 0;
-/** organization used (true=x16, false=x8) */
-bool mirowire_master_organization_x16 = true;
-
-void microwire_master_setup(uint32_t frequency, bool organization_x16, uint8_t address_size)
-{
- // sanity checks
- if (0 == frequency || 0 == address_size) {
- return;
- }
- mirowire_master_address_size = address_size; // save address size
- mirowire_master_organization_x16 = organization_x16; // save organisation
-
- // setup GPIO
- rcc_periph_clock_enable(GPIO_RCC(MICROWIRE_MASTER_SDO_PIN)); // enable clock for GPIO domain for SDO signal
- gpio_set_mode(GPIO_PORT(MICROWIRE_MASTER_SDO_PIN), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(MICROWIRE_MASTER_SDO_PIN)); // set SDO signal as output (controlled by the master)
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SDO_PIN), GPIO_PIN(MICROWIRE_MASTER_SDO_PIN)); // SDO is idle low
- rcc_periph_clock_enable(GPIO_RCC(MICROWIRE_MASTER_SDI_PIN)); // enable clock for GPIO domain for SDI signal
- gpio_set_mode(GPIO_PORT(MICROWIRE_MASTER_SDI_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(MICROWIRE_MASTER_SDI_PIN)); // set SDI signal as output (controlled by the slave)
- rcc_periph_clock_enable(GPIO_RCC(MICROWIRE_MASTER_SCK_PIN)); // enable clock for GPIO domain for SCK signal
- gpio_set_mode(GPIO_PORT(MICROWIRE_MASTER_SCK_PIN), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(MICROWIRE_MASTER_SCK_PIN)); // set SCK signal as output (controlled by the master)
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SCK_PIN), GPIO_PIN(MICROWIRE_MASTER_SCK_PIN)); // SCK is idle low
-
- // setup timer to generate timing for the signal
- rcc_periph_clock_enable(RCC_TIM(MICROWIRE_MASTER_TIMER)); // enable clock for timer domain
- rcc_periph_reset_pulse(RST_TIM(MICROWIRE_MASTER_TIMER)); // reset timer state
- timer_set_mode(TIM(MICROWIRE_MASTER_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
- uint16_t prescaler = rcc_ahb_frequency / (frequency * 2) / (uint32_t)(1 << 16) + 1; // calculate prescaler for most accurate timing for this speed
- timer_set_prescaler(TIM(MICROWIRE_MASTER_TIMER), prescaler - 1); // set calculated prescaler
- uint16_t period = (rcc_ahb_frequency / prescaler) / (frequency * 2); // calculate period to get most accurate timing based on the calculated prescaler
- timer_set_period(TIM(MICROWIRE_MASTER_TIMER), period - 1); // set calculated period
- timer_update_on_overflow(TIM(MICROWIRE_MASTER_TIMER)); // only use counter overflow as UEV source (use overflow as timeout)
- SCB_SCR |= SCB_SCR_SEVONPEND; // enable wake up on event (instead of using ISR)
- timer_enable_irq(TIM(MICROWIRE_MASTER_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
-}
-
-/** wait for clock tick used to synchronise communication */
-static void microwire_master_wait_clock(void)
-{
- while ( !timer_get_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF)) { // wait for timer overflow event for clock change
- __asm__("wfe"); // go to sleep and wait for event
- }
- timer_clear_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF); // clear timer flag
- nvic_clear_pending_irq(NVIC_TIM_IRQ(MICROWIRE_MASTER_TIMER)); // clear IRQ flag (else event doesn't wake up)
-}
-
-/** send bit over microwire
- * @param[in] bit bit to send (true = '1', false = '0')
- */
-static void microwire_master_send_bit(bool bit)
-{
- if (bit) {
- gpio_set(GPIO_PORT(MICROWIRE_MASTER_SDO_PIN), GPIO_PIN(MICROWIRE_MASTER_SDO_PIN)); // set '1' on output
- } else {
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SDO_PIN), GPIO_PIN(MICROWIRE_MASTER_SDO_PIN)); // set '0' on output
- }
- microwire_master_wait_clock(); // wait for clock timing
- gpio_set(GPIO_PORT(MICROWIRE_MASTER_SCK_PIN), GPIO_PIN(MICROWIRE_MASTER_SCK_PIN)); // make rising edge for slave to sample
- microwire_master_wait_clock(); // keep output signal stable while clock is high
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SCK_PIN), GPIO_PIN(MICROWIRE_MASTER_SCK_PIN)); // put clock back to idle
-}
-
-/** initialize microwire communication and send header (with leading start bit '1')
- * @param[in] operation operation code to send (2 bits)
- * @param[in] address slave memory address to select
- */
-static void microwire_master_start(uint8_t operation, uint32_t address)
-{
- // to sanity checks
- if (0==mirowire_master_address_size) { // can't send address
- return;
- }
-
- // initial setup
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SCK_PIN), GPIO_PIN(MICROWIRE_MASTER_SCK_PIN)); // ensure clock is low (to sample on rising edge)
- timer_set_counter(TIM(MICROWIRE_MASTER_TIMER), 0); // reset timer counter
- timer_clear_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF); // clear timer flag
- nvic_clear_pending_irq(NVIC_TIM_IRQ(MICROWIRE_MASTER_TIMER)); // clear IRQ flag (else event doesn't wake up)
- timer_enable_counter(TIM(MICROWIRE_MASTER_TIMER)); // start timer to generate timing
-
- // send '1' start bit
- microwire_master_send_bit(true); // send start bit
- // send two bits operation code
- if (operation & 0x2) { // send first bit (MSb first)
- microwire_master_send_bit(true); // send '1'
- } else {
- microwire_master_send_bit(false); // send '2'
- }
- if (operation & 0x1) { // send second bit (LSb last)
- microwire_master_send_bit(true); // send '1'
- } else {
- microwire_master_send_bit(false); // send '2'
- }
-
- // send address
- for (uint8_t bit = mirowire_master_address_size; bit > 0; bit--) {
- if ((address >> (bit - 1)) & 0x01) {
- microwire_master_send_bit(true); // send '1' address bit
- } else {
- microwire_master_send_bit(false); // send '0' address bit
- }
- }
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SDO_PIN), GPIO_PIN(MICROWIRE_MASTER_SDO_PIN)); // ensure output is idle low (could be floating)
-}
-
-/** stop microwire communication and end all activities */
-static void microwire_master_stop(void)
-{
- timer_disable_counter(TIM(MICROWIRE_MASTER_TIMER)); // disable timer
- timer_set_counter(TIM(MICROWIRE_MASTER_TIMER), 0); // reset timer counter
- timer_clear_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF); // clear timer flag
- nvic_clear_pending_irq(NVIC_TIM_IRQ(MICROWIRE_MASTER_TIMER)); // clear IRQ flag
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SCK_PIN), GPIO_PIN(MICROWIRE_MASTER_SCK_PIN)); // ensure clock is idle low
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SDO_PIN), GPIO_PIN(MICROWIRE_MASTER_SDO_PIN)); // ensure output is idle low
-}
-
-
-/** read bit from microwire communication
- * @return bit value (true = '1', false = '0')
- */
-static bool microwire_master_read_bit(void)
-{
- microwire_master_wait_clock(); // wait for clock timing
- gpio_set(GPIO_PORT(MICROWIRE_MASTER_SCK_PIN), GPIO_PIN(MICROWIRE_MASTER_SCK_PIN)); // make rising edge for slave to output data
- microwire_master_wait_clock(); // wait for signal to be stable
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SCK_PIN), GPIO_PIN(MICROWIRE_MASTER_SCK_PIN)); // set clock low again
- return 0 != gpio_get(GPIO_PORT(MICROWIRE_MASTER_SDI_PIN), GPIO_PIN(MICROWIRE_MASTER_SDI_PIN)); // read input signal
-}
-
-void microwire_master_read(uint32_t address, uint16_t* data, size_t length)
-{
- // to sanity checks
- if (NULL == data || 0 == length || 0 == mirowire_master_address_size) { // can't save data
- return;
- }
-
- microwire_master_start(0x02, address); // send '10' READ instruction and memory address
-
- // there should already be a '0' dummy bit
- if (0!=gpio_get(GPIO_PORT(MICROWIRE_MASTER_SDI_PIN), GPIO_PIN(MICROWIRE_MASTER_SDI_PIN))) { // the dummy bit wasn't '0'
- goto clean;
- }
-
- // read data
- for (size_t i = 0; i < length; i++) {
- for (uint8_t b = (mirowire_master_organization_x16 ? 16 : 8); b > 0; b--) {
- if (microwire_master_read_bit()) { // read bit, MSb first
- data[i] |= (1 << (b - 1)); // set bit
- } else {
- data[i] &= ~(1 << (b - 1)); // clear bit
- }
- }
- }
-
-clean:
- microwire_master_stop(); // stop communication and clean up
-}
-
-void microwire_master_write_enable(void)
-{
- // to sanity checks
- if (mirowire_master_address_size < 2) { // can't send '11...' address
- return;
- }
-
- microwire_master_start(0x0, 0x3 << (mirowire_master_address_size - 2)); // send '00' WEN operation code and '11...' address
- microwire_master_stop(); // clean up
-}
-
-void microwire_master_write_disable(void)
-{
- // to sanity checks
- if (mirowire_master_address_size < 2) { // can't send '00...' address
- return;
- }
-
- microwire_master_start(0x0, 0); // send '00' WDS operation code and '00...' address
- microwire_master_stop(); // clean up
-}
-
-void microwire_master_write(uint32_t address, uint16_t data)
-{
- // to sanity checks
- if (0==mirowire_master_address_size) { // can't send address
- return;
- }
-
- microwire_master_start(0x01, address); // send '01' WRITE operation code and memory address
-
- // write data (MSb first)
- for (uint8_t b=(mirowire_master_organization_x16 ? 16 : 8); b>0; b--) {
- if (data&(1<<(b-1))) { // bit is set
- microwire_master_send_bit(true); // send '1' data bit
- } else {
- microwire_master_send_bit(false); // send '0' data bit
- }
- }
-
- microwire_master_stop(); // clean up
-}
-
-void microwire_master_wait_ready(void)
-{
-
- // initial setup
- gpio_clear(GPIO_PORT(MICROWIRE_MASTER_SCK_PIN), GPIO_PIN(MICROWIRE_MASTER_SCK_PIN)); // ensure clock is low (to sample on rising edge)
- timer_set_counter(TIM(MICROWIRE_MASTER_TIMER), 0); // reset timer counter
- timer_clear_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF); // clear timer flag
- nvic_clear_pending_irq(NVIC_TIM_IRQ(MICROWIRE_MASTER_TIMER)); // clear IRQ flag (else event doesn't wake up)
- timer_enable_counter(TIM(MICROWIRE_MASTER_TIMER)); // start timer to generate timing
-
-
- // SDI low on busy, high on ready, clock is ignored
- while (!microwire_master_read_bit()); // wait until slave is ready
-
- microwire_master_stop(); // clean up
-}
-
-void microwire_master_erase(uint32_t address)
-{
- // sanity checks
- if (0==mirowire_master_address_size) { // can't send address
- return;
- }
-
- microwire_master_start(0x03, address); // send '11' ERASE operation code and memory address
- microwire_master_stop(); // clean up
-}
-
-void microwire_master_erase_all(void)
-{
- // sanity checks
- if (mirowire_master_address_size < 2) { // can't send '11...' address
- return;
- }
-
- microwire_master_start(0x00, 0x2 << (mirowire_master_address_size - 2)); // send '00' ERAL operation code and '10...' address
- microwire_master_stop(); // clean up
-}
-
-void microwire_master_write_all(uint16_t data)
-{
- // sanity checks
- if (0 == mirowire_master_address_size) { // can't send address
- return;
- }
-
- microwire_master_start(0x00, 0x1 << (mirowire_master_address_size - 2)); // send '00' WRAL operation code and '01...' address
- // write data (MSb first)
- for (uint8_t b = (mirowire_master_organization_x16 ? 16 : 8); b > 0; b--) {
- if (data&(1 << (b - 1))) { // bit is set
- microwire_master_send_bit(true); // send '1' data bit
- } else {
- microwire_master_send_bit(false); // send '0' data bit
- }
- }
-
- microwire_master_stop(); // clean up
-}
diff --git a/lib/microwire_master.h b/lib/microwire_master.h
deleted file mode 100644
index d2899e7..0000000
--- a/lib/microwire_master.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/** library to communicate using microwire as master
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: GPIO @ref microwire_master_gpio, timer @ref microwire_master_timer
- * microwire is a 3-Wire half-duplex synchronous bus. It is very similar to SPI without fixed length messages (bit-wised).
- * @note the user has to handle the slave select pin (high during operations) so to be able to handle multiple slaves.
- * @warning this library implements the M93Cx8 EEPROM operation codes. Other microwire-based ICs might use different ones.
- */
-#pragma once
-#error not converted for STM32F4
-
-/** setup microwire peripheral
- * @param[in] frequency clock frequency in Hz
- * @param[in] organization_x16 if x16 memory organization (16-bits) is used, or x8 (8-bits)
- * @param[in] address_size address size in bits
- * @note frequency practically limited to 500 kHz due to the software implementation nature
- */
-void microwire_master_setup(uint32_t frequency, bool organization_x16, uint8_t address_size);
-/** read data from slave memory
- * @param[in] address memory address of data to read
- * @param[out] data array to store read data
- * @param[in] length number of data bytes/words to read
- */
-void microwire_master_read(uint32_t address, uint16_t* data, size_t length);
-/** enable write and erase operations
- * @note on slave boot write is disable to prevent corruption
- */
-void microwire_master_write_enable(void);
-/** disable write and erase operations
- * @note this should be done after every complete write operation to protect against corruption
- */
-void microwire_master_write_disable(void);
-/** write data to slave memory
- * @param[in] address memory address of data to read
- * @param[in] data byte/word to write
- * @note after each write and before the next operation user should wait for the slave to be ready
- */
-void microwire_master_write(uint32_t address, uint16_t data);
-/** wait until slave is ready after a write or erase */
-void microwire_master_wait_ready(void);
-/** erase memory
- * @param[in] address memory address of data to read
- * @note after each erase and before the next operation user should wait for the slave to be ready
- */
-void microwire_master_erase(uint32_t address);
-/** erase all memory
- * @note after each erase and before the next operation user should wait for the slave to be ready
- */
-void microwire_master_erase_all(void);
-/** write data to all slave memory
- * @param[in] data byte/word to write
- * @note after each write and before the next operation user should wait for the slave to be ready
- */
-void microwire_master_write_all(uint16_t data);
diff --git a/lib/oled_ssd1306.c b/lib/oled_ssd1306.c
deleted file mode 100644
index 6bbaf00..0000000
--- a/lib/oled_ssd1306.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/** SSD1306 OLED library (code)
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2018-2020
- * @note peripherals used: I2C @ref i2c_master_i2c
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdbool.h> // boolean type
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/stm32/i2c.h> // I2C library
-
-/* own libraries */
-#include "global.h" // global utilities
-#include "oled_ssd1306.h" // OLED definitions
-#include "i2c_master.h" // I²C header and definitions
-
-/** SSD1306 OLED display I²C slave address */
-static uint8_t oled_ssd1306_slave_addr = 0x3c;
-
-bool oled_ssd1306_setup(uint8_t slave_addr)
-{
- if (!i2c_master_check_signals()) { // check if there are pull-ups to operator I²C
- return false;
- }
- oled_ssd1306_slave_addr = slave_addr; // save I²C slave address of SSD1306
- i2c_master_setup(400); // setup I²C bus (SSD1306 supports an I²C clock up to 400 kHz)
- const uint8_t oled_init[] = {
- 0x00, // control byte: continuous (multiple byes), command
- 0xae, // Set Display ON/OFF: OFF
- // hardware configuration
- 0xa8, 0x3f, // Set Multiplex Ratio: 64
- 0xd3, 0x00, // Set Display Offset: 0
- 0xa1, // Set Segment Re-map: column address 0 is mapped to SEG127
- 0xc8, // Set COM Output Scan Direction: normal mode (RESET) Scan from COM[N-1] to COM[0]
- 0xda, 0x12, // Set COM Pins Hardware Configuration: Alternative COM pin configuration, Disable COM Left/Right remap
- 0x40, // Set Display Start Line: start line register from 0
- // fundamental commands
- 0x81, 0xff, // Set Contrast Control: 256
- 0xa6, // Set Normal/Inverse Display: Normal display (RESET)
- // Timing & Driving Scheme Setting
- 0xd5, 0xf0, // Set Display Clock Divide Ratio/Oscillator Frequency: Divide ratio=129, F_OSC=1
- 0xd9, 0x22, // Set Pre-charge Period: Phase 1=2 DCLK, Phase 2=2DCLK
- 0xdb, 0x20, // Set V_COMH Deselect Level: ~0.77xV_CC
- // Charge Pump
- 0x8d, 0x14, // Charge Pump Setting: Enable Charge Pump
- // Addressing Setting
- 0x20, 0x00 // Set Memory Addressing Mode: Horizontal Addressing Mode
- }; // command to initialize the display
- return I2C_MASTER_RC_NONE == i2c_master_slave_write(oled_ssd1306_slave_addr, false, oled_init, LENGTH(oled_init)); // send command to initialize display
-}
-
-void oled_ssd1306_on(void)
-{
- const uint8_t oled_display_on[] = {
- 0x80, // control byte: no continuation, command
- 0xaf, // Set Display ON/OFF: ON
- }; // command to switch on display
- i2c_master_slave_write(oled_ssd1306_slave_addr, false, oled_display_on, LENGTH(oled_display_on)); // sent command to switch on display
-}
-
-void oled_ssd1306_off(void)
-{
- const uint8_t oled_display_off[] = {
- 0x80, // control byte: no continuation, command
- 0xae, // Set Display ON/OFF: OFF
- }; // command to switch off display
- i2c_master_slave_write(oled_ssd1306_slave_addr, false, oled_display_off, LENGTH(oled_display_off)); // sent command to switch font display
-}
-
-void oled_ssd1306_test(void)
-{
- const uint8_t oled_entire_display_on[] = {
- 0x80, // control byte: no continuation, command
- 0xa5 // Entire Display ON: Entire display ON Output ignores RAM content
- }; // command to set entire display on
- i2c_master_slave_write(oled_ssd1306_slave_addr, false, oled_entire_display_on, LENGTH(oled_entire_display_on)); // send command to switch entire display on
- oled_ssd1306_on(); // set display on
- sleep_ms(200); // let is on for a bit (enough for the user to see it is completely on
- oled_ssd1306_off(); // set display off
- const uint8_t oled_entire_display_ram[] = {
- 0x80, // control byte: no continuation, command
- 0xa4 // Entire Display ON: Resume to RAM content display
- }; // command to display RAM
- i2c_master_slave_write(oled_ssd1306_slave_addr, false, oled_entire_display_ram, LENGTH(oled_entire_display_ram)); // send command to display RAM
-}
-
-void oled_ssd1306_display(const uint8_t* display_data, uint16_t display_length)
-{
- // verify input
- if (0 == display_length || NULL == display_data) {
- return;
- }
-
- const uint8_t oled_start_page[] = {
- 0x00, // control byte: continuous (multiple byes), command
- 0xb0, // Set Page Start Address for Page Addressing Mode: PAGE0
- 0x00, // Set Lower Column Start Address for Page Addressing Mode: 0
- 0x10 // Set Higher Column Start Address for Page Addressing Mode: 0
- }; // command to set addressing mode
- i2c_master_slave_write(oled_ssd1306_slave_addr, false, oled_start_page, LENGTH(oled_start_page)); // send command to set addressing mode
- if (I2C_MASTER_RC_NONE != i2c_master_start()) { // send start condition
- return;
- }
- if (I2C_MASTER_RC_NONE != i2c_master_select_slave(oled_ssd1306_slave_addr, false, true)) { // select OLED display
- return;
- }
- uint8_t oled_data[display_length + 1]; // we have to copy the data because we need to send a single block since i2c_master_write sends a stop
- oled_data[0] = 0x40; // control byte: continuous (multiple byes), data
- for (uint16_t i = 0; i < display_length; i++) {
- oled_data[i + 1] = display_data[i];
- }
- if (I2C_MASTER_RC_NONE != i2c_master_write(oled_data, display_length + 1)) { // send data header
- return;
- }
- i2c_master_stop(); // send stop condition
-}
-
diff --git a/lib/oled_ssd1306.h b/lib/oled_ssd1306.h
deleted file mode 100644
index 4aa2894..0000000
--- a/lib/oled_ssd1306.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/** SSD1306 OLED library
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2018-2020
- * @note peripherals used: I2C @ref i2c_master_i2c
- */
-#pragma once
-
-/** setup OLED display
- * @param[in] slave_addr I²C slave address of SSD1306 device (least significant 7-bit)
- * @return if the display setup is successful, else the display is probably not on the I²C bus
- * @warning only one display on the I²C bus is currently supported
- */
-bool oled_ssd1306_setup(uint8_t slave_addr);
-/** switch OLED display on */
-void oled_ssd1306_on(void);
-/** switch OLED display off */
-void oled_ssd1306_off(void);
-/** test OLED display: switch entire screen on for a brief time */
-void oled_ssd1306_test(void);
-/** send data to display to OLED display
- * @param[in] display_data data to display (first byte is left column, MSb is top pixel, warps pages)
- * @param[in] display_length length of data to display
- */
-void oled_ssd1306_display(const uint8_t* display_data, uint16_t display_length);
diff --git a/lib/oled_text.c b/lib/oled_text.c
deleted file mode 100644
index cc2789b..0000000
--- a/lib/oled_text.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-/** library to show display text on SSD1306 OLED display
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @date 2020
- * @note peripherals used: I²C @ref oled_ssd1306_i2c
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdbool.h> // boolean type
-#include <string.h> // string utilities
-
-/* own libraries */
-#include "global.h" // global utilities
-#include "oled_text.h" // own definitions
-#include "oled_ssd1306.h" // OLED display utilities
-#include "font.h" // font glyphs
-
-/** if the OLED display is present and setup */
-static bool oled_text_present = false;
-
-/** display pixel buffer */
-static uint8_t oled_text_display[128 * 8] = {0};
-
-/** SSD1306 OLED display I2C slave address */
-#define OLED_SSD1306_SLAVE 0x3c
-
-/** look-up table to swap the bit order in a byte
- * @remark this is useful for the OLED screen since the top pixel is the MSb
- */
-static const uint8_t bit_order_switch_lut[256] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, };
-
-bool oled_text_setup(void)
-{
-
- // setup SSD1306 OLED display
- oled_text_clear(); // clean display buffer
- oled_text_present = oled_ssd1306_setup(OLED_SSD1306_SLAVE); // setup OLED display
- if (oled_text_present) {
-#if DEBUG
- oled_ssd1306_test(); // test OLED display
-#endif
- oled_text_update(); // send display buffer
- oled_ssd1306_on(); // switch display back on
- };
-
- return oled_text_present;
-}
-
-void oled_text_clear(void)
-{
- // write all buffer to 0
- for (uint16_t i = 0; i < LENGTH(oled_text_display); i++) {
- oled_text_display[i] = 0;
- }
-}
-
-void oled_text_pos(uint8_t column, uint8_t row, enum font_name font_name, const char *text)
-{
- // sanity checks
- if (column >= 128) {
- return;
- }
- if (row >= 64) {
- return;
- }
- if (font_name >= FONT_MAX) {
- return;
- }
- if (NULL == text) {
- return;
- }
-
- const struct font_s *font = &fonts[font_name]; // get selected font
- while (*text && column < 128) {
- char c = *text;
- if (c >= ' ' && c < ' ' + FONT_GLYPH_NUMBERS) {
- for (uint8_t i = 0; i < font->width; i++) { // draw glyph from left to right
- uint8_t col = column + i; // calculate destination column position
- if (col >= 128) {
- break; // end of screen reached
- }
- uint16_t glyph_column = font->glyphs[font->width * (c - ' ') + i]; // get glyph column to draw
- // draw bottom part of glyph
- uint16_t pixel_byte_row = 128 * ((row / 8) - 0) + col;
- uint8_t glyph_byte_row = (glyph_column << (7 - (row % 8))) >> 0;
- glyph_byte_row = bit_order_switch_lut[glyph_byte_row];
- oled_text_display[pixel_byte_row] |= glyph_byte_row;
- // draw middle part of glyph
- if (row >= 8 && font->height > 8 - (row % 8)) {
- pixel_byte_row -= 128;
- glyph_byte_row = (glyph_column << (7 - (row % 8))) >> 8;
- glyph_byte_row = bit_order_switch_lut[glyph_byte_row];
- oled_text_display[pixel_byte_row] |= glyph_byte_row;
- }
- // draw top part of glyph
- if (row >= 16 && font->height > 8 + (row % 8)) {
- pixel_byte_row -= 128;
- glyph_byte_row = ((uint32_t)glyph_column << (7 - (row % 8))) >> 16;
- glyph_byte_row = bit_order_switch_lut[glyph_byte_row];
- oled_text_display[pixel_byte_row] |= glyph_byte_row;
- }
- }
- }
- text++; // go to next character
- column += font->width+1;
- }
-}
-
-void oled_text_line(const char* text, uint8_t line_nb)
-{
- // verify input
- if (NULL == text) {
- return;
- }
- if (line_nb > 3) { // we only use 4 lines
- return;
- }
-
- // clear line
- for (uint16_t i = 128 * (line_nb * 2); i < 128 * (line_nb * 2 + 2); i++) {
- oled_text_display[i] = 0;
- }
-
- oled_text_pos(0, 15 + 16 * line_nb, FONT_KING14, text); // draw text on the left of top line
-}
-
-void oled_text_update(void)
-{
- if (oled_text_present) { // only do something if the display is present
- oled_ssd1306_display(oled_text_display, LENGTH(oled_text_display)); // send current display buffer
- }
-}
diff --git a/lib/oled_text.h b/lib/oled_text.h
deleted file mode 100644
index f584c23..0000000
--- a/lib/oled_text.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-/** library to show display text on SSD1306 OLED display
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @date 2018-2020
- * @note peripherals used: I²C @ref oled_ssd1306_i2c
- */
-#include "font.h"
-
-/** setup OLED display
- * @return if OLED screen is present and responsive
- */
-bool oled_text_setup(void);
-/** clear display buffer
- * @note update the display to clear it
- */
-void oled_text_clear(void);
-/** draw text in display buffer
- * @param[in] column display column where to start drawing the text (0 is left)
- * @param[in] row display row where to put the lower end of the characters (0 is top)
- * @param[in] font_name name of the font to use to draw the text
- * @param[in] text text string to draw
- */
-void oled_text_pos(uint8_t column, uint8_t row, enum font_name font_name, const char *text);
-/** draw text on display
- * @param[in] text text to display on top left side of screen
- * @param[in] line_nb on which line to display the text (up to 3)
- * @note update the display to display the text
- */
-void oled_text_line(const char* text, uint8_t line_nb);
-/** update OLED display RAM with current display buffer */
-void oled_text_update(void);
diff --git a/lib/onewire_master.c b/lib/onewire_master.c
deleted file mode 100644
index 0744525..0000000
--- a/lib/onewire_master.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/** library for 1-wire protocol as master
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: timer @ref onewire_master_timer, GPIO @ref onewire_master_gpio
- * @note overdrive mode is not provided
- * @implements 1-Wire protocol description from Book of iButton Standards
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdbool.h> // boolean type
-#include <stddef.h> // NULL definition
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/timer.h> // timer library
-
-/* own libraries */
-#include "global.h" // help macros
-#include "interrupt.h" // runtime interrupt table
-#include "onewire_master.h" // own definitions
-
-/** @defgroup onewire_master_gpio GPIO used for 1-wire signal
- * @note external pull-up resistor on pin is required (< 5 kOhm)
- * @{
- */
-#define ONEWIRE_MASTER_PIN PC9 /**< GPIO pin */
-/** @} */
-
-/** @defgroup onewire_master_timer timer used to measure 1-wire signal timing
- * @{
- */
-#define ONEWIRE_MASTER_TIMER 5 /**< timer ID */
-/** @} */
-
-/** set if the timer ISR should be set in the interrupt table instead of the vector table
- * @note the vector table is faster, but doesn't allow to change the ISR
- */
-#define ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE false
-
-/** state of 1-Wire communication */
-volatile enum {
- ONEWIRE_STATE_IDLE, /**< no current communication */
- ONEWIRE_STATE_DONE, /**< communication complete */
- ONEWIRE_STATE_ERROR, /**< communication error */
- ONEWIRE_STATE_MASTER_RESET, /**< reset pulse started */
- ONEWIRE_STATE_SLAVE_PRESENCE, /**< waiting for slave response to reset pulse */
- ONEWIRE_STATE_MASTER_WRITE, /**< master is writing bits */
- ONEWIRE_STATE_MASTER_READ, /**< master is reading bits */
- ONEWIRE_MAX /** to count the number of possible states */
-} onewire_master_state = ONEWIRE_STATE_IDLE;
-
-static volatile bool slave_presence = false; /**< if slaves have been detected */
-static uint8_t* buffer = NULL; /**< input/output buffer for read/write commands/functions */
-static uint32_t buffer_size = 0; /**< size of buffer in bits */
-static volatile uint32_t buffer_bit = 0; /**< number of bits read/written */
-#if defined(ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE) && ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE
-static void (*isr_backup)(void) = NULL; /**< backup for the existing timer ISR */
-static bool irq_backup = false; /**< backup for the existing timer IRQ */
-#endif
-
-/** interrupt service routine called for timer */
-#if defined(ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE) && ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE
-static void onewire_master_timer_isr(void)
-#else
-void TIM_ISR(ONEWIRE_MASTER_TIMER)(void)
-#endif
-{
- if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_UIF)) { // overflow update event happened
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_UIF); // clear flag
- switch (onewire_master_state) {
- case ONEWIRE_STATE_MASTER_RESET: // reset pulse has been started
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC4IF); // clear output compare flag
- timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC4IE); // enable compare interrupt for presence detection
- gpio_set(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // set signal high again for slaves to respond
- onewire_master_state = ONEWIRE_STATE_SLAVE_PRESENCE; // set new state
- break;
- case ONEWIRE_STATE_SLAVE_PRESENCE: // waiting for slave presence but none received
- timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC4IE); // disable compare interrupt for presence detection
- onewire_master_state = ONEWIRE_STATE_DONE; // go to next state
- break;
- case ONEWIRE_STATE_MASTER_READ: // end of time slot and recovery time for reading bit
- case ONEWIRE_STATE_MASTER_WRITE: // end of time slot and recovery time for writing bit
- if (buffer_bit < buffer_size) { // check if byte to read/write are remaining
- gpio_clear(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // pull signal low to start next slot
- } else { // all bytes read/written
- timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC1IE); // disable compare interrupt for master pull low
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // disable compare interrupt for read/write bit
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC3IE); // disable compare interrupt for end of slot
- onewire_master_state = ONEWIRE_STATE_DONE; // set end state
- }
- break;
- default: // unknown state for this stage
- timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC1IE); // disable all compare interrupt
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // disable all compare interrupt
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC3IE); // disable all compare interrupt
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC4IE); // disable all compare interrupt
- gpio_set(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // pull signal high (idle state)
- onewire_master_state = ONEWIRE_STATE_ERROR; // indicate error
- }
- } else if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC1IF)) { // compare event happened for master pull low end for read
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC1IF); // clear flag
- switch (onewire_master_state) {
- case ONEWIRE_STATE_MASTER_READ: // master has to read a bit
- gpio_set(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // pull signal high to end time slot
- break;
- default: // unknown state for this stage
- break; // let the overflow handle the error if any
- }
- } else if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF)) { // compare event happened for bit sampling/setting
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF); // clear flag
- switch (onewire_master_state) {
- case ONEWIRE_STATE_MASTER_WRITE: // master has to write a bit
- if (buffer_bit < buffer_size) { // check if byte to send are remaining
- if (buffer[buffer_bit / 8] & (1 << (buffer_bit % 8))) { // check bit (LSb first)
- gpio_set(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // set signal high again to write "1"
- }
- buffer_bit++; // got to next bit
- } else {
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // disable compare interrupt
- onewire_master_state = ONEWIRE_STATE_ERROR; // indicate error
- }
- break;
- case ONEWIRE_STATE_MASTER_READ: // master has to read a bit set by slave
- if (buffer_bit<buffer_size) { // check if byte to send are remaining
- if (gpio_get(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN))) { // check if the slave kept it low
- buffer[buffer_bit / 8] |= (1 << (buffer_bit % 8)); // save bit "1"
- } else {
- buffer[buffer_bit / 8] &= ~(1 << (buffer_bit % 8)); // save bit "0"
- }
- buffer_bit++; // got to next bit
- } else {
- timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // disable compare interrupt
- onewire_master_state = ONEWIRE_STATE_ERROR; // indicate error
- }
- break;
- default: // unknown state for this stage
- break; // let the overflow handle the error if any
- }
- } else if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF)) { // compare event happened for end to time slot
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF); // clear flag
- gpio_set(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // pull signal high to end time slot
- } else if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC4IF)) { // compare event happened for slave presence detection
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC4IF); // clear flag
- if (gpio_get(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN))) { // check is a slave let its presence know by pulling low
- slave_presence = false; // remember no slave(s) responded
- } else {
- slave_presence = true; // remember slave(s) responded
- }
- } else { // no other interrupt should occur
- while (true); // unhandled exception: wait for the watchdog to bite
- }
-}
-
-void onewire_master_setup(void)
-{
- // setup GPIO with external interrupt
- rcc_periph_clock_enable(GPIO_RCC(ONEWIRE_MASTER_PIN)); // enable clock for GPIO peripheral
- gpio_set(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // idle is high (using pull-up resistor)
- gpio_mode_setup(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(ONEWIRE_MASTER_PIN)); // set pin as output, and expect external pull-up resistor
- gpio_set_output_options(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN(ONEWIRE_MASTER_PIN)); // set pin output as open-drain for normal 1-Wire communication (no parasite power)
-
- // setup timer to generate/measure signal timing
- rcc_periph_clock_enable(RCC_TIM(ONEWIRE_MASTER_TIMER)); // enable clock for timer peripheral
- rcc_periph_reset_pulse(RST_TIM(ONEWIRE_MASTER_TIMER)); // reset timer state
- timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer to configure it
- timer_set_mode(TIM(ONEWIRE_MASTER_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(ONEWIRE_MASTER_TIMER), 1 - 1); // don't use prescale since this 16 bits timer allows to wait > 480 us used for the reset pulse ( 1/(72E6/1/(2**16))=910us )
-
- // use comparator to time signal (without using the output), starting at slot start
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC1IF); // clear flag
- timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC1, 1 * (rcc_ahb_frequency / 1000000) - 1); // use compare function to time master pulling low when reading (1 < Tlowr < 15)
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF); // clear flag
- timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC2, 7 * (rcc_ahb_frequency / 1000000) - 1); // use compare function to read or write 0 or 1 (1 < Trw < 15)
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF); // clear flag
- timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC3, 62 * (rcc_ahb_frequency / 1000000) - 1); // use compare function to end time slot (60 < Tslot < 120), this will be followed by a recovery time (end of timer)
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC4IF); // clear flag
- timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC4, (70 - 10) * (rcc_ahb_frequency / 1000000) - 1); // use compare function to detect slave presence (15 < Tpdh < 60 + 60 < Tpdl < 240), with hand tuning
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_UIF); // clear update (overflow) flag
- timer_update_on_overflow(TIM(ONEWIRE_MASTER_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout)
- timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_UIE); // enable update interrupt for overflow
-#if defined(ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE) && ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE
- isr_backup = interrupt_table[NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)]; // backup timer ISR
- interrupt_table[NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)] = &onewire_master_timer_isr; // set the 1-wire timer ISR
- irq_backup = nvic_get_irq_enabled(NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)); // backup timer IRQ setting
-#endif
- nvic_enable_irq(NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)); // catch interrupt in service routine
-
- slave_presence = false; // reset state
- onewire_master_state = ONEWIRE_STATE_IDLE; // reset state
-}
-
-void onewire_master_release(void)
-{
- // release timer
- timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer
- rcc_periph_reset_pulse(RST_TIM(ONEWIRE_MASTER_TIMER)); // reset timer state
- rcc_periph_clock_disable(RCC_TIM(ONEWIRE_MASTER_TIMER)); // disable clock for timer peripheral
-
- // release GPIO
- gpio_mode_setup(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN(ONEWIRE_MASTER_PIN)); // put back to input floating
-
- // disable timer ISR
-#if defined(ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE) && ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE
- if (!irq_backup) { // don't disable the IRQ if there was already enabled
- nvic_disable_irq(NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)); // stop timer IRQ
- }
- interrupt_table[NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)] = isr_backup; // set back original timer ISR
-#else
- nvic_disable_irq(NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)); // stop timer IRQ
-#endif
-}
-
-bool onewire_master_reset(void)
-{
- // prepare timer
- timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer to reconfigure it
- timer_set_counter(TIM(ONEWIRE_MASTER_TIMER), 0); // reset counter
- timer_set_period(TIM(ONEWIRE_MASTER_TIMER), 490 * (rcc_ahb_frequency / 1000000) - 1); // set timeout to > 480 us (480 < Trst)
-
- slave_presence = false; // reset state
- onewire_master_state = ONEWIRE_STATE_MASTER_RESET; // set new state
-
- gpio_set_output_options(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN(ONEWIRE_MASTER_PIN)); // set pin output as open-drain for normal 1-Wire communication (no parasite power)
- gpio_clear(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // pull signal low to start reset (it's not important if it was low in the first place since the reset pulse has no maximum time)
- timer_enable_counter(TIM(ONEWIRE_MASTER_TIMER)); // start timer
-
- while (onewire_master_state != ONEWIRE_STATE_DONE && onewire_master_state != ONEWIRE_STATE_ERROR) { // wait until reset procedure completed
- __WFI(); // go to sleep
- }
- if (ONEWIRE_STATE_ERROR == onewire_master_state) { // an error occurred
- return false;
- }
-
- return slave_presence;
-}
-
-/** write bits on 1-Wire bus
- * @warning buffer_size must be set to the number of bits to writen and buffer must contain the data to write
- * @return if write succeeded
- */
-static bool onewire_master_write(void)
-{
- buffer_bit = 0; // reset bit index
- onewire_master_state = ONEWIRE_STATE_MASTER_WRITE; // set new state
-
- // prepare timer
- timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer to reconfigure it
- timer_set_counter(TIM(ONEWIRE_MASTER_TIMER), 0); // reset counter
- timer_set_period(TIM(ONEWIRE_MASTER_TIMER), TIM_CCR3(TIM(ONEWIRE_MASTER_TIMER)) + 2 * (rcc_ahb_frequency / 1000000)); // set time for new time slot (recovery timer Trec>1, after time slot end )
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF); // clear output compare flag
- timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // enable compare interrupt for bit setting
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF); // clear output compare flag
- timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC3IE); // enable compare interrupt for end of time slow
-
- // start writing
- gpio_set_output_options(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN(ONEWIRE_MASTER_PIN)); // set pin output as open-drain for normal 1-Wire communication (no parasite power)
- gpio_clear(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // pull signal low to start slot
- timer_enable_counter(TIM(ONEWIRE_MASTER_TIMER)); // start timer
- while (onewire_master_state != ONEWIRE_STATE_DONE && onewire_master_state != ONEWIRE_STATE_ERROR) { // wait until write procedure completed
- __WFI(); // go to sleep
- }
- if (ONEWIRE_STATE_ERROR == onewire_master_state) { // an error occurred
- return false;
- }
- return true;
-}
-
-/** read bits on 1-Wire bus
- * @warning buffer_size must be set to the number of bits to read
- * @return if read succeeded
- */
-static bool onewire_master_read(void)
-{
- if (0 == buffer_size) { // check input
- return false;
- }
- buffer_bit = 0; // reset bit index
- onewire_master_state = ONEWIRE_STATE_MASTER_READ; // set new state
-
- // prepare timer
- timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer to reconfigure it
- timer_set_counter(TIM(ONEWIRE_MASTER_TIMER), 0); // reset counter
- timer_set_period(TIM(ONEWIRE_MASTER_TIMER), TIM_CCR3(TIM(ONEWIRE_MASTER_TIMER)) + 2*(rcc_ahb_frequency / 1000000)); // set time for new time slot (recovery timer Trec>1, after time slot end )
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC1IF); // clear output compare flag
- timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC1IE); // enable compare interrupt for stop pulling low
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF); // clear output compare flag
- timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // enable compare interrupt for bit setting
- timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF); // clear output compare flag
- timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC3IE); // enable compare interrupt for end of time slow
-
- // start reading
- gpio_set_output_options(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN(ONEWIRE_MASTER_PIN)); // set pin output as open-drain for normal 1-Wire communication (no parasite power)
- gpio_clear(GPIO_PORT(ONEWIRE_MASTER_PIN), GPIO_PIN(ONEWIRE_MASTER_PIN)); // pull signal low to start slot
- timer_enable_counter(TIM(ONEWIRE_MASTER_TIMER)); // start timer
- while (onewire_master_state != ONEWIRE_STATE_DONE && onewire_master_state != ONEWIRE_STATE_ERROR) { // wait until read procedure completed
- __WFI(); // go to sleep
- }
- if (ONEWIRE_STATE_ERROR == onewire_master_state) { // an error occurred
- return false;
- }
- return true;
-}
-
-uint8_t onewire_master_crc(uint8_t* data, uint32_t length)
-{
- if (NULL == data || 0 == length) { // check input
- return 0; // wrong input
- }
-
- uint8_t crc = 0x00; // initial value
- for (uint8_t i = 0; i < length; i++) { // go through every byte
- crc ^= data[i]; // XOR byte
- for (uint8_t b = 0; b < 8; b++) { // go through every bit
- if (crc & 0x01) { // least significant bit is set (we are using the reverse way)
- crc = (crc >> 1) ^ 0x8C; // // shift to the right (for the next bit) and XOR with (reverse) polynomial
- } else {
- crc >>= 1; // just shift right (for the next bit)
- }
- }
- }
- return crc;
-}
-
-bool onewire_master_read_byte(uint8_t* data)
-{
- if (NULL == data) { // check input
- return false; // wrong input
- }
-
- // read data
- buffer_size = 8; // save number of bits to read (1 byte)
- buffer = data; // set the buffer to the data to write
- if (!onewire_master_read()) { // read bits from slave
- return false; // an error occurred
- }
- return true;
-}
-
-bool onewire_master_write_byte(uint8_t data)
-{
- // send data byte
- buffer_size = 8; // function command is only one byte
- buffer = &data; // set the buffer to the function code
- if (!onewire_master_write()) { // send command
- return false; // an error occurred
- }
- return true;
-}
-
-bool onewire_master_function_read(uint8_t function, uint8_t* data, uint32_t bits)
-{
- // send function command
- if (!onewire_master_write_byte(function)) {
- return false; // an error occurred
- }
-
- if (NULL == data || 0 == bits) { // there is no data to read
- return true; // operation completed
- }
-
- // read data
- buffer_size = bits; // save number of bits to read
- buffer = data; // set the buffer to the data to write
- if (!onewire_master_read()) { // read bits from slave
- return false; // an error occurred
- }
-
- return true;
-}
-
-bool onewire_master_function_write(uint8_t function, uint8_t* data, uint32_t bits)
-{
- // send function command
- if (!onewire_master_write_byte(function)) {
- return false; // an error occurred
- }
-
- if (NULL == data || 0 == bits) { // there is no data to read
- return true; // operation completed
- }
-
- // copy data from user buffer
- buffer_size = bits; // save number of bits to write
- buffer = data; // set the buffer to the data to write
- // write data
- if (!onewire_master_write()) { // read bits from slave
- return false; // an error occurred
- }
-
- return true;
-}
-
-uint64_t onewire_master_rom_read(void)
-{
- uint8_t rom_code[8] = {0}; // to store 64 bits ROM code
- if (!onewire_master_function_read(0x33, rom_code, 64)) { // read ROM code (I'm cheating because the ROM command isn't a function command, but it works the same way in the end)
- return 0; // an error occurred
- }
- if (onewire_master_crc(rom_code, LENGTH(rom_code))) { // verify checksum
- return 0; // checksum is wrong (not 0)
- }
-
- // return ROM code
- uint64_t code = 0;
- for (uint32_t i = 0; i < 8; i++) {
- code += (uint64_t)rom_code[i] << (8 * i); // add byte
- }
-
- return code;
-}
-
-bool onewire_master_rom_search(uint64_t* code, bool alarm)
-{
- static uint8_t conflict_last = 64; // on which bit has the conflict been detected (64 means there hasn't been)
- uint8_t conflict_current = 64; // to remember on which bit the last unknown conflict has been detected
- uint8_t bits[1] = {0}; // small buffer to store the bits used to search the ROM codes
-
- // send SEARCH ROM command
- uint8_t command = 0xf0; // SEARCH ROM command
- if (alarm) { // looking only for ROM codes for slaves in alarm state
- command = 0xec; // use ALARM SEARCH ROM command instead
- }
- if (!onewire_master_function_read(command, NULL, 0)) { // send SEARCH ROM command
- goto end; // an error occurred
- }
-
- if (conflict_last >= 64) { // no previous conflict has been detected
- *code = 0; // restart search codes
- }
-
- buffer = bits; // buffer to read up to two bits
- for (uint8_t bit = 0; bit < 64; bit++) { // go through all 64 bits ROM code
- buffer_size = 2; // read two first bits to detect conflict
- if (!onewire_master_read()) { // read ROM ID from slave
- goto end; // an error occurred
- }
- switch (buffer[0] & 0x03) { // check 2 bits received
- case 0: // collision detected
- if (bit == conflict_last) { // this conflict is known
- *code |= (((uint64_t)1) << bit); // use 0 as next bit
- } else { // unknown conflict
- conflict_current = bit; // remember conflict
- *code &= ~(((uint64_t)1) << bit); // use 1 as next bit
- }
- break;
- case 1: // no conflict, valid bit is 1
- *code |= (((uint64_t)1) << bit); // remember valid bit 1
- break;
- case 2: // no conflict, valid bit is 0
- *code &= ~(((uint64_t)1) << bit); // remember valid bit 0
- break;
- default: // two 1's indicate there is no slave
- conflict_current = 64; // remember there was no conflict because there is no slave
- goto end; // an error has occurred
- }
- buffer_size = 1; // to send next bit
- buffer[0] = ((*code) >> bit); // set bit to send
- if (!onewire_master_write()) { // send bit
- goto end; // an error has occurred
- }
- }
- // verify ROM code
- uint8_t rom_code[8] = {0}; // to store ROM code
- for (uint8_t i = 0; i < LENGTH(rom_code); i++) {
- rom_code[i] = (*code) >> (8 * i); // split and save last code in ROM code
- }
- if (onewire_master_crc(rom_code, LENGTH(rom_code))) { // verify checksum
- *code = 0; // return the last code found since it's valid
- }
-
-end:
- conflict_last = conflict_current; // update the last seen and unknown conflict
- if (conflict_current < 64) { // we have seen an unknown conflict
- return true; // tell there are more slaves
- } else { // no conflict seen
- return false; // no more slaves
- }
-}
-
-bool onewire_master_rom_skip(void)
-{
- if (!onewire_master_function_write(0xcc, NULL, 0)) { // send SKIP ROM command
- return false; // an error occurred
- }
- return true;
-}
-
-bool onewire_master_rom_match(uint64_t code)
-{
- uint8_t rom_code[8] = {0}; // to store ROM code
- for (uint8_t i = 0; i < LENGTH(rom_code); i++) {
- rom_code[i] = code >> (8 * i); // split and save code in ROM code
- }
- if (!onewire_master_function_write(0x55, rom_code, 64)) { // send MATCH ROM command with ROM code
- return false; // an error occurred
- }
- return true;
-}
diff --git a/lib/onewire_master.h b/lib/onewire_master.h
deleted file mode 100644
index fe18c62..0000000
--- a/lib/onewire_master.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/** library for 1-wire protocol as master
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: timer @ref onewire_master_timer, GPIO @ref onewire_master_gpio
- * @note overdrive mode is not provided
- */
-#pragma once
-
-/** setup 1-wire peripheral
- */
-void onewire_master_setup(void);
-/** release 1-wire peripheral
- */
-void onewire_master_release(void);
-/** send reset pulse
- * @return if slaves have indicated their presence
- */
-bool onewire_master_reset(void);
-/** compute CRC for 1-Wire
- * @note this CRC-8 uses normal polynomial 0x31, reverse polynomial 0x8C, start value 0x00
- * @param[in] data bytes on which to calculate CRC checksum on
- * @param[in] length number of bytes in data
- * @return computed CRC checksum
- */
-uint8_t onewire_master_crc(uint8_t* data, uint32_t length);
-/** send READ ROM command and read ROM code response
- * @note user needs to send reset pulse before
- * @return ROM code read
- */
-uint64_t onewire_master_rom_read(void);
-/** send SEARCH ROM command
- * @note user needs to send reset pulse before
- * @warning undefined behaviour if a ROM code different than the last found is provided
- * @param[in,out] code use 0 to start search ROM code from scratch, or last know value to search next; writes back next ROM code found, or 0 if error occurred
- * @param[in] alarm search only for ROM codes for slaves with an alarm flag set
- * @return if an additional slave has been detected
- * @warning when the code found is 0 it very probably means that the 1-wire line is not pulled up instead of actually having found a slave with ROM code 0
- */
-bool onewire_master_rom_search(uint64_t* code, bool alarm);
-/** send SKIP ROM command (all slaves on the bus will be selected)
- * @note user needs to send reset pulse before
- * @return if operation succeeded
- */
-bool onewire_master_rom_skip(void);
-/** send MATCH ROM command to select a specific slave
- * @note user needs to send reset pulse before
- * @param[in] code ROM code of slave to select
- * @return if operation succeeded
- */
-bool onewire_master_rom_match(uint64_t code);
-/** read data byte
- * @note it is up to the user to send the reset pulse
- * @param[out] data buffer to save data read
- * @return if operation succeeded
- */
-bool onewire_master_read_byte(uint8_t* data);
-/** write data byte
- * @note it is up to the user to send the reset pulse
- * @param[in] data byte to write
- * @return if operation succeeded
- */
-bool onewire_master_write_byte(uint8_t data);
-/** issue function and read data
- * @note user needs to send a ROM command before
- * @param[in] function function command to send
- * @param[out] data buffer to save read bits (NULL if only the function command should be sent)
- * @param[in] bits number of bits to read (0 if only the function command should be sent)
- * @return if operation succeeded
- */
-bool onewire_master_function_read(uint8_t function, uint8_t* data, uint32_t bits);
-/** issue function and write data
- * @note user needs to send a ROM command before
- * @param[in] function function command to send
- * @param[out] data data to write (NULL if only the function command should be sent)
- * @param[in] bits number of bits to write (0 if only the function command should be sent)
- * @return if operation succeeded
- */
-bool onewire_master_function_write(uint8_t function, uint8_t* data, uint32_t bits);
-
-/** device corresponding to a family code
- */
-struct onewire_family_code_t {
- uint8_t code; /**< ROM ID code */
- const char* device; /**< device name(s) */
-};
-
-/** list of possible devices corresponding to the family code
- * sources:
- * - http://owfs.org/index.php?page=family-code-list
- * - http://owfs.sourceforge.net/family.html
- * - https://www.maximintegrated.com/en/app-notes/index.mvp/id/155
- * - https://github.com/owfs/owfs-doc/wiki/1Wire-Device-List
- * - IDs seen or reported
- */
-static const struct onewire_family_code_t onewire_family_codes[] = {
- {
- .code = 0x01,
- .device = "DS1990R/DS2401/DS2411/DS2490A",
- },
- {
- .code = 0x02,
- .device = "DS1991/DS1425",
- },
- {
- .code = 0x04,
- .device = "DS1994/DS2404",
- },
- {
- .code = 0x05,
- .device = "DS2405",
- },
- {
- .code = 0x06,
- .device = "DS1993",
- },
- {
- .code = 0x08,
- .device = "DS1992",
- },
- {
- .code = 0x09,
- .device = "DS1982/DS2502/DS2703/DS2704",
- },
- {
- .code = 0x0a,
- .device = "DS1995",
- },
- {
- .code = 0x0b,
- .device = "DS1985/DS2505",
- },
- {
- .code = 0x0c,
- .device = "DS1996",
- },
- {
- .code = 0x0f,
- .device = "DS1986/DS2506",
- },
- {
- .code = 0x10,
- .device = "DS1920/DS18S20",
- },
- {
- .code = 0x12,
- .device = "DS2406/DS2407",
- },
- {
- .code = 0x14,
- .device = "DS1971/DS2430A",
- },
- {
- .code = 0x16,
- .device = "DS1954/DS1957",
- },
- {
- .code = 0x18,
- .device = "DS1963S/DS1962",
- },
- {
- .code = 0x1a,
- .device = "DS1963L",
- },
- {
- .code = 0x1b,
- .device = "DS2436",
- },
- {
- .code = 0x1c,
- .device = "DS28E04-100",
- },
- {
- .code = 0x1d,
- .device = "DS2423",
- },
- {
- .code = 0x1e,
- .device = "DS2437",
- },
- {
- .code = 0x1f,
- .device = "DS2409",
- },
- {
- .code = 0x20,
- .device = "DS2450",
- },
- {
- .code = 0x21,
- .device = "DS1921",
- },
- {
- .code = 0x22,
- .device = "DS1922",
- },
- {
- .code = 0x23,
- .device = "DS1973/DS2433",
- },
- {
- .code = 0x24,
- .device = "DS1904/DS2415",
- },
- {
- .code = 0x26,
- .device = "DS2438",
- },
- {
- .code = 0x27,
- .device = "DS2417",
- },
- {
- .code = 0x28,
- .device = "DS18B20",
- },
- {
- .code = 0x29,
- .device = "DS2408",
- },
- {
- .code = 0x2c,
- .device = "DS2890",
- },
- {
- .code = 0x2d,
- .device = "DS1972/DS2431",
- },
- {
- .code = 0x2e,
- .device = "DS2770",
- },
- {
- .code = 0x2f,
- .device = "DS28E01-100",
- },
- {
- .code = 0x30,
- .device = "DS2760/DS2761/DS2762",
- },
- {
- .code = 0x31,
- .device = "DS2720",
- },
- {
- .code = 0x32,
- .device = "DS2780",
- },
- {
- .code = 0x33,
- .device = "DS1961S/DS2432",
- },
- {
- .code = 0x34,
- .device = "DS2703",
- },
- {
- .code = 0x35,
- .device = "DS2755",
- },
- {
- .code = 0x36,
- .device = "DS2740",
- },
- {
- .code = 0x37,
- .device = "DS1977",
- },
- {
- .code = 0x3a,
- .device = "DS2413",
- },
- {
- .code = 0x3b,
- .device = "DS1825/MAX31826/MAX31850",
- },
- {
- .code = 0x3d,
- .device = "DS2781",
- },
- {
- .code = 0x41,
- .device = "DS1922/DS1923/DS2422",
- },
- {
- .code = 0x42,
- .device = "DS28EA00",
- },
- {
- .code = 0x43,
- .device = "DS28EC20",
- },
- {
- .code = 0x44,
- .device = "DS28E10",
- },
- {
- .code = 0x51,
- .device = "DS2751",
- },
- {
- .code = 0x7e,
- .device = "EDS00xx",
- },
- {
- .code = 0x81,
- .device = "DS1420/DS2490R/DS2490B",
- },
- {
- .code = 0x82,
- .device = "DS1425",
- },
- {
- .code = 0x84,
- .device = "DS2404S",
- },
- {
- .code = 0x89,
- .device = "DS1982U/DS2502",
- },
- {
- .code = 0x8b,
- .device = "DS1985U/DS2505",
- },
- {
- .code = 0x8f,
- .device = "DS1986U/DS2506",
- },
- {
- .code = 0xa0,
- .device = "mRS001",
- },
- {
- .code = 0xa1,
- .device = "mVM001",
- },
- {
- .code = 0xa2,
- .device = "mCM001",
- },
- {
- .code = 0xa6,
- .device = "mTS017",
- },
- {
- .code = 0xb1,
- .device = "mTC001",
- },
- {
- .code = 0xb2,
- .device = "mAM001",
- },
- {
- .code = 0xb3,
- .device = "DS2432/mTC002",
- },
- {
- .code = 0xfc,
- .device = "BAE0910/BAE0911",
- },
- {
- .code = 0xff,
- .device = "Swart LCD",
- }
-};
diff --git a/lib/onewire_slave.c b/lib/onewire_slave.c
deleted file mode 100644
index edf87ce..0000000
--- a/lib/onewire_slave.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/** library for 1-wire protocol as master
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: GPIO and timer @ref onewire_slave_timer, GPIO @ref onewire_slave_gpio
- * @note overdrive mode is not supported
- * @implements 1-Wire protocol description from Book of iButton Standards
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdbool.h> // boolean type
-#include <stddef.h> // NULL definition
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/timer.h> // timer library
-#include <libopencm3/stm32/exti.h> // external interrupt library
-
-/* own libraries */
-#include "global.h" // help macros
-#include "onewire_slave.h" // own definitions
-
-/** @defgroup onewire_slave_timer timer used to measure 1-wire signal timing
- * @{
- */
-#define ONEWIRE_SLAVE_TIMER 2 /**< timer ID */
-/** @} */
-
-/** @defgroup onewire_slave_gpio GPIO used for 1-wire signal
- * @warning ensure no same pin number on other parts are used for external interrupts
- * @note external pull-up resistor on pin is required (< 5 kOhm), generally provided by the master
- * @{
- */
-#define ONEWIRE_SLAVE_PIN PA4 /**< GPIO pin */
-/** @} */
-
-/** state of 1-Wire communication */
-static volatile enum {
- ONEWIRE_STATE_IDLE, /**< no current communication */
- ONEWIRE_STATE_RESET, /**< reset pulse has been detected */
- ONEWIRE_STATE_WAIT_PRESENCE, /**< waiting before sending the presence pulse */
- ONEWIRE_STATE_PULSE_PRESENCE, /**< sending the presence pulse */
- ONEWIRE_STATE_ROM_COMMAND, /**< slave is reading ROM command bits */
- ONEWIRE_STATE_ROM_READ, /**< slave is sending ROM code in response to ROM command READ ROM */
- ONEWIRE_STATE_ROM_MATCH, /**< master is sending ROM code to select slave */
- ONEWIRE_STATE_ROM_SEARCH_TRUE, /**< master is searching ROM code, slave will send first bit (not negated) */
- ONEWIRE_STATE_ROM_SEARCH_FALSE, /**< master is searching ROM code, slave will send first bit (not negated) */
- ONEWIRE_STATE_ROM_SEARCH_SELECT, /**< master is searching ROM code, slave will read selected bit */
- ONEWIRE_STATE_FUNCTION_COMMAND, /**< slave is reading function command bits */
- ONEWIRE_STATE_FUNCTION_DATA, /**< waiting for user to provide data to transfer */
- ONEWIRE_STATE_FUNCTION_READ, /**< slave is reading bits */
- ONEWIRE_STATE_FUNCTION_WRITE, /**< slave is writing bits */
- ONEWIRE_MAX /** to count the number of possible states */
-} onewire_slave_state = ONEWIRE_STATE_IDLE;
-
-static uint8_t onewire_slave_rom_code[8] = {0}; /**< slave ROM code */
-
-volatile bool onewire_slave_function_code_received = false;
-volatile uint8_t onewire_slave_function_code = 0;
-volatile bool onewire_slave_transfer_complete = false;
-
-static volatile uint8_t bits_buffer = 0; /**< buffer for the incoming bits (up to one byte) */
-static volatile uint32_t bits_bit = 0; /**< number of incoming bits */
-static volatile uint8_t* onewire_slave_transfer_data = NULL; /**< data to transfer (read or write) */
-static volatile uint32_t onewire_slave_transfer_bits = 0; /**< number of bits to transfer */
-
-/** compute CRC for 1-Wire
- * @note this CRC-8 uses normal polynomial 0x31, reverse polynomial 0x8C, start value 0x00
- * @param[in] data bytes on which to calculate CRC checksum on
- * @param[in] length number of bytes in data
- * @return computed CRC checksum
- */
-static uint8_t onewire_slave_crc(uint8_t* data, uint32_t length)
-{
- if (NULL==data || 0==length) { // check input
- return 0; // wrong input
- }
-
- uint8_t crc = 0x00; // initial value
- for (uint8_t i=0; i<length; i++) { // go through every byte
- crc ^= data[i]; // XOR byte
- for (uint8_t b=0; b<8; b++) { // go through every bit
- if (crc&0x01) { // least significant bit is set (we are using the reverse way)
- crc = (crc>>1)^0x8C; // // shift to the right (for the next bit) and XOR with (reverse) polynomial
- } else {
- crc >>= 1; // just shift right (for the next bit)
- }
- }
- }
- return crc;
-}
-
-void onewire_slave_setup(uint8_t family, uint64_t serial)
-{
- // save ROM code (LSB first)
- onewire_slave_rom_code[0] = family;
- onewire_slave_rom_code[1] = serial >> 40;
- onewire_slave_rom_code[2] = serial >> 32;
- onewire_slave_rom_code[3] = serial >> 24;
- onewire_slave_rom_code[4] = serial >> 16;
- onewire_slave_rom_code[5] = serial >> 8;
- onewire_slave_rom_code[6] = serial >> 0;
- onewire_slave_rom_code[7] = onewire_slave_crc(onewire_slave_rom_code, 7); // calculate CRC
-
- // setup timer to generate/measure signal timing
- rcc_periph_clock_enable(RCC_TIM(ONEWIRE_SLAVE_TIMER)); // enable clock for timer peripheral
- rcc_periph_reset_pulse(RST_TIM(ONEWIRE_SLAVE_TIMER)); // reset timer state
- timer_set_mode(TIM(ONEWIRE_SLAVE_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(ONEWIRE_SLAVE_TIMER), 1 - 1); // don't use prescale since this 16 bits timer allows to wait > 480 us used for the reset pulse ( 1/(72E6/1/(2**16))=910us )
-
- // use comparator to time signal (without using the output), starting at slot start
- timer_set_period(TIM(ONEWIRE_SLAVE_TIMER), 480 * (rcc_ahb_frequency / 1000000) - 1 - 1300); // minimum time needed for a reset pulse (480 < Trst), plus hand tuning
- timer_set_oc_mode(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC1, TIM_OCM_FROZEN);
- timer_set_oc_value(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC1, 16 * (rcc_ahb_frequency / 1000000) - 1); // time to wait before sending the presence pulse, after the rising edge of the reset pulse (15 < Tpdh < 60)
- timer_set_oc_mode(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC2, TIM_OCM_FROZEN);
- timer_set_oc_value(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC2, 45 * (rcc_ahb_frequency / 1000000) - 1 - 350); // time to sample the bit after being set (1 < Tlow1 < 15, 60 < Tslot < 120), or stop sending the bit use compare function to detect slave presence (15 = Trdv + 0 < Trelease < 45), plus hand tuning
- timer_set_oc_value(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC3, 90 * (rcc_ahb_frequency / 1000000) - 1); // time to stop the presence pulse (60 < Tpdl < 120)
- timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // clear all interrupt flags
- timer_update_on_overflow(TIM(ONEWIRE_SLAVE_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout)
- timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_UIE); // enable update interrupt for overflow
- nvic_enable_irq(NVIC_TIM_IRQ(ONEWIRE_SLAVE_TIMER)); // catch interrupt in service routine
-
- onewire_slave_function_code_received = false; // reset state
- onewire_slave_state = ONEWIRE_STATE_IDLE; // reset state
- onewire_slave_transfer_complete = false; // reset state
-
- // setup GPIO with external interrupt
- rcc_periph_clock_enable(GPIO_RCC(ONEWIRE_SLAVE_PIN)); // enable clock for GPIO peripheral
- gpio_set(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_PIN(ONEWIRE_SLAVE_PIN)); // idle is high (using pull-up resistor)
- gpio_set_mode(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(ONEWIRE_SLAVE_PIN)); // control output using open drain (this mode also allows to read the input signal)
- rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
- exti_select_source(GPIO_EXTI(ONEWIRE_SLAVE_PIN), GPIO_PORT(ONEWIRE_SLAVE_PIN)); // mask external interrupt of this pin only for this port
- exti_set_trigger(GPIO_EXTI(ONEWIRE_SLAVE_PIN), EXTI_TRIGGER_BOTH); // trigger on signal change
- exti_enable_request(GPIO_EXTI(ONEWIRE_SLAVE_PIN)); // enable external interrupt
- nvic_enable_irq(GPIO_NVIC_EXTI_IRQ(ONEWIRE_SLAVE_PIN)); // enable interrupt
-}
-
-bool onewire_slave_function_read(uint8_t* data, size_t size)
-{
- if (NULL == data || 0 == size) { // verify input
- return false;
- }
- if (UINT32_MAX / 8 < size) { // too many bits to transfer
- return false;
- }
- if (onewire_slave_state != ONEWIRE_STATE_FUNCTION_DATA) { // not in the right state to transfer data
- return false;
- }
- onewire_slave_transfer_data = data; // save buffer to write to
- onewire_slave_transfer_bits = size*8; // number of bits to read
- onewire_slave_transfer_complete = false; // reset state
- bits_bit = 0; // reset number of bits read
- onewire_slave_state = ONEWIRE_STATE_FUNCTION_READ; // read data
- return true;
-}
-
-bool onewire_slave_function_write(const uint8_t* data, size_t size)
-{
- if (NULL == data || 0 == size) { // verify input
- return false;
- }
- if (onewire_slave_state != ONEWIRE_STATE_FUNCTION_DATA) { // not in the right state to transfer data
- return false;
- }
- if (UINT32_MAX / 8 < size) { // too many bits to transfer
- return false;
- }
- onewire_slave_transfer_data = (uint8_t*)data; // save buffer to read from
- onewire_slave_transfer_bits = size*8; // number of bits to write
- onewire_slave_transfer_complete = false; // reset state
- bits_bit = 0; // reset number of bits written
- bits_buffer = onewire_slave_transfer_data[0]; // prepare byte to write
- onewire_slave_state = ONEWIRE_STATE_FUNCTION_WRITE; // write data
- return true;
-}
-
-/** interrupt service routine called when 1-Wire signal changes */
-void GPIO_EXTI_ISR(ONEWIRE_SLAVE_PIN)(void)
-{
- exti_reset_request(GPIO_EXTI(ONEWIRE_SLAVE_PIN)); // reset interrupt
- if (gpio_get(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_PIN(ONEWIRE_SLAVE_PIN))) { // it's a rising edge
- switch (onewire_slave_state) {
- case ONEWIRE_STATE_RESET: // reset pulse has ended
- timer_disable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // stop timer for reconfiguration
- timer_set_counter(TIM(ONEWIRE_SLAVE_TIMER), 0); // reset timer counter
- timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC1IF); // clear flag
- timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC1IE); // enable compare interrupt for presence pulse
- timer_enable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // start timer to generate timing
- onewire_slave_state = ONEWIRE_STATE_WAIT_PRESENCE; // set new stated
- break;
- case ONEWIRE_STATE_PULSE_PRESENCE: // we stopped sending the presence pulse
- onewire_slave_state = ONEWIRE_STATE_ROM_COMMAND; // we now expect a ROM command
- bits_bit = 0; // reset buffer bit count
- break; // no need to stop the time, the reset will be checked correctly
- default: // rising edge is not important is the other cases
- break; // nothing to do
- }
- } else { // it's a falling edge, the beginning of a new signal
- timer_disable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // stop timer for reconfiguration
- timer_set_counter(TIM(ONEWIRE_SLAVE_TIMER), 0); // reset timer counter
- timer_disable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE); // disable all timers
- switch (onewire_slave_state) {
- case ONEWIRE_STATE_PULSE_PRESENCE: // we started sending the presence pulse
- timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC3IE); // enable timer for end of pulse
- break;
- case ONEWIRE_STATE_ROM_COMMAND: // read ROM command bits
- case ONEWIRE_STATE_ROM_MATCH: // read ROM code bits
- case ONEWIRE_STATE_FUNCTION_COMMAND: // read function command bits
- case ONEWIRE_STATE_ROM_SEARCH_SELECT: // read selected ROM code bit
- case ONEWIRE_STATE_FUNCTION_READ: // read function data bit
- timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC2IE); // enable timer for reading bit
- break;
- case ONEWIRE_STATE_ROM_READ: // send ROM code bit
- case ONEWIRE_STATE_ROM_SEARCH_TRUE: // send ROM code bit while searching ROM, not negated
- case ONEWIRE_STATE_ROM_SEARCH_FALSE: // send ROM code bit while searching ROM, already negated
- case ONEWIRE_STATE_FUNCTION_WRITE: // write function data bit
- timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC2IE); // enable timer for reading bit
- if (0 == (bits_buffer & (1 << (bits_bit % 8)))) { // need to send a 0 bit
- gpio_clear(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_PIN(ONEWIRE_SLAVE_PIN)); // hold low to send 0 bit
- }
- break;
- case ONEWIRE_STATE_IDLE: // we only expect a reset
- default: // we don't expect any falling edge in other states
- onewire_slave_state = ONEWIRE_STATE_IDLE; // unexpected signal, reset to idle state
- break; // the timer overflow will confirm detect reset pulses
- }
- timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // clear all flags
- timer_enable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // start timer to measure the configured timeouts
- }
-}
-
-/** interrupt service routine called for timer */
-void TIM_ISR(ONEWIRE_SLAVE_TIMER)(void)
-{
- if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF)) { // reset timer triggered, verify if it's a reset
- if (0 == gpio_get(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_PIN(ONEWIRE_SLAVE_PIN))) { // signal it still low, thus it must be a reset
- onewire_slave_state = ONEWIRE_STATE_RESET; // update state
- }
- timer_disable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // stop timer since there is nothing more to measure
- timer_disable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE); // disable all timers
- timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // clear all flag (I have no idea why the others are get too, even when the interrupt is not enabled)
- }
- if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC1IF)) { // wait for presence pulse timer triggered
- timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC1IF); // clear flag
- if (ONEWIRE_STATE_WAIT_PRESENCE == onewire_slave_state) { // we can now send the pulse
- onewire_slave_state = ONEWIRE_STATE_PULSE_PRESENCE; // save new state
- gpio_clear(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_PIN(ONEWIRE_SLAVE_PIN)); // send presence pulse (will also trigger the timer start)
- }
- }
- if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC2IF)) { // time to read the bit, or stop writing it
- // read/write bit depending on bit
- switch (onewire_slave_state) {
- case ONEWIRE_STATE_ROM_COMMAND: // read ROM command code bit
- case ONEWIRE_STATE_ROM_MATCH: // read ROM code
- case ONEWIRE_STATE_FUNCTION_COMMAND: // read function command code bit
- case ONEWIRE_STATE_ROM_SEARCH_SELECT: // read selected ROM code bit
- case ONEWIRE_STATE_FUNCTION_READ: // read function data bit
- if (gpio_get(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_PIN(ONEWIRE_SLAVE_PIN))) { // bit is set to 1
- bits_buffer |= (1 << (bits_bit % 8)); // set bit
- } else { // bit is set to 0
- bits_buffer &= ~(1 << (bits_bit % 8)); // clear bit
- }
- bits_bit++; // go to next bit
- break;
- case ONEWIRE_STATE_ROM_READ: // write ROM code
- case ONEWIRE_STATE_FUNCTION_WRITE: // write function data bit
- gpio_set(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_PIN(ONEWIRE_SLAVE_PIN)); // stop sending bit
- bits_bit++; // go to next bit
- break;
- case ONEWIRE_STATE_ROM_SEARCH_TRUE: // ROM code bit is sent
- case ONEWIRE_STATE_ROM_SEARCH_FALSE: // ROM code bit is sent
- gpio_set(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_PIN(ONEWIRE_SLAVE_PIN)); // stop sending bit
- break;
- default: // these states don't need read/write
- break;
- }
- static uint8_t rom_code_byte; // which byte of the ROM code is processed
- // act on bit count
- switch (onewire_slave_state) {
- case ONEWIRE_STATE_ROM_COMMAND: // read ROM command
- if (bits_bit > 7) { // complete ROM command code received
- bits_bit = 0; // reset buffer
- rom_code_byte = 0; // reset ROM code byte index
- switch (bits_buffer) { // act depending on ROM command code
- case 0x33: // READ ROM
- bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare to send the first byte
- onewire_slave_state = ONEWIRE_STATE_ROM_READ; // write ROM code
- break;
- case 0xcc: // SKIP ROM
- onewire_slave_state = ONEWIRE_STATE_FUNCTION_COMMAND; // now read function command code
- break;
- case 0x55: // MATCH ROM
- onewire_slave_state = ONEWIRE_STATE_ROM_MATCH; // read ROM code
- break;
- case 0xf0: // SEARCH ROM
- bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare to search code
- onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_TRUE; // prepare to start sending first new bit
- break;
- default: // unknown ROM code
- onewire_slave_state = ONEWIRE_STATE_IDLE; // go back to default idle state
- break;
- }
- }
- break;
- case ONEWIRE_STATE_ROM_READ: // send ROM code
- if (bits_bit > 7) { // complete byte transmitted
- rom_code_byte++; // go to next ROM code byte
- if (rom_code_byte>LENGTH(onewire_slave_rom_code)) { // complete ROM code send
- onewire_slave_state = ONEWIRE_STATE_IDLE; // go back to default idle state
- } else {
- bits_bit = 0; // reset buffer
- bits_buffer = onewire_slave_rom_code[rom_code_byte]; // send next ROM code byte
- }
- }
- break;
- case ONEWIRE_STATE_ROM_MATCH: // compare ROM code
- if (bits_bit > 7) { // complete byte received
- if (bits_buffer == onewire_slave_rom_code[rom_code_byte]) { // ROM code byte matches
- bits_bit = 0; // reset buffer
- rom_code_byte++; // go to next ROM code byte
- if (rom_code_byte >= LENGTH(onewire_slave_rom_code)) { // complete ROM code matches
- onewire_slave_state = ONEWIRE_STATE_FUNCTION_COMMAND; // now read function command code
- }
- } else { // ROM code does not match
- onewire_slave_state = ONEWIRE_STATE_IDLE; // stop comparing and go back to idle
- }
- }
- break;
- case ONEWIRE_STATE_ROM_SEARCH_TRUE: // ROM code bit is send, prepare to send negated version
- bits_buffer ^= (1 << bits_bit); // negate bit
- onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_FALSE; // send negated version
- break;
- case ONEWIRE_STATE_ROM_SEARCH_FALSE: // negated ROM code bit is send, prepare to read selected bit
- onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_SELECT; // read selected
- break;
- case ONEWIRE_STATE_ROM_SEARCH_SELECT: // check if we are selected
- if ((bits_buffer&(1 << (bits_bit - 1))) == (onewire_slave_rom_code[rom_code_byte] & (1 << (bits_bit - 1)))) { // we have been selected
- onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_TRUE; // prepare to compare next bit
- } else { // we are no selected
- onewire_slave_state = ONEWIRE_STATE_IDLE; // go back to idle
- }
- if (bits_bit > 7) { // complete byte searched
- bits_bit = 0; // reset buffer
- rom_code_byte++; // go to next ROM code byte
- if (rom_code_byte >= LENGTH(onewire_slave_rom_code)) { // complete ROM code search
- onewire_slave_state = ONEWIRE_STATE_FUNCTION_COMMAND; // now read function command code
- } else {
- bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare next ROM code byte
- }
- }
- break;
- case ONEWIRE_STATE_FUNCTION_COMMAND: // read function command
- if (bits_bit > 7) { // complete function command code received
- onewire_slave_function_code = bits_buffer; // save function command code to user buffer
- onewire_slave_state = ONEWIRE_STATE_FUNCTION_DATA; // let the user transfer data
- onewire_slave_function_code_received = true; // notify user
- }
- break;
- case ONEWIRE_STATE_FUNCTION_READ: // save function data bit
- if (0 == bits_bit % 8) { // complete byte received
- onewire_slave_transfer_data[(bits_bit - 1) / 8] = bits_buffer; // save received bytes
- }
- if (bits_bit >= onewire_slave_transfer_bits) { // read transfer complete
- onewire_slave_transfer_data[(bits_bit - 1) / 8] = bits_buffer; // save last bits
- onewire_slave_state = ONEWIRE_STATE_FUNCTION_DATA; // let the user transfer more data
- onewire_slave_transfer_complete = true; // notify user
- }
- break;
- case ONEWIRE_STATE_FUNCTION_WRITE: // update function data bit to write
- if (0 == bits_bit % 8) { // complete byte transfer
- bits_buffer = onewire_slave_transfer_data[bits_bit / 8]; // prepare next byte to write
- }
- if (bits_bit >= onewire_slave_transfer_bits) { // write transfer complete
- onewire_slave_state = ONEWIRE_STATE_FUNCTION_DATA; // let the user transfer more data
- onewire_slave_transfer_complete = true; // notify user
- }
- break;
- default: // no action needed
- break;
- }
- timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC2IF); // clear flag
- }
- if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC3IF)) { // end of presence pulse timer triggered
- timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC3IF); // clear flag
- if (ONEWIRE_STATE_PULSE_PRESENCE == onewire_slave_state) {
- gpio_set(GPIO_PORT(ONEWIRE_SLAVE_PIN), GPIO_PIN(ONEWIRE_SLAVE_PIN)); // stop sending presence pulse
- // if the pin stays low the reset timer will catch it
- }
- }
-}
diff --git a/lib/onewire_slave.h b/lib/onewire_slave.h
deleted file mode 100644
index 72836b7..0000000
--- a/lib/onewire_slave.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/** library for 1-wire protocol as slave
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: timer @ref onewire_slave_timer, GPIO @ref onewire_slave_gpio
- * @note overdrive mode is not supported
- */
-#pragma once
-#error not converted for STM32F4
-
-/** set when a function command code has been received
- * @note needs to be cleared by user
- */
-extern volatile bool onewire_slave_function_code_received;
-/** last function command code received */
-extern volatile uint8_t onewire_slave_function_code;
-/** set when data read/write transfer has been completed
- * @note needs to be cleared by user
- */
-extern volatile bool onewire_slave_transfer_complete;
-
-/** setup 1-wire peripheral
- * @param[in] family family code for slave ROM code (8 bits)
- * @param[in] serial serial number for slave ROM code (48 bits)
- */
-void onewire_slave_setup(uint8_t family, uint64_t serial);
-/** read data from master
- * @param[out] data buffer to save read bits
- * @param[in] size number of bytes to read
- * @return if transfer initialization succeeded
- * @note onewire_slave_transfer_complete is set when transfer is completed
- */
-bool onewire_slave_function_read(uint8_t* data, size_t size);
-/** write data to master
- * @param[in] data data to write
- * @param[in] size number of bytes to write
- * @return if transfer initialization succeeded
- * @note onewire_slave_transfer_complete is set when transfer is completed
- */
-bool onewire_slave_function_write(const uint8_t* data, size_t size);
diff --git a/lib/radio_esp8266.c b/lib/radio_esp8266.c
deleted file mode 100644
index ba65719..0000000
--- a/lib/radio_esp8266.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/** library to send data using ESP8266 WiFi SoC (code)
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016
- * @note peripherals used: USART @ref radio_esp8266_usart
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <string.h> // string and memory utilities
-#include <stdio.h> // string utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/usart.h> // universal synchronous asynchronous receiver transmitter library
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-
-#include "radio_esp8266.h" // radio header and definitions
-#include "global.h" // common methods
-
-/** @defgroup radio_esp8266_usart USART peripheral used for communication with radio
- * @{
- */
-#define RADIO_ESP8266_USART 2 /**< USART peripheral */
-/** @} */
-
-/* input and output buffers and used memory */
-static uint8_t rx_buffer[24] = {0}; /**< buffer for received data (we only expect AT responses) */
-static volatile uint16_t rx_used = 0; /**< number of byte in receive buffer */
-static uint8_t tx_buffer[256] = {0}; /**< buffer for data to transmit */
-static volatile uint16_t tx_used = 0; /**< number of bytes used in transmit buffer */
-
-volatile bool radio_esp8266_activity = false;
-volatile bool radio_esp8266_success = false;
-
-/** transmit data to radio
- * @param[in] data data to transmit
- * @param[in] length length of data to transmit
- */
-static void radio_esp8266_transmit(uint8_t* data, uint8_t length) {
- while (tx_used || !usart_get_flag(USART(RADIO_ESP8266_USART), USART_SR_TXE)) { // wait until ongoing transmission completed
- usart_enable_tx_interrupt(USART(RADIO_ESP8266_USART)); // enable transmit interrupt
- __WFI(); // sleep until something happened
- }
- usart_disable_tx_interrupt(USART(RADIO_ESP8266_USART)); // ensure transmit interrupt is disable to prevent index corruption (the ISR should already have done it)
- radio_esp8266_activity = false; // reset status because of new activity
- for (tx_used=0; tx_used<length && tx_used<LENGTH(tx_buffer); tx_used++) { // copy data
- tx_buffer[tx_used] = data[length-1-tx_used]; // put character in buffer (in reverse order)
- }
- if (tx_used) {
- usart_enable_tx_interrupt(USART(RADIO_ESP8266_USART)); // enable interrupt to send bytes
- }
-}
-
-void radio_esp8266_setup(void)
-{
- /* enable USART I/O peripheral */
- rcc_periph_clock_enable(RCC_AFIO); // enable pin alternate function (USART)
- rcc_periph_clock_enable(USART_PORT_RCC(RADIO_ESP8266_USART)); // enable clock for USART port peripheral
- rcc_periph_clock_enable(USART_RCC(RADIO_ESP8266_USART)); // enable clock for USART peripheral
- gpio_set_mode(USART_PORT(RADIO_ESP8266_USART), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USART_PIN_TX(RADIO_ESP8266_USART)); // setup GPIO pin USART transmit
- gpio_set_mode(USART_PORT(RADIO_ESP8266_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, USART_PIN_RX(RADIO_ESP8266_USART)); // setup GPIO pin USART receive
- gpio_set(USART_PORT(RADIO_ESP8266_USART), USART_PIN_RX(RADIO_ESP8266_USART)); // pull up to avoid noise when not connected
-
- /* setup USART parameters for ESP8266 AT firmware */
- usart_set_baudrate(USART(RADIO_ESP8266_USART), 115200); // AT firmware 0.51 (SDK 1.5.0) uses 115200 bps
- usart_set_databits(USART(RADIO_ESP8266_USART), 8);
- usart_set_stopbits(USART(RADIO_ESP8266_USART), USART_STOPBITS_1);
- usart_set_mode(USART(RADIO_ESP8266_USART), USART_MODE_TX_RX);
- usart_set_parity(USART(RADIO_ESP8266_USART), USART_PARITY_NONE);
- usart_set_flow_control(USART(RADIO_ESP8266_USART), USART_FLOWCONTROL_NONE);
-
- nvic_enable_irq(USART_IRQ(RADIO_ESP8266_USART)); // enable the USART interrupt
- usart_enable_rx_interrupt(USART(RADIO_ESP8266_USART)); // enable receive interrupt
- usart_enable(USART(RADIO_ESP8266_USART)); // enable USART
-
- /* reset buffer states */
- rx_used = 0;
- tx_used = 0;
- radio_esp8266_activity = false;
- radio_esp8266_success = false;
-
- radio_esp8266_transmit((uint8_t*)"AT\r\n",4); // verify if module is present
- while (!radio_esp8266_activity || !radio_esp8266_success) { // wait for response
- __WFI(); // sleep until something happened
- }
- radio_esp8266_transmit((uint8_t*)"AT+RST\r\n",8); // reset module
- while (!radio_esp8266_activity || !radio_esp8266_success) { // wait for response
- __WFI(); // sleep until something happened
- }
- while(rx_used<13 || memcmp((char*)&rx_buffer[rx_used-13], "WIFI GOT IP\r\n", 13)!=0) { // wait to have IP
- __WFI(); // sleep until something happened
- }
- radio_esp8266_transmit((uint8_t*)"ATE0\r\n",6); // disable echoing
- while (!radio_esp8266_activity || !radio_esp8266_success) { // wait for response
- __WFI(); // sleep until something happened
- }
-}
-
-void radio_esp8266_tcp_open(char* host, uint16_t port)
-{
- char command[256] = {0}; // string to create command
- int length = snprintf(command, LENGTH(command), "AT+CIPSTART=\"TCP\",\"%s\",%u\r\n", host, port); // create AT command to establish a TCP connection
- if (length>0) {
- radio_esp8266_transmit((uint8_t*)command, length);
- }
-}
-
-void radio_esp8266_send(uint8_t* data, uint8_t length)
-{
- char command[16+1] = {0}; // string to create command
- int command_length = snprintf(command, LENGTH(command), "AT+CIPSEND=%u\r\n", length); // create AT command to send data
- if (command_length>0) {
- radio_esp8266_transmit((uint8_t*)command, command_length); // transmit AT command
- while (!radio_esp8266_activity || !radio_esp8266_success) { // wait for response
- __WFI(); // sleep until something happened
- }
- if (!radio_esp8266_success) { // send AT command did not succeed
- return; // don't transmit data
- }
- radio_esp8266_transmit(data, length); // transmit data
- }
-}
-
-void radio_esp8266_close(void)
-{
- radio_esp8266_transmit((uint8_t*)"AT+CIPCLOSE\r\n", 13); // send AT command to close established connection
-}
-
-/** USART interrupt service routine called when data has been transmitted or received */
-void USART_ISR(RADIO_ESP8266_USART)(void)
-{
- if (usart_get_interrupt_source(USART(RADIO_ESP8266_USART), USART_SR_TXE)) { // data has been transmitted
- if (tx_used) { // there is still data in the buffer to transmit
- usart_send(USART(RADIO_ESP8266_USART),tx_buffer[tx_used-1]); // put data in transmit register
- tx_used--; // update used size
- } else { // no data in the buffer to transmit
- usart_disable_tx_interrupt(USART(RADIO_ESP8266_USART)); // disable transmit interrupt
- }
- }
- if (usart_get_interrupt_source(USART(RADIO_ESP8266_USART), USART_SR_RXNE)) { // data has been received
- while (rx_used>=LENGTH(rx_buffer)) { // if buffer is full
- memmove(rx_buffer,&rx_buffer[1],LENGTH(rx_buffer)-1); // drop old data to make space (ring buffer are more efficient but harder to handle)
- rx_used--; // update used buffer information
- }
- rx_buffer[rx_used++] = usart_recv(USART(RADIO_ESP8266_USART)); // put character in buffer
- // if the used send a packet with these strings during the commands detection the AT command response will break (AT commands are hard to handle perfectly)
- if (rx_used>=4 && memcmp((char*)&rx_buffer[rx_used-4], "OK\r\n", 4)==0) { // OK received
- radio_esp8266_activity = true; // response received
- radio_esp8266_success = true; // command succeeded
- rx_used = 0; // reset buffer
- } else if (rx_used>=7 && memcmp((char*)&rx_buffer[rx_used-7], "ERROR\r\n", 7)==0) { // ERROR received
- radio_esp8266_activity = true; // response received
- radio_esp8266_success = false; // command failed
- rx_used = 0; // reset buffer
- }
- }
-}
diff --git a/lib/radio_esp8266.h b/lib/radio_esp8266.h
deleted file mode 100644
index c515495..0000000
--- a/lib/radio_esp8266.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/** library to send data using ESP8266 WiFi SoC
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016
- * @note peripherals used: USART @ref radio_esp8266_usart
- */
-#pragma once
-#error not converted for STM32F4
-
-/** a response has been returned by the radio */
-extern volatile bool radio_esp8266_activity;
-/** the last command has succeeded */
-extern volatile bool radio_esp8266_success;
-
-/** setup peripherals to communicate with radio
- * @note this is blocking to ensure we are connected to the WiFi network
- */
-void radio_esp8266_setup(void);
-/** establish TCP connection
- * @param[in] host host to connect to
- * @param[in] port TCP port to connect to
- * @note wait for activity to get success status
- */
-void radio_esp8266_tcp_open(char* host, uint16_t port);
-/** send data (requires established connection)
- * @param[in] data data to send
- * @param[in] length size of data to send
- * @note wait for activity to get success status
- */
-void radio_esp8266_send(uint8_t* data, uint8_t length);
-/** close established connection
- * @note wait for activity to get success status
- */
-void radio_esp8266_close(void);
diff --git a/lib/radio_sx172x.c b/lib/radio_sx172x.c
deleted file mode 100644
index 48695d3..0000000
--- a/lib/radio_sx172x.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/** library to communication with Semtech SX172x LoRa radio module using SPI
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2020
- * @note peripherals used: SPI @ref radio_sx172x_spi, GPIO @ref radio_sx172x_gpio
- * @note the interrupts and corresponding DIO should be handled directly by the user
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <stdbool.h> // boolean utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/spi.h> // SPI library
-
-/* own libraries */
-#include "global.h" // common methods
-#include "radio_sx172x.h" // own definitions
-
-/** @defgroup radio_sx172x_spi SPI peripheral used to communicate with the SX172x
- * @{
- */
-#define RADIO_SX172X_SPI 2 /**< SPI peripheral */
-/** @} */
-
-/** @defgroup radio_sx172x_gpio GPIO used to control the SX172x
- * @{
- */
-#define RADIO_SX172X_GPIO_NRESET PB7 /**< reset input (active low) */
-/** @} */
-
-bool radio_sx172x_setup(void)
-{
- // setup SPI
- rcc_periph_clock_enable(RCC_SPI_SCK_PORT(RADIO_SX172X_SPI)); // enable clock for GPIO peripheral for clock signal
- gpio_set_mode(SPI_SCK_PORT(RADIO_SX172X_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(RADIO_SX172X_SPI)); // set SCK as output (clock speed will be negotiated later)
- rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(RADIO_SX172X_SPI)); // enable clock for GPIO peripheral for MOSI signal
- gpio_set_mode(SPI_MOSI_PORT(RADIO_SX172X_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(RADIO_SX172X_SPI)); // set MOSI as output
- rcc_periph_clock_enable(RCC_SPI_MISO_PORT(RADIO_SX172X_SPI)); // enable clock for GPIO peripheral for MISO signal
- gpio_set_mode(SPI_MISO_PORT(RADIO_SX172X_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SPI_MISO_PIN(RADIO_SX172X_SPI)); // set MISO as input
- rcc_periph_clock_enable(RCC_SPI_NSS_PORT(RADIO_SX172X_SPI)); // enable clock for GPIO peripheral for NSS (CS) signal
- gpio_set_mode(SPI_NSS_PORT(RADIO_SX172X_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, SPI_NSS_PIN(RADIO_SX172X_SPI)); // set NSS (CS) as output
- rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
- rcc_periph_clock_enable(RCC_SPI(RADIO_SX172X_SPI)); // enable clock for SPI peripheral
- spi_reset(SPI(RADIO_SX172X_SPI)); // clear SPI values to default
- spi_init_master(SPI(RADIO_SX172X_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); // initialise SPI as master, divide clock by 8 (72E6/8 < 10 MHz, max SX172X SCK is 10 MHz, maximum SPI PCLK clock is 72 MHz, depending on which SPI is used), set clock polarity to idle low (not that important), set clock phase to do bit change on falling edge (polarity depends on clock phase), use 8-bit frames , use MSb first
- spi_set_full_duplex_mode(SPI(RADIO_SX172X_SPI)); // ensure we are in full duplex mode
- spi_enable_software_slave_management(SPI(RADIO_SX172X_SPI)); // control NSS (CS) manually
- spi_set_nss_high(SPI(RADIO_SX172X_SPI)); // set NSS high (internally) so we can output
- spi_disable_ss_output(SPI(RADIO_SX172X_SPI)); // disable NSS output since we control CS manually
- gpio_set(SPI_NSS_PORT(RADIO_SX172X_SPI), SPI_NSS_PIN(RADIO_SX172X_SPI)); // set CS high to unselect device
- spi_enable(SPI(RADIO_SX172X_SPI)); // enable SPI
- // use NRESET pin to read ensure it started
- rcc_periph_clock_enable(GPIO_RCC(RADIO_SX172X_GPIO_NRESET)); // enable clock for GPIO port
- gpio_set_mode(GPIO_PORT(RADIO_SX172X_GPIO_NRESET), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(RADIO_SX172X_GPIO_NRESET)); // set GPIO as input
- sleep_ms(10); // wait for POR sequence to complete
- return (0 != gpio_get(GPIO_PORT(RADIO_SX172X_GPIO_NRESET), GPIO_PIN(RADIO_SX172X_GPIO_NRESET))); // ensure the module has started
-}
-
-void radio_sx172x_release(void)
-{
- spi_disable(SPI(RADIO_SX172X_SPI));
- rcc_periph_clock_disable(RCC_SPI(RADIO_SX172X_SPI));
- gpio_set_mode(SPI_NSS_PORT(RADIO_SX172X_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_NSS_PIN(RADIO_SX172X_SPI));
- gpio_set_mode(SPI_MISO_PORT(RADIO_SX172X_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_MISO_PIN(RADIO_SX172X_SPI));
- gpio_set_mode(SPI_MOSI_PORT(RADIO_SX172X_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_MOSI_PIN(RADIO_SX172X_SPI));
- gpio_set_mode(SPI_SCK_PORT(RADIO_SX172X_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_SCK_PIN(RADIO_SX172X_SPI));
-}
-
-bool radio_sx172x_reset(void)
-{
- gpio_clear(GPIO_PORT(RADIO_SX172X_GPIO_NRESET), GPIO_PIN(RADIO_SX172X_GPIO_NRESET)); // set low to reset device
- gpio_set_mode(GPIO_PORT(RADIO_SX172X_GPIO_NRESET), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(RADIO_SX172X_GPIO_NRESET)); // set GPIO as output
- sleep_us(200); // set low for at least 100 us (see datasheet section 7.2.2)
- gpio_set_mode(GPIO_PORT(RADIO_SX172X_GPIO_NRESET), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(RADIO_SX172X_GPIO_NRESET)); // set GPIO as input
- sleep_ms(6); // wait for at least 5 ms for reset to complete (see datasheet section 7.2.2)
- return (0 != gpio_get(GPIO_PORT(RADIO_SX172X_GPIO_NRESET), GPIO_PIN(RADIO_SX172X_GPIO_NRESET))); // ensure the module has started
-}
-
-uint8_t radio_sx172x_read_register(enum radio_sx172x_register_t name)
-{
- gpio_clear(SPI_NSS_PORT(RADIO_SX172X_SPI), SPI_NSS_PIN(RADIO_SX172X_SPI)); // set CS low to select device
- (void)SPI_DR(SPI(RADIO_SX172X_SPI)); // clear RXNE flag (by reading previously received data)
- spi_send(SPI(RADIO_SX172X_SPI), name & 0x7f); // send register address (with 7th bit at 0 to read) and any data
- spi_read(SPI(RADIO_SX172X_SPI)); // wait for data to be transferred, but discard the received data (clears RXNE go get the next data correctly)
- spi_send(SPI(RADIO_SX172X_SPI), 0); // write any data so we can read back data
- const uint8_t value = spi_read(SPI(RADIO_SX172X_SPI)); // read data
- while ((SPI_SR(SPI(RADIO_SX172X_SPI)) & SPI_SR_BSY)); // wait for SPI to not be busy (communication completed)
- gpio_set(SPI_NSS_PORT(RADIO_SX172X_SPI), SPI_NSS_PIN(RADIO_SX172X_SPI)); // set CS high to unselect device
- return value;
-}
-
-void radio_sx172x_write_register(enum radio_sx172x_register_t name, uint8_t value)
-{
- gpio_clear(SPI_NSS_PORT(RADIO_SX172X_SPI), SPI_NSS_PIN(RADIO_SX172X_SPI)); // set CS low to select device
- spi_send(SPI(RADIO_SX172X_SPI), name | 0x80); // send register address (with 7th bit at 1 to write) and value
- spi_send(SPI(RADIO_SX172X_SPI), value); // write value
- while ((SPI_SR(SPI(RADIO_SX172X_SPI)) & SPI_SR_BSY)); // wait for SPI to not be busy (communication completed)
- gpio_set(SPI_NSS_PORT(RADIO_SX172X_SPI), SPI_NSS_PIN(RADIO_SX172X_SPI)); // set CS high to unselect device
-}
-
-void radio_sx172x_read_fifo(uint8_t addr, uint8_t* data, uint8_t length)
-{
- if (NULL == data || 0 == length || addr + length > 256) { // sanity check
- return;
- }
- const uint8_t mode = radio_sx172x_read_register(RADIO_SX172X_REG_OP_MODE); // read in which mode we are
- if (0 == (mode & 0x7)) { // we are in sleep mode
- radio_sx172x_write_register(RADIO_SX172X_REG_OP_MODE, (mode & 0xf8) | 1); // go to standby mode so we can access the FIFO registers
- }
- radio_sx172x_write_register(RADIO_SX172X_REG_LORA_FIFO_ADDR_PTR, addr); // set address to be read
- gpio_clear(SPI_NSS_PORT(RADIO_SX172X_SPI), SPI_NSS_PIN(RADIO_SX172X_SPI)); // set CS low to select device
- (void)SPI_DR(SPI(RADIO_SX172X_SPI)); // clear RXNE flag (by reading previously received data)
- spi_send(SPI(RADIO_SX172X_SPI), RADIO_SX172X_REG_FIFO & 0x7f); // select FIFO register (with 7th bit at 0 to read)
- spi_read(SPI(RADIO_SX172X_SPI)); // wait for data to be transferred, but discard the received data (clears RXNE go get the next data correctly)
- for (uint8_t i = 0; i < length; i++) {
- spi_send(SPI(RADIO_SX172X_SPI), 0); // write any data so we can read back data
- data[i] = spi_read(SPI(RADIO_SX172X_SPI)); // read data
- }
- while ((SPI_SR(SPI(RADIO_SX172X_SPI)) & SPI_SR_BSY)); // wait for SPI to not be busy (communication completed)
- gpio_set(SPI_NSS_PORT(RADIO_SX172X_SPI), SPI_NSS_PIN(RADIO_SX172X_SPI)); // set CS high to unselect device
-}
-
-void radio_sx172x_write_fifo(uint8_t addr, const uint8_t* data, uint8_t length)
-{
- if (NULL == data || 0 == length || addr + length > 256) { // sanity check
- return;
- }
- const uint8_t mode = radio_sx172x_read_register(RADIO_SX172X_REG_OP_MODE); // read in which mode we are
- if (0 == (mode & 0x7)) { // we are in sleep mode
- radio_sx172x_write_register(RADIO_SX172X_REG_OP_MODE, (mode & 0xf8) | 1); // go to standby mode so we can access the FIFO registers
- }
- radio_sx172x_write_register(RADIO_SX172X_REG_LORA_FIFO_ADDR_PTR, addr); // set address to be read
- gpio_clear(SPI_NSS_PORT(RADIO_SX172X_SPI), SPI_NSS_PIN(RADIO_SX172X_SPI)); // set CS low to select device
- spi_send(SPI(RADIO_SX172X_SPI), RADIO_SX172X_REG_FIFO | 0x80); // select FIFO register (with 7th bit at 1 to write)
- for (uint8_t i = 0; i < length; i++) {
- spi_send(SPI(RADIO_SX172X_SPI), data[i]); // write data
- }
- while ((SPI_SR(SPI(RADIO_SX172X_SPI)) & SPI_SR_BSY)); // wait for SPI to not be busy (communication completed)
- gpio_set(SPI_NSS_PORT(RADIO_SX172X_SPI), SPI_NSS_PIN(RADIO_SX172X_SPI)); // set CS high to unselect device
-}
diff --git a/lib/radio_sx172x.h b/lib/radio_sx172x.h
deleted file mode 100644
index 7d8f248..0000000
--- a/lib/radio_sx172x.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/** library to communication with Semtech SX172x LoRa radio module using SPI
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2020
- * @note peripherals used: SPI @ref radio_sx172x_spi, GPIO @ref radio_sx172x_gpio
- * @note the interrupts and corresponding DIO should be handled directly by the user
- */
-#pragma once
-#error not converted for STM32F4
-
-/** register addresses */
-enum radio_sx172x_register_t {
- RADIO_SX172X_REG_FIFO = 0x00,
- RADIO_SX172X_REG_OP_MODE = 0x01,
- RADIO_SX172X_REG_FSKOOK_BITRATE_MSB = 0x02,
- RADIO_SX172X_REG_FSKOOK_BITRATE_LSB = 0x03,
- RADIO_SX172X_REG_FSKOOK_FDEV_MSB = 0x04,
- RADIO_SX172X_REG_FSKOOK_FDEV_LSB = 0x05,
- RADIO_SX172X_REG_FRF_MSB = 0x06,
- RADIO_SX172X_REG_FRF_MID = 0x07,
- RADIO_SX172X_REG_FRF_LSB = 0x08,
- RADIO_SX172X_REG_PA_CONFIG = 0x09,
- RADIO_SX172X_REG_PA_RAMP = 0x0A,
- RADIO_SX172X_REG_OCP = 0x0B,
- RADIO_SX172X_REG_LNA = 0x0C,
- RADIO_SX172X_REG_FSKOOB_RX_CONFIG = 0x0D,
- RADIO_SX172X_REG_LORA_FIFO_ADDR_PTR = 0x0D,
- RADIO_SX172X_REG_FSKOOB_RSSI_CONFIG = 0x0E,
- RADIO_SX172X_REG_LORA_FIFO_TX_BASE_ADDR = 0x0E,
- RADIO_SX172X_REG_FSKOOB_RSSI_COLLISION = 0x0F,
- RADIO_SX172X_REG_LORA_FIFO_RX_BASE_ADDR = 0x0F,
- RADIO_SX172X_REG_FSKOOB_RSSI_THRESH = 0x10,
- RADIO_SX172X_REG_LORA_FIFO_RX_CURRENT_ADDR = 0x10,
- RADIO_SX172X_REG_FSKOOK_RSSI_VALUE = 0x11,
- RADIO_SX172X_REG_LORA_IRQ_FLAGS_MASK = 0x11,
- RADIO_SX172X_REG_FSKOOK_RX_BW = 0x12,
- RADIO_SX172X_REG_LORA_IRQ_FLAGS = 0x12,
- RADIO_SX172X_REG_FSKOOK_AFC_BW = 0x13,
- RADIO_SX172X_REG_LORA_RX_NB_BYTES = 0x13,
- RADIO_SX172X_REG_FSKOOK_OOK_PEAK = 0x14,
- RADIO_SX172X_REG_LORA_RX_HEADER_CNT_VALUE_MSB = 0x14,
- RADIO_SX172X_REG_FSKOOK_OOK_FIX = 0x15,
- RADIO_SX172X_REG_LORA_RX_HEADER_CNT_VALUE_LSB = 0x15,
- RADIO_SX172X_REG_FSKOOK_OOK_AVG = 0x16,
- RADIO_SX172X_REG_LORA_RX_PACKET_CNT_VALUE_MSB = 0x16,
- RADIO_SX172X_REG_LORA_RX_PACKET_CNT_VALUE_LSB = 0x17,
- RADIO_SX172X_REG_LORA_MODEM_STAT = 0x18,
- RADIO_SX172X_REG_LORA_PKT_SNR_VALUE = 0x19,
- RADIO_SX172X_REG_FSKOOK_AFC_FEI = 0x1A,
- RADIO_SX172X_REG_LORA_PKT_RSSI_VALUE = 0x1A,
- RADIO_SX172X_REG_FSKOOK_AFC_MSB = 0x1B,
- RADIO_SX172X_REG_LORA_RSSI_VALUE = 0x1B,
- RADIO_SX172X_REG_FSKOOK_AFC_LSB = 0x1C,
- RADIO_SX172X_REG_LORA_HOP_CHANNEL = 0x1C,
- RADIO_SX172X_REG_FSKOOK_FEI_MSB = 0x1D,
- RADIO_SX172X_REG_LORA_MODEM_CONFIG_1 = 0x1D,
- RADIO_SX172X_REG_FSKOOK_FEI_LSB = 0x1E,
- RADIO_SX172X_REG_LORA_MODEM_CONFIG_2 = 0x1E,
- RADIO_SX172X_REG_FSKOOK_PREAMBLE_DETECT = 0x1F,
- RADIO_SX172X_REG_LORA_SYMB_TIMEOUT_LSB = 0x1F,
- RADIO_SX172X_REG_FSKOOK_RX_TIMEOUT_1 = 0x20,
- RADIO_SX172X_REG_LORA_PREAMBLE_MSB = 0x20,
- RADIO_SX172X_REG_FSKOOK_RX_TIMEOUT_2 = 0x21,
- RADIO_SX172X_REG_LORA_PREAMBLE_LSB = 0x21,
- RADIO_SX172X_REG_FSKOOK_RX_TIMEOUT_3 = 0x22,
- RADIO_SX172X_REG_LORA_PAYLOAD_LENGTH = 0x22,
- RADIO_SX172X_REG_FSKOOK_RX_DELAY = 0x23,
- RADIO_SX172X_REG_LORA_MAX_PAYLOD_LENGTH = 0x23,
- RADIO_SX172X_REG_FSKOOK_OSC = 0x24,
- RADIO_SX172X_REG_LORA_HOP_PERIOD = 0x24,
- RADIO_SX172X_REG_FSKOOK_PREAMBLE_MSB = 0x25,
- RADIO_SX172X_REG_LORA_FIFO_RX_BYTE_ADDR = 0x25,
- RADIO_SX172X_REG_FSKOOK_PREAMBLE_LSB = 0x26,
- RADIO_SX172X_REG_LORA_MODEM_CONFIG_3 = 0x26,
- RADIO_SX172X_REG_FSKOOK_SYNC_CONFIG = 0x27,
- RADIO_SX172X_REG_FSKOOK_SYNC_VALUE_1 = 0x28,
- RADIO_SX172X_REG_LORA_FEI_MSB = 0x28,
- RADIO_SX172X_REG_FSKOOK_SYNC_VALUE_2 = 0x29,
- RADIO_SX172X_REG_LORA_FEI_MID = 0x29,
- RADIO_SX172X_REG_FSKOOK_SYNC_VALUE_3 = 0x2A,
- RADIO_SX172X_REG_LORA_FEI_LSB = 0x2A,
- RADIO_SX172X_REG_FSKOOK_SYNC_VALUE_4 = 0x2B,
- RADIO_SX172X_REG_FSKOOK_SYNC_VALUE_5 = 0x2C,
- RADIO_SX172X_REG_LORA_RSSI_WIDEBAND = 0x2C,
- RADIO_SX172X_REG_FSKOOK_SYNC_VALUE_6 = 0x2D,
- RADIO_SX172X_REG_FSKOOK_SYNC_VALUE_7 = 0x2E,
- RADIO_SX172X_REG_FSKOOK_SYNC_VALUE_8 = 0x2F,
- RADIO_SX172X_REG_LORA_IF_FREQ_1 = 0x2F,
- RADIO_SX172X_REG_FSKOOK_PACKET_CONFIG_1 = 0x30,
- RADIO_SX172X_REG_LORA_IF_FREQ_2 = 0x30,
- RADIO_SX172X_REG_FSKOOK_PACKET_CONFIG_2 = 0x31,
- RADIO_SX172X_REG_LORA_DETECT_OPTIMIZE = 0x31,
- RADIO_SX172X_REG_FSKOOK_PAYLOAD_LENGTH = 0x32,
- RADIO_SX172X_REG_FSKOOK_NODE_ADRS = 0x33,
- RADIO_SX172X_REG_LORA_INVERT_IQ = 0x33,
- RADIO_SX172X_REG_FSKOOK_BROADCAST_ADRS = 0x34,
- RADIO_SX172X_REG_FSKOOK_FIFO_THRESH = 0x35,
- RADIO_SX172X_REG_FSKOOK_SEQ_CONFIG_1 = 0x36,
- RADIO_SX172X_REG_LORA_HIGH_BW_OPTIMIZE_1 = 0x36,
- RADIO_SX172X_REG_FSKOOK_SEQ_CONFIG_2 = 0x37,
- RADIO_SX172X_REG_LORA_DETECTION_THRESHOLD = 0x37,
- RADIO_SX172X_REG_FSKOOK_TIMER_RESOLV = 0x38,
- RADIO_SX172X_REG_FSKOOK_TIMER_1_COEF = 0x39,
- RADIO_SX172X_REG_LORA_SYNC_WORD = 0x39,
- RADIO_SX172X_REG_FSKOOK_TIMER_2_COEF = 0x3A,
- RADIO_SX172X_REG_LORA_HIGH_BW_OPTIMIZE_2 = 0x3A,
- RADIO_SX172X_REG_FSKOOK_IMAGE_CAL = 0x3B,
- RADIO_SX172X_REG_LORA_INVERT_IQ_2 = 0x3B,
- RADIO_SX172X_REG_FSKOOK_TEMP = 0x3C,
- RADIO_SX172X_REG_FSKOOK_LOW_BAT = 0x3D,
- RADIO_SX172X_REG_FSKOOK_IRQ_FLAGS_1 = 0x3E,
- RADIO_SX172X_REG_FSKOOK_IRQ_FLAGS_2 = 0x3F,
- RADIO_SX172X_REG_DIO_MAPPING_1 = 0x40,
- RADIO_SX172X_REG_DIO_MAPPING_2 = 0x41,
- RADIO_SX172X_REG_VERSION = 0x42,
- RADIO_SX172X_REG_FSKOOK_PLL_HOP = 0x44,
- RADIO_SX172X_REG_TCX0 = 0x4B,
- RADIO_SX172X_REG_PA_DAC = 0x4D,
- RADIO_SX172X_REG_FORMER_TEMP = 0x5B,
- RADIO_SX172X_REG_FSKOOK_BIT_RATE_FRAC = 0x5D,
- RADIO_SX172X_REG_AGC_REF = 0x61,
- RADIO_SX172X_REG_AGC_THRESH_1 = 0x62,
- RADIO_SX172X_REG_AGC_THRESH_2 = 0x63,
- RADIO_SX172X_REG_AGC_THRESH_3 = 0x64,
- RADIO_SX172X_REG_PLL = 0x70,
-};
-
-/** setup communication to SX172x
- * @return if SX172x is ready
- */
-bool radio_sx172x_setup(void);
-/** release resources and peripherals used by communication */
-void radio_sx172x_release(void);
-/** reset SX172x chip
- * @return if SX172x is ready
- */
-bool radio_sx172x_reset(void);
-/** read register from SX172x
- * @param[in] name register name to read
- * @return register value read
- */
-uint8_t radio_sx172x_read_register(enum radio_sx172x_register_t name);
-/** write register to SX172x
- * @param[in] name register name to write
- * @param[in} value register value to write
- */
-void radio_sx172x_write_register(enum radio_sx172x_register_t name, uint8_t value);
-/** read FIFO data
- * @param[in] addr address of the data to be read in the FIFO buffer
- * @param[out] data buffer to store read data
- * @param[in] length number of byte to read
- * @warning puts device in standby mode when in sleep mode
- */
-void radio_sx172x_read_fifo(uint8_t addr, uint8_t* data, uint8_t length);
-/** write FIFO data
- * @param[in] addr address of the data to be written in the FIFO buffer
- * @param[out] data data to be written in FIFO buffer
- * @param[in] length number of byte to written
- * @warning puts device in standby mode when in sleep mode
- */
-void radio_sx172x_write_fifo(uint8_t addr, const uint8_t* data, uint8_t length);
diff --git a/lib/rtc_dcf77.c b/lib/rtc_dcf77.c
deleted file mode 100644
index 29ecbb9..0000000
--- a/lib/rtc_dcf77.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/** library to get time from a DCF77 module
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: GPIO @ref rtc_dcf77_gpio, timer @ref rtc_dcf77_timer
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/spi.h> // SPI library
-#include <libopencm3/stm32/timer.h> // timer library
-
-#include "rtc_dcf77.h" // RTC DCF77 library API
-#include "global.h" // common methods
-
-/** @defgroup rtc_dcf77_gpio output to enable DCF module and input to capture DCF signal
- * @{
- */
-#define RTC_DCF77_ENABLE_PIN PA2 /**< GPIO pinto enable the module */
-#define RTC_DCF77_SIGNAL_PIN PA3 /**< GPIO pin to capture the DCF signal */
-/** @} */
-
-/** @defgroup rtc_dcf77_timer timer to sample DCF77 signal
- * @{
- */
-#define RTC_DCF77_TIMER 4 /**< timer peripheral */
-/** @} */
-
-volatile bool rtc_dcf77_time_flag = false;
-struct rtc_dcf77_time_t rtc_dcf77_time = {
- .valid = false,
- .milliseconds = 0,
- .seconds = 0,
- .minutes = 0,
- .hours = 0,
- .day = 0,
- .weekday = 0,
- .month = 0,
- .year = 0,
-};
-
-/** the received DCF77 frame bits */
-static volatile uint64_t rtc_dcf77_frame = 0;
-/** values of the DCF77 signal over 10 ms for 1 s (how many times it is high) */
-static uint8_t rtc_dcf77_bins[100] = {0};
-/** the bin shift for the bit phase */
-static uint8_t rtc_dcf77_phase = 0;
-/** the maximum phase value */
-static int16_t rtc_dcf77_phase_max = INT16_MIN;
-/** if the current phase has been verified */
-static bool rtc_dcf77_phase_locked = false;
-/** number of invalid decoding */
-static uint8_t rtc_dcf77_invalid = 0;
-/** maximum number of invalid decoding before switching off */
-#define RTC_DCF77_INVALID_MAX 5
-
-void rtc_dcf77_setup(void)
-{
- // setup enable output
- rcc_periph_clock_enable(GPIO_RCC(RTC_DCF77_ENABLE_PIN)); // enable clock GPIO peripheral
- gpio_set_mode(GPIO_PORT(RTC_DCF77_ENABLE_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(RTC_DCF77_ENABLE_PIN)); // set pin to output push-pull to be able to enable the module
- rtc_dcf77_off(); // disable module at start
-
- // setup signal input
- rcc_periph_clock_enable(GPIO_RCC(RTC_DCF77_SIGNAL_PIN)); // enable clock for signal input peripheral
- gpio_set_mode(GPIO_PORT(RTC_DCF77_SIGNAL_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(RTC_DCF77_SIGNAL_PIN)); // set signal pin to input
-
- // setup timer to sample signal at 1kHz
- rcc_periph_clock_enable(RCC_TIM(RTC_DCF77_TIMER)); // enable clock for timer peripheral
- rcc_periph_reset_pulse(RST_TIM(RTC_DCF77_TIMER)); // reset timer state
- timer_set_mode(TIM(RTC_DCF77_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(RTC_DCF77_TIMER), 1); // set prescaler to divide frequency by two, to be able to have a period of 1 kHz (72MHz/2/2^16=549Hz<1kHz)
- timer_set_period(TIM(RTC_DCF77_TIMER), rcc_ahb_frequency / 2 / 1000 - 1); // set period to 1kHz (plus hand tuning)
- timer_clear_flag(TIM(RTC_DCF77_TIMER), TIM_SR_UIF); // clear update event flag
- timer_update_on_overflow(TIM(RTC_DCF77_TIMER)); // only use counter overflow as UEV source
- timer_enable_irq(TIM(RTC_DCF77_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
- nvic_enable_irq(NVIC_TIM_IRQ(RTC_DCF77_TIMER)); // catch interrupt in service routine
-}
-
-void rtc_dcf77_on(void)
-{
- if (!gpio_get(GPIO_PORT(RTC_DCF77_ENABLE_PIN), GPIO_PIN(RTC_DCF77_ENABLE_PIN))) { // receiver is already turned on
- return; // do nothing
- }
- rtc_dcf77_frame = 0; // reset frame
- rtc_dcf77_phase_locked = false; // reset phase lock
- rtc_dcf77_phase_max = INT16_MIN; // restart searching for phase
- rtc_dcf77_invalid = 0; // reset invalid count
- gpio_clear(GPIO_PORT(RTC_DCF77_ENABLE_PIN), GPIO_PIN(RTC_DCF77_ENABLE_PIN)); // enable module by pulling pin low
- timer_set_counter(TIM(RTC_DCF77_TIMER), 0); // reset timer counter
- timer_enable_counter(TIM(RTC_DCF77_TIMER)); // start timer to sample signal
-}
-
-void rtc_dcf77_off(void)
-{
- gpio_set(GPIO_PORT(RTC_DCF77_ENABLE_PIN), GPIO_PIN(RTC_DCF77_ENABLE_PIN)); // disable module by pull pin high
- timer_disable_counter(TIM(RTC_DCF77_TIMER)); // stop timer since we don't need to sample anymore
-}
-
-/** decode rtc_dcf77_frame DCF77 frame into rtc_dcf77_time DCF77 time
- * @note check valid for validity
- */
-static void rtc_dcf77_decode(void)
-{
- rtc_dcf77_time.valid = false; // reset validity
-
- if (rtc_dcf77_frame == 0) { // no time received yet
- return;
- }
- if (!(rtc_dcf77_frame & (1ULL << 20))) { // start of encoded time should always be 1
- return;
- }
-
- // check minute parity
- uint8_t parity = 0; // to check parity
- for (uint8_t bit = 21; bit <= 28; bit++) {
- if (rtc_dcf77_frame & (1ULL << bit)) {
- parity++; // count the set bits
- }
- }
- if (parity%2) { // parity should be even
- return;
- }
- rtc_dcf77_time.minutes = 1 * ((rtc_dcf77_frame >> 21) & (0x1)) + 2 * ((rtc_dcf77_frame >> 22) & (0x1)) + 4 * ((rtc_dcf77_frame >> 23) & (0x1)) + 8 * ((rtc_dcf77_frame >> 24) & (0x1)) + 10 * ((rtc_dcf77_frame >> 25) & (0x1)) + 20 * ((rtc_dcf77_frame >> 26) & (0x1)) + 40 * ((rtc_dcf77_frame >> 27) & (0x1)); // read minute (00-59)
- if (rtc_dcf77_time.minutes > 59) { // minutes should not be more than 59
- return;
- }
-
- // check hour parity
- parity = 0;
- for (uint8_t bit = 29; bit <= 35; bit++) {
- if (rtc_dcf77_frame & (1ULL << bit)) {
- parity++; // count the set bits
- }
- }
- if (parity % 2) { // parity should be even
- return;
- }
- rtc_dcf77_time.hours = 1 * ((rtc_dcf77_frame >> 29) & (0x1)) + 2 * ((rtc_dcf77_frame >> 30) & (0x1)) + 4 * ((rtc_dcf77_frame >> 31) & (0x1)) + 8 * ((rtc_dcf77_frame >> 32) & (0x1)) + 10 * ((rtc_dcf77_frame >> 33) & (0x1)) + 20 * ((rtc_dcf77_frame >> 34) & (0x1)); // read hour (00-23)
- if (rtc_dcf77_time.hours > 23) { // hours should not be more than 23
- return;
- }
-
- // check date parity
- parity = 0;
- for (uint8_t bit = 36; bit <= 58; bit++) {
- if (rtc_dcf77_frame & (1ULL << bit)) {
- parity++; // count the set bits
- }
- }
- if (parity % 2) { // parity should be even
- return;
- }
- rtc_dcf77_time.day = 1 * ((rtc_dcf77_frame >> 36) & (0x1)) + 2 * ((rtc_dcf77_frame >> 37) & (0x1)) + 4 * ((rtc_dcf77_frame >> 38) & (0x1)) + 8 * ((rtc_dcf77_frame >> 39) & (0x1)) + 10 * ((rtc_dcf77_frame >> 40) & (0x1)) + 20 * ((rtc_dcf77_frame >> 41) & (0x1)); // read day of the month (01-31)
- if (rtc_dcf77_time.day == 0 || rtc_dcf77_time.day > 31) { // day of the month should be 1-31
- return;
- }
- rtc_dcf77_time.weekday = 1 * ((rtc_dcf77_frame >> 42) & (0x1)) + 2*((rtc_dcf77_frame >> 43) & (0x1)) + 4 * ((rtc_dcf77_frame >> 44) & (0x1)); // read day of the week (1=Monday - 7=Sunday)
- if (rtc_dcf77_time.weekday == 0 || rtc_dcf77_time.weekday > 7) { // day of the week should be 1-7
- return;
- }
- rtc_dcf77_time.month = 1 * ((rtc_dcf77_frame >> 45) & (0x1)) + 2 * ((rtc_dcf77_frame >> 46) & (0x1)) + 4 * ((rtc_dcf77_frame >> 47) & (0x1)) + 8*((rtc_dcf77_frame >> 48) & (0x1)) + 10 * ((rtc_dcf77_frame >> 49) & (0x1)); // read month of the year (01-12)
- if (rtc_dcf77_time.month == 0 || rtc_dcf77_time.month > 12) { // month of the year should be 1-12
- return;
- }
- rtc_dcf77_time.year = 1 * ((rtc_dcf77_frame >> 50) & (0x1)) + 2 * ((rtc_dcf77_frame >> 51) & (0x1)) + 4 * ((rtc_dcf77_frame >> 52) & (0x1)) + 8 * ((rtc_dcf77_frame >> 53) & (0x1)) + 10 * ((rtc_dcf77_frame >> 54) & (0x1)) + 20 * ((rtc_dcf77_frame >> 55) & (0x1)) + 40 * ((rtc_dcf77_frame >> 56) & (0x1)) + 80 * ((rtc_dcf77_frame >> 57) & (0x1)); // read year of the century (00-99)
- if (rtc_dcf77_time.year > 99) { // year should be <100
- return;
- }
-
- rtc_dcf77_time.valid = true; // if we managed it until here the decoding is successful
-}
-
-/** find phase of 1 seconds DCF77 signal in the bins
- * searches the complete second for the highest correlation if the phase it not locked
- * searches only around the last phase if locked
- * saves the new phase with the highest correlation
- */
-static void rtc_dcf77_phase_detector(void) {
- uint8_t integral_i = 0; // which bin has the highest integral/correlation
- int16_t integral_max = 0; // maximum integral value found
-
- for (uint8_t start = 0; start < (rtc_dcf77_phase_locked ? 10 : LENGTH(rtc_dcf77_bins)); start++) { // which bin has been used to start the convolution (only use +/- 15 bits of previous phase if locked)
- int16_t integral = 0; // value of the integral
- for (uint8_t bin = 0; bin < LENGTH(rtc_dcf77_bins); bin++) { // go through bins to calculate correlation
- int8_t dfc77_signal = -1; // the signal of the reference DCF77 signal
- if (bin < 10) { // the signal is always high for the first 100 ms
- dfc77_signal = 1; // use highest values
- } else if (bin < 20) { // the signal has 50% chance of being high for the next 100 ms (encoding the bit)
- dfc77_signal = 0; // use middle value
- }
- // the rest of the time the signal is low (keep lowest value)
- integral += rtc_dcf77_bins[(start + bin + rtc_dcf77_phase + LENGTH(rtc_dcf77_bins) - 5) % LENGTH(rtc_dcf77_bins)] * dfc77_signal; // calculate the correlation at this point and integrate it (start with previous phase - 15 bins)
- }
- if (integral>integral_max) { // we found a better correlation result
- integral_max = integral; // save new best result
- integral_i = (start + rtc_dcf77_phase + LENGTH(rtc_dcf77_bins) - 5) % LENGTH(rtc_dcf77_bins); // start new best phase start
- }
- }
-
- if ((int16_t)(integral_max + 40) > rtc_dcf77_phase_max) { // only save new phase if it is better than the last one, with some margin to compensate for the drift (perfect correlation = 100, worst correlation = -800)
- rtc_dcf77_phase_max = integral_max; // save best phase value
- rtc_dcf77_phase = integral_i; // save bin index corresponding to start of the phase
- }
-}
-
-/** interrupt service routine called for timer */
-void TIM_ISR(RTC_DCF77_TIMER)(void)
-{
- static uint8_t bin_state = 0; // how many samples have been stored in the bin
- static uint8_t bin_i = 0; // current bin filled
- static uint8_t bit_i = 0; // current bit in the DCF77 minute frame
- if (timer_get_flag(TIM(RTC_DCF77_TIMER), TIM_SR_UIF)) { // overflow update event happened
- timer_clear_flag(TIM(RTC_DCF77_TIMER), TIM_SR_UIF); // clear flag
- // fill bin with current sample state
- if (gpio_get(GPIO_PORT(RTC_DCF77_SIGNAL_PIN), GPIO_PIN(RTC_DCF77_SIGNAL_PIN))) {
- rtc_dcf77_bins[bin_i]++; // only need to increase if the signal is high
- }
- bin_state++; // remember we filled the bin
-
- if (bin_state>=10) { // bin has 10x1 ms samples, it is now full
- bin_i = (bin_i + 1) % LENGTH(rtc_dcf77_bins); // go to next bin
- rtc_dcf77_bins[bin_i] = 0; // restart bin
- bin_state = 0; // restart collecting
- }
-
- if (0 == bin_i && 0 == bin_state) { // we have 1 s of samples
- if (bit_i < 59) {
- rtc_dcf77_phase_detector(); // detect phase in signal
- // check modulation of first 100 ms
- uint16_t modulation = 0;
- for (uint8_t bin = 0; bin < 10; bin++) {
- modulation += rtc_dcf77_bins[(rtc_dcf77_phase + bin) % LENGTH(rtc_dcf77_bins)];
- }
- if (modulation < 50) { // signal is not modulated, it might be the 60th pause bit
- bit_i = 0; // restart frame
- rtc_dcf77_frame = 0; // restart frame
- rtc_dcf77_phase_max = INT16_MIN; // restart searching for phase
- rtc_dcf77_phase_locked = false; // unlock phase since the decoding seems wrong
- } else { // modulation detected
- // check modulation of next 100 ms
- modulation = 0;
- for (uint8_t bin = 10; bin < 20; bin++) {
- modulation += rtc_dcf77_bins[(rtc_dcf77_phase + bin) % LENGTH(rtc_dcf77_bins)];
- }
- if (modulation < 50) { // it's a 0
- // bit is already cleared
- } else { // it's a 1
- rtc_dcf77_frame |= (1ULL << bit_i); // set bit
- }
- bit_i++; // go to next bit
- }
- } else { // complete DCF77 frame received
- rtc_dcf77_decode(); // decode frame
- if (rtc_dcf77_time.valid) { // decoded time is valid
- rtc_dcf77_time.milliseconds = rtc_dcf77_phase * 10; // save milliseconds corresponding to phase
- rtc_dcf77_phase_locked = true; // lock phase since decoding succeeded
- rtc_dcf77_invalid = 0; // remember we had an valid decoding
- rtc_dcf77_time_flag = true; // notify user we have time
- } else {
- rtc_dcf77_invalid++; // remember we had an invalid decoding
- }
- if (rtc_dcf77_invalid >= RTC_DCF77_INVALID_MAX) { // too many invalid decoding
- rtc_dcf77_off(); // switch off receiver so it can re-tune
- }
- bit_i = 0; // restart frame
- rtc_dcf77_frame = 0; // restart frame
- }
- }
- } else { // no other interrupt should occur
- while (true); // unhandled exception: wait for the watchdog to bite
- }
-}
diff --git a/lib/rtc_dcf77.h b/lib/rtc_dcf77.h
deleted file mode 100644
index 224df1c..0000000
--- a/lib/rtc_dcf77.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/** library to get time from a DCF77 module
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: GPIO @ref rtc_dcf77_gpio, timer @ref rtc_dcf77_timer
- */
-#pragma once
-#error not converted for STM32F4
-
-/** set when time information has been received */
-extern volatile bool rtc_dcf77_time_flag;
-
-/** DCF77 time structure */
-struct rtc_dcf77_time_t {
- bool valid; /**< if the time is valid */
- uint8_t milliseconds; /**< milliseconds (00-99) */
- uint8_t seconds; /**< seconds (always 0) */
- uint8_t minutes; /**< minutes (00-49) */
- uint8_t hours; /**< hours (00-23) */
- uint8_t day; /**< day of the month (01-31) */
- uint8_t weekday; /**< day of the week (1-7=Monday-Sunday) */
- uint8_t month; /**< month (01-12) */
- uint8_t year; /**< year within century (00-99) */
-};
-
-/** decoded DCF77 time received */
-extern struct rtc_dcf77_time_t rtc_dcf77_time;
-
-/** setup DCF77 time receiver module */
-void rtc_dcf77_setup(void);
-/** switch on DCF77 time receiver module
- * @note it switches back off after too many invalid decoding attempts
- */
-void rtc_dcf77_on(void);
-/** switch off DCF77 time receiver module */
-void rtc_dcf77_off(void);
diff --git a/lib/rtc_ds1307.c b/lib/rtc_ds1307.c
deleted file mode 100644
index 97b3fcb..0000000
--- a/lib/rtc_ds1307.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/** library to communicate with the Maxim DS1307 I2C RTC IC (code)
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2017
- * @note peripherals used: I²C
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdio.h> // standard I/O facilities
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/i2c.h> // I2C library
-
-#include "global.h" // global utilities
-#include "rtc_ds1307.h" // RTC header and definitions
-#include "i2c_master.h" // i2c utilities
-
-#define RTC_DS1307_I2C_ADDR 0x68 /**< DS1307 I2C address (fixed to 0b1101000) */
-
-void rtc_ds1307_setup(void)
-{
- // configure I2C peripheral
- i2c_master_setup(false); // DS1307 only supports normal mode (up to 100 kHz)
-}
-
-bool rtc_ds1307_oscillator_disabled(void)
-{
- uint8_t data[1] = {0}; // to read data over I2C
- const uint8_t address[] = {0x00}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing CH value
- return false;
- }
- return data[0]&0x80; // return CH bit value to indicate if oscillator is disabled
-}
-
-uint16_t rtc_ds1307_read_square_wave(void)
-{
- uint16_t to_return = 0; // square wave frequency to return (in Hz)
- uint8_t data[1] = {0}; // to read data over I2C
- const uint16_t rtc_ds1307_rs[] = {1, 4096, 8192, 32768}; // RS1/RS0 values
- const uint8_t address[] = {0x07}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing control register
- return 0xffff; // error occurred
- }
- if (data[0]&0x10) { // verify if the square wave is enabled (SQWE)
- to_return = rtc_ds1307_rs[data[0]&0x03]; // read RS1/RS0 and get value
- } else {
- to_return = 0; // square wave output is disabled
- }
- return to_return;
-}
-
-uint8_t rtc_ds1307_read_seconds(void)
-{
- uint8_t to_return = 0; // seconds to return
- uint8_t data[1] = {0}; // to read data over I2C
- const uint8_t address[] = {0x00}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
- return 0xff;
- }
- to_return = ((data[0]&0x70)>>4)*10+(data[0]&0x0f); // convert BCD coding into seconds
- return to_return;
-}
-
-uint8_t rtc_ds1307_read_minutes(void)
-{
- uint8_t to_return = 0; // minutes to return
- uint8_t data[1] = {0}; // to read data over I2C
- const uint8_t address[] = {0x01}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
- return 0xff;
- }
- to_return = (data[0]>>4)*10+(data[0]&0x0f); // convert BCD coding into minutes
- return to_return;
-}
-
-uint8_t rtc_ds1307_read_hours(void)
-{
- uint8_t to_return = 0; // hours to return
- uint8_t data[1] = {0}; // to read data over I2C
- const uint8_t address[] = {0x02}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
- return 0xff;
- }
- if (data[0]&0x40) { // 12 hour mode
- if (data[0]&0x02) { // PM
- to_return += 12; // add the 12 hours
- }
- to_return += ((data[0]&0x10)>>4)*10; // convert BCD coding into hours (first digit)
- } else {
- to_return = ((data[0]&0x30)>>4)*10; // convert BCD coding into hours (first digit)
- }
- to_return += (data[0]&0x0f); // convert BCD coding into hours (second digit)
- return to_return;
-}
-
-uint8_t rtc_ds1307_read_day(void)
-{
- uint8_t to_return = 0; // day to return
- uint8_t data[1] = {0}; // to read data over I2C
- const uint8_t address[] = {0x03}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
- return 0xff;
- }
- to_return = (data[0]&0x07); // convert BCD coding into days
- return to_return;
-}
-
-uint8_t rtc_ds1307_read_date(void)
-{
- uint8_t to_return = 0; // date to return
- uint8_t data[1] = {0}; // to read data over I2C
- const uint8_t address[] = {0x04}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
- return 0xff;
- }
- to_return = ((data[0]&0x30)>>4)*10+(data[0]&0x0f); // convert BCD coding into date
- return to_return;
-}
-
-uint8_t rtc_ds1307_read_month(void)
-{
- uint8_t to_return = 0; // month to return
- uint8_t data[1] = {0}; // to read data over I2C
- const uint8_t address[] = {0x05}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
- return 0xff;
- }
- to_return = ((data[0]&0x10)>>4)*10+(data[0]&0x0f); // convert BCD coding into month
- return to_return;
-}
-
-uint8_t rtc_ds1307_read_year(void)
-{
- uint8_t data[1] = {0}; // to read data over I2C
- const uint8_t address[] = {0x06}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read a single byte containing value
- return 0xff;
- }
- uint8_t to_return = ((data[0]&0xf0)>>4)*10+(data[0]&0x0f); // convert BCD coding into year
- return to_return;
-}
-
-uint8_t* rtc_ds1307_read_time(void)
-{
- static uint8_t time[7] = {0}; // store time {seconds, minutes, hours, day, date, month, year}
- uint8_t data[7] = {0}; // to read data over I2C
- const uint8_t address[] = {0x00}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read all time bytes
- return NULL; // error occurred
- }
- time[0] = ((data[0]&0x70)>>4)*10+(data[0]&0x0f); // convert seconds from BCD
- time[1] = (data[1]>>4)*10+(data[1]&0x0f); // convert minutes from BCD
- time[2] = 0; // re-initialize hours
- if (data[2]&0x40) { // 12 hour mode
- if (data[2]&0x02) { // PM
- time[2] += 12; // add the 12 hours
- }
- time[2] += ((data[2]&0x10)>>4)*10; // convert BCD coding into hours (first digit)
- } else {
- time[2] = ((data[2]&0x30)>>4)*10; // convert BCD coding into hours (first digit)
- }
- time[2] += (data[2]&0x0f); // convert BCD coding into hours (second digit)
- time[3] = (data[3]&0x07); // convert BCD coding into days
- time[4] = ((data[4]&0x30)>>4)*10+(data[4]&0x0f); // convert BCD coding into date
- time[5] = ((data[5]&0x10)>>4)*10+(data[5]&0x0f); // convert BCD coding into month
- time[6] = ((data[6]&0xf0)>>4)*10+(data[6]&0x0f); // convert BCD coding into year
- return time;
-}
-
-bool rtc_ds1307_read_ram(uint8_t* data, uint8_t start, uint8_t length)
-{
- // sanity checks
- if (data==NULL || length==0) { // nothing to read
- return false;
- }
- if (start>55 || start+length>56) { // out of bounds RAM
- return false;
- }
-
- const uint8_t address[] = {0x08+start}; // memory address for data
- return i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // read RAM (starting at 0x08)
-}
-
-bool rtc_ds1307_oscillator_disable(void)
-{
- uint8_t data[1] = {0}; // to write CH value data over I2C
- const uint8_t address[] = {0x00}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read seconds with CH value
- return false;
- }
- data[0] |= 0x80; // set CH to disable oscillator
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write current seconds with CH value
-}
-
-bool rtc_ds1307_oscillator_enable(void)
-{
- uint8_t data[1] = {0}; // to write CH value data over I2C
- const uint8_t address[] = {0x00}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read seconds with CH value
- return false;
- }
- data[0] &= 0x7f; // clear CH to enable oscillator
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write current seconds with CH value
-}
-
-bool rtc_ds1307_write_square_wave(uint16_t frequency)
-{
- uint8_t data[1] = {0}; // to write control register value data over I2C
- switch (frequency) { // set RS1/RS0 based on frequency
- case 0:
- data[0] = 0;
- break;
- case 1:
- data[0] = 0|(1<<4);
- break;
- case 4096:
- data[0] = 1|(1<<4);
- break;
- case 8192:
- data[0] = 2|(1<<4);
- break;
- case 32768:
- data[0] = 3|(1<<4);
- break;
- default: // unspecified frequency
- return false;
- }
- const uint8_t address[] = {0x07}; // memory address for data
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write current seconds with CH value
-}
-
-bool rtc_ds1307_write_seconds(uint8_t seconds)
-{
- if (seconds>59) {
- return false;
- }
- uint8_t data[1] = {0}; // to read CH value data and write seconds value over I2C
- const uint8_t address[] = {0x00}; // memory address for data
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data))) { // read seconds with CH value
- return false;
- }
- data[0] &= 0x80; // only keep CH flag
- data[0] |= (((seconds/10)%6)<<4)+(seconds%10); // encode seconds in BCD format
-
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write current seconds with previous CH value
-}
-
-bool rtc_ds1307_write_minutes(uint8_t minutes)
-{
- if (minutes>59) {
- return false;
- }
- uint8_t data[1] = {0}; // to write time value
- data[0] = (((minutes/10)%6)<<4)+(minutes%10); // encode minutes in BCD format
-
- const uint8_t address[] = {0x01}; // memory address for data
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
-}
-
-bool rtc_ds1307_write_hours(uint8_t hours)
-{
- if (hours>24) {
- return false;
- }
- uint8_t data[1] = {0}; // to write time value
- data[0] = (((hours/10)%3)<<4)+(hours%10); // encode hours in BCD 24h format
-
- const uint8_t address[] = {0x02}; // memory address for data
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
-}
-
-bool rtc_ds1307_write_day(uint8_t day)
-{
- if (day<1 || day>7) {
- return false;
- }
- uint8_t data[1] = {0}; // to write time value
- data[0] = (day%8); // encode day in BCD format
-
- const uint8_t address[] = {0x03}; // memory address for data
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
-}
-
-bool rtc_ds1307_write_date(uint8_t date)
-{
- if (date<1 || date>31) {
- return false;
- }
- uint8_t data[1] = {0}; // to write time value
- data[0] = (((date/10)%4)<<4)+(date%10); // encode date in BCD format
-
- const uint8_t address[] = {0x04}; // memory address for data
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
-}
-
-bool rtc_ds1307_write_month(uint8_t month)
-{
- if (month<1 || month>12) {
- return false;
- }
- uint8_t data[1] = {0}; // to write time value
- data[0] = (((month/10)%2)<<4)+(month%10); // encode month in BCD format
-
- const uint8_t address[] = {0x05}; // memory address for data
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
-}
-
-bool rtc_ds1307_write_year(uint8_t year)
-{
- if (year>99) {
- return false;
- }
- uint8_t data[1] = {0}; // to write time value
- data[0] = (((year/10)%10)<<4)+(year%10); // encode year in BCD format
-
- const uint8_t address[] = {0x06}; // memory address for data
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
-}
-
-bool rtc_ds1307_write_time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, uint8_t date, uint8_t month, uint8_t year)
-{
- uint8_t data[7] = {0}; // to write all time values
- const uint8_t address[] = {0x00}; // memory address for data
- // seconds
- if (seconds>59) {
- return false;
- }
- if (!i2c_master_read(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, 1)) { // read seconds with CH value
- return false;
- }
- data[0] &= 0x80; // only keep CH flag
- data[0] |= (((seconds/10)%6)<<4)+(seconds%10); // encode seconds in BCD format
- // minutes
- if (minutes>59) {
- return false;
- }
- data[1] = (((minutes/10)%6)<<4)+(minutes%10); // encode minutes in BCD format
- // hours
- if (hours>24) {
- return false;
- }
- data[2] = (((hours/10)%3)<<4)+(hours%10); // encode hours in BCD 24h format
- // day
- if (day<1 || day>7) {
- return false;
- }
- data[3] = (day%8); // encode day in BCD format
- // date
- if (date<1 || date>31) {
- return false;
- }
- data[4] = (((date/10)%4)<<4)+(date%10); // encode date in BCD format
- // month
- if (month<1 || month>12) {
- return false;
- }
- data[5] = (((month/10)%2)<<4)+(month%10); // encode month in BCD format
- // year
- if (year>99) {
- return false;
- }
- data[6] = (((year/10)%10)<<4)+(year%10); // encode year in BCD format
-
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write time value on RTC
-}
-
-bool rtc_ds1307_write_ram(uint8_t* data, uint8_t start, uint8_t length)
-{
- // sanity checks
- if (data==NULL || length==0) { // nothing to read
- return false;
- }
- if (start>55 || start+length>56) { // out of bounds RAM
- return false;
- }
- const uint8_t address[] = {0x08+start}; // memory address for data
- return i2c_master_write(RTC_DS1307_I2C_ADDR, address, LENGTH(address), data, LENGTH(data)); // write RAM (starting at 0x08)
-}
diff --git a/lib/rtc_ds1307.h b/lib/rtc_ds1307.h
deleted file mode 100644
index 96f1b69..0000000
--- a/lib/rtc_ds1307.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/** library to communicate with the Maxim DS1307 I2C RTC IC
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2017
- * @note peripherals used: I²C
- */
-#pragma once
-#error not converted for STM32F4
-
-/** setup communication with RTC IC
- * configure the I2C port defined in the sources
- */
-void rtc_ds1307_setup(void);
-/** verify if oscillator is disabled
- * @return if oscillator is disabled (or if communication error occurred)
- */
-bool rtc_ds1307_oscillator_disabled(void);
-/** read square wave output frequency (in Hz)
- * @return square wave output frequency in Hz, 0 if disabled (0xffff if communication error occurred)
- */
-uint16_t rtc_ds1307_read_square_wave(void);
-/** read seconds from RTC IC
- * @return number of seconds (0-59) of the current time (0xff if communication error occurred)
- */
-uint8_t rtc_ds1307_read_seconds(void);
-/** read minutes from RTC IC
- * @return number of minutes (0-59) of the current time (0xff if communication error occurred)
- */
-uint8_t rtc_ds1307_read_minutes(void);
-/** read hours from RTC IC
- * @return number of hours (0-23) of the current time (0xff if communication error occurred)
- */
-uint8_t rtc_ds1307_read_hours(void);
-/** read day from RTC IC
- * @return day of the week (1-7, 1 is Sunday) of the current time, 1 being Sunday (0xff if communication error occurred)
- */
-uint8_t rtc_ds1307_read_day(void);
-/** read date from RTC IC
- * @return day of the month (1-31) of the current time (0xff if communication error occurred)
- */
-uint8_t rtc_ds1307_read_date(void);
-/** read month from RTC IC
- * @return month of the year (1-12) of the current time (0xff if communication error occurred)
- */
-uint8_t rtc_ds1307_read_month(void);
-/** read year from RTC IC
- * @return year of the century (00-99) of the current time (0xff if communication error occurred)
- */
-uint8_t rtc_ds1307_read_year(void);
-/** read time from RTC IC
- * @return array of {seconds, minutes, hours, day, date, month, year} as defined above (NULL if communication error occurred)
- */
-uint8_t* rtc_ds1307_read_time(void);
-/** read user RAM from RTC IC
- * @param[out] data array to store the RAM read
- * @param[in] start start of the user RAM to read (0-55)
- * @param[in] length number of user RAM bytes to read (0-55)
- * @return if read succeeded
- */
-bool rtc_ds1307_read_ram(uint8_t* data, uint8_t start, uint8_t length);
-/** disable RTC IC oscillator
- * @return if disabling oscillator succeeded
- */
-bool rtc_ds1307_oscillator_disable(void);
-/** enable RTC IC oscillator
- * @return if enabling oscillator succeeded
- */
-bool rtc_ds1307_oscillator_enable(void);
-/** write square wave output frequency (in Hz)
- * @param[in] frequency square wave output frequency in Hz (0 to disable, 1, 4096, 8192, 32768)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_square_wave(uint16_t frequency);
-/** write seconds into RTC IC
- * @param[in] seconds number of seconds (0-59)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_seconds(uint8_t seconds);
-/** write minutes into RTC IC
- * @param[in] minutes number of minutes (0-59)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_minutes(uint8_t minutes);
-/** write hours into RTC IC
- * @param[in] hours number of hours (0-23)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_hours(uint8_t hours);
-/** write day into RTC IC
- * @param[in] day day of the week (1-7, 1 is Sunday)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_day(uint8_t day);
-/** write date into RTC IC
- * @param[in] date day of the month (1-31)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_date(uint8_t date);
-/** write month into RTC IC
- * @param[in] month month of the year (1-12)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_month(uint8_t month);
-/** write year into RTC IC
- * @param[in] year year of the century (00-99)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_year(uint8_t year);
-/** write time into RTC IC
- * @param[in] seconds number of seconds (0-59)
- * @param[in] minutes number of minutes (0-59)
- * @param[in] hours number of hours (0-23)
- * @param[in] day day of the week (1-7, 1 is Sunday)
- * @param[in] date day of the month (1-31)
- * @param[in] month month of the year (1-12)
- * @param[in] year year of the century (00-99)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, uint8_t date, uint8_t month, uint8_t year);
-/** write user RAM from RTC IC
- * @param[in] data array of byte to write in RAM
- * @param[in] start start of the user RAM to write (0-55)
- * @param[in] length number of user RAM bytes to write (0-55)
- * @return if write succeeded
- */
-bool rtc_ds1307_write_ram(uint8_t* data, uint8_t start, uint8_t length);
-
diff --git a/lib/sensor_as3935.c b/lib/sensor_as3935.c
deleted file mode 100644
index cbf8c06..0000000
--- a/lib/sensor_as3935.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/** library to communication with ams AS3935 Franklin lightning sensor IC using SPI
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2019
- * @note peripherals used: SPI @ref sensor_as3935_spi, GPIO @ref sensor_as3935_gpio
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <stdbool.h> // boolean utilities
-#include <math.h> // math utilities
-#include <strings.h> // fff utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/spi.h> // SPI library
-#include <libopencm3/stm32/exti.h> // external interrupt defines
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-
-/* own libraries */
-#include "global.h" // common methods
-#include "sensor_as3935.h" // own definitions
-
-/** @defgroup sensor_as3935_spi SPI peripheral used to communicate with the AS3935
- * @{
- */
-#define SENSOR_AS3935_SPI 1 /**< SPI peripheral */
-/** @} */
-
-/** @defgroup sensor_as3935_gpio GPIO used to control the AS3935
- * @{
- */
-#define SENSOR_AS3935_GPIO_SI PA3 /**< AS3935 Select Interface pin (high = SPI, low = I2C) */
-#define SENSOR_AS3935_GPIO_IRQ PA2 /**< AS3935 Interrupt pin (active high) */
-#define SENSOR_AS3935_GPIO_EN_VREG PA0 /**< AS3935 Voltage Regulator Enable pin (active high) */
-/** @} */
-
-/** register details */
-struct sensor_as3935_register_info_t {
- uint8_t address; /**< register address */
- uint8_t mask; /**< mask of relevant register bits */
- bool writable; /**< if register is writable */
-};
-
-/** AS3935 registers description */
-static const struct sensor_as3935_register_info_t sensor_as3935_register_infos[] = {
- [SENSOR_AS3935_REGISTER_AFE_GB] = {
- .address = 0x00,
- .mask = 0x3e,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_PWD] = {
- .address = 0x00,
- .mask = 0x01,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_NF_LEV] = {
- .address = 0x01,
- .mask = 0x70,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_WDTH] = {
- .address = 0x01,
- .mask = 0x0f,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_CL_STAT] = {
- .address = 0x02,
- .mask = 0x40,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_MIN_NUM_LIGH] = {
- .address = 0x02,
- .mask = 0x30,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_SREJ] = {
- .address = 0x02,
- .mask = 0x0f,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LCO_FDIV] = {
- .address = 0x03,
- .mask = 0xc0,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_MASK_DIST] = {
- .address = 0x03,
- .mask = 0x20,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_INT] = {
- .address = 0x03,
- .mask = 0x0f,
- .writable = false,
- },
- [SENSOR_AS3935_REGISTER_S_LIG_L] = {
- .address = 0x04,
- .mask = 0xff,
- .writable = false,
- },
- [SENSOR_AS3935_REGISTER_S_LIG_M] = {
- .address = 0x05,
- .mask = 0xff,
- .writable = false,
- },
- [SENSOR_AS3935_REGISTER_S_LIG_MM] = {
- .address = 0x06,
- .mask = 0x1f,
- .writable = false,
- },
- [SENSOR_AS3935_REGISTER_DISTANCE] = {
- .address = 0x07,
- .mask = 0x3f,
- .writable = false,
- },
- [SENSOR_AS3935_REGISTER_DISP_LCO] = {
- .address = 0x08,
- .mask = 0x80,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_DISP_SRCO] = {
- .address = 0x08,
- .mask = 0x40,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_DISP_TRCO] = {
- .address = 0x08,
- .mask = 0x20,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_TUN_CAP] = {
- .address = 0x08,
- .mask = 0x0f,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT1] = {
- .address = 0x09,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT2] = {
- .address = 0x0a,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT3] = {
- .address = 0x0b,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT4] = {
- .address = 0x0c,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT5] = {
- .address = 0x0d,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT6] = {
- .address = 0x0e,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT7] = {
- .address = 0x0f,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT8] = {
- .address = 0x10,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT9] = {
- .address = 0x11,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT10] = {
- .address = 0x12,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT11] = {
- .address = 0x13,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT12] = {
- .address = 0x14,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT13] = {
- .address = 0x15,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT14] = {
- .address = 0x16,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT15] = {
- .address = 0x17,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT16] = {
- .address = 0x18,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT17] = {
- .address = 0x19,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT18] = {
- .address = 0x1a,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT19] = {
- .address = 0x1b,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT20] = {
- .address = 0x1c,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT21] = {
- .address = 0x1d,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT22] = {
- .address = 0x1e,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT23] = {
- .address = 0x1f,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT24] = {
- .address = 0x20,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT25] = {
- .address = 0x21,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT26] = {
- .address = 0x22,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT27] = {
- .address = 0x23,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT28] = {
- .address = 0x24,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT29] = {
- .address = 0x25,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT30] = {
- .address = 0x26,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT31] = {
- .address = 0x27,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT32] = {
- .address = 0x28,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT33] = {
- .address = 0x29,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT34] = {
- .address = 0x2a,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT35] = {
- .address = 0x2b,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT36] = {
- .address = 0x2c,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT37] = {
- .address = 0x2d,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT38] = {
- .address = 0x2e,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT39] = {
- .address = 0x2f,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT40] = {
- .address = 0x30,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT41] = {
- .address = 0x31,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_LDLUT42] = {
- .address = 0x32,
- .mask = 0xff,
- .writable = true,
- },
- [SENSOR_AS3935_REGISTER_TRCO_CALIB_DONE] = {
- .address = 0x3a,
- .mask = 0x80,
- .writable = false,
- },
- [SENSOR_AS3935_REGISTER_TRCO_CALIB_NOK] = {
- .address = 0x3a,
- .mask = 0x40,
- .writable = false,
- },
- [SENSOR_AS3935_REGISTER_SRCO_CALIB_DONE] = {
- .address = 0x3b,
- .mask = 0x80,
- .writable = false,
- },
- [SENSOR_AS3935_REGISTER_SRCO_CALIB_NOK] = {
- .address = 0x3b,
- .mask = 0x40,
- .writable = false,
- },
-};
-
-/** flag set if an interrupt has been received */
-volatile bool sensor_as3935_interrupt = false;
-/** if we are currently calibrating the sensor */
-static bool sensor_as3935_calibrating = false;
-/** number of interrupts received */
-static volatile uint16_t sensor_as3935_interrupt_count = 0;
-
-bool sensor_as3935_setup(void)
-{
- // disable internal voltage regulator since we already provide 3.3V (plus VREG is tied to VCC using a 0R resistor)
- rcc_periph_clock_enable(GPIO_RCC(SENSOR_AS3935_GPIO_EN_VREG)); // enable clock for GPIO port
- gpio_clear(GPIO_PORT(SENSOR_AS3935_GPIO_EN_VREG), GPIO_PIN(SENSOR_AS3935_GPIO_EN_VREG)); // set low to disable voltage regulator
- gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_EN_VREG), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(SENSOR_AS3935_GPIO_EN_VREG)); // set GPIO as output
- // select SPI interface
- rcc_periph_clock_enable(GPIO_RCC(SENSOR_AS3935_GPIO_SI)); // enable clock for GPIO port
- gpio_clear(GPIO_PORT(SENSOR_AS3935_GPIO_SI), GPIO_PIN(SENSOR_AS3935_GPIO_SI)); // pull low since it's active high
- gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_SI), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(SENSOR_AS3935_GPIO_SI)); // set GPIO as output
- // configure interrupt
- rcc_periph_clock_enable(GPIO_RCC(SENSOR_AS3935_GPIO_IRQ)); // enable clock for GPIO port
- gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_IRQ), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(SENSOR_AS3935_GPIO_IRQ)); // set interrupt as input
- // setup SPI
- rcc_periph_clock_enable(RCC_SPI_SCK_PORT(SENSOR_AS3935_SPI)); // enable clock for GPIO peripheral for clock signal
- gpio_set_mode(SPI_SCK_PORT(SENSOR_AS3935_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(SENSOR_AS3935_SPI)); // set SCK as output (clock speed will be negotiated later)
- rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(SENSOR_AS3935_SPI)); // enable clock for GPIO peripheral for MOSI signal
- gpio_set_mode(SPI_MOSI_PORT(SENSOR_AS3935_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(SENSOR_AS3935_SPI)); // set MOSI as output
- rcc_periph_clock_enable(RCC_SPI_MISO_PORT(SENSOR_AS3935_SPI)); // enable clock for GPIO peripheral for MISO signal
- gpio_set_mode(SPI_MISO_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SPI_MISO_PIN(SENSOR_AS3935_SPI)); // set MISO as input
- rcc_periph_clock_enable(RCC_SPI_NSS_PORT(SENSOR_AS3935_SPI)); // enable clock for GPIO peripheral for NSS (CS) signal
- gpio_set_mode(SPI_NSS_PORT(SENSOR_AS3935_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, SPI_NSS_PIN(SENSOR_AS3935_SPI)); // set NSS (CS) as output
- rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
- rcc_periph_clock_enable(RCC_SPI(SENSOR_AS3935_SPI)); // enable clock for SPI peripheral
- spi_reset(SPI(SENSOR_AS3935_SPI)); // clear SPI values to default
- spi_init_master(SPI(SENSOR_AS3935_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_64, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_16BIT, SPI_CR1_MSBFIRST); // initialise SPI as master, divide clock by 64 (72E6/64=1125 kHz, max AS3935 SCK is 2 MHz, maximum SPI PCLK clock is 72 Mhz, depending on which SPI is used), set clock polarity to idle low (not that important), set clock phase to do bit change on falling edge (polarity depends on clock phase), use 16 bits frames , use MSb first
- spi_set_full_duplex_mode(SPI(SENSOR_AS3935_SPI)); // ensure we are in full duplex mode
- spi_enable_software_slave_management(SPI(SENSOR_AS3935_SPI)); // control NSS (CS) manually
- spi_set_nss_high(SPI(SENSOR_AS3935_SPI)); // set NSS high (internally) so we can output
- spi_disable_ss_output(SPI(SENSOR_AS3935_SPI)); // disable NSS output since we control CS manually
- gpio_set(SPI_NSS_PORT(SENSOR_AS3935_SPI), SPI_NSS_PIN(SENSOR_AS3935_SPI)); // set CS high to unselect device
- // sadly we can't use the interrupts as events to sleep (WFE) since sleep disables also communication (e.g. going to sleep until Rx buffer is not empty prevents transmission)
- spi_enable(SPI(SENSOR_AS3935_SPI)); // enable SPI
- sleep_ms(2); // be sure TCO has enough time to start
- // configure device
- sensor_as3935_command(SENSOR_AS3935_OPERATION_DIRECT_COMMAND, SENSOR_AS3935_DIRECT_COMMAND_PRESET_DEFAULT, SENSOR_AS3935_DIRECT_COMMAND_VALUE); // reset all values to default
- if (0x24 != sensor_as3935_command(SENSOR_AS3935_OPERATION_READ, 0, 0)) { // check if communication works by checking default register value
- return false;
- }
- sensor_as3935_power_down(); // power down to save power
- rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
- // configure IRQ interrupt
- exti_select_source(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ), GPIO_PORT(SENSOR_AS3935_GPIO_IRQ)); // mask external interrupt of the IRQ pin only for this port
- exti_set_trigger(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ), EXTI_TRIGGER_RISING); // IRQ goes high in interrupt
- exti_enable_request(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ)); // enable external interrupt
- nvic_enable_irq(GPIO_NVIC_EXTI_IRQ(SENSOR_AS3935_GPIO_IRQ)); // enable interrupt
- sensor_as3935_interrupt = (0 != gpio_get(GPIO_PORT(SENSOR_AS3935_GPIO_IRQ), GPIO_PIN(SENSOR_AS3935_GPIO_IRQ))); // update interrupt status
- return true;
-}
-
-void sensor_as3935_release(void)
-{
- nvic_disable_irq(GPIO_NVIC_EXTI_IRQ(SENSOR_AS3935_GPIO_IRQ));
- exti_disable_request(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ));
- spi_reset(SPI(SENSOR_AS3935_SPI));
- spi_disable(SPI(SENSOR_AS3935_SPI));
- rcc_periph_clock_disable(RCC_SPI(SENSOR_AS3935_SPI));
- gpio_set_mode(SPI_NSS_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_NSS_PIN(SENSOR_AS3935_SPI));
- gpio_set_mode(SPI_MISO_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_MISO_PIN(SENSOR_AS3935_SPI));
- gpio_set_mode(SPI_MOSI_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_MOSI_PIN(SENSOR_AS3935_SPI));
- gpio_set_mode(SPI_SCK_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_SCK_PIN(SENSOR_AS3935_SPI));
- gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_IRQ), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(SENSOR_AS3935_GPIO_IRQ));
- gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_SI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(SENSOR_AS3935_GPIO_SI));
- gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_EN_VREG), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(SENSOR_AS3935_GPIO_EN_VREG));
-}
-
-uint8_t sensor_as3935_command(enum sensor_as3935_operation_t operation, uint8_t address_command, uint8_t data)
-{
- gpio_clear(SPI_NSS_PORT(SENSOR_AS3935_SPI), SPI_NSS_PIN(SENSOR_AS3935_SPI)); // set CS low to select device
- spi_send(SPI(SENSOR_AS3935_SPI), ((operation & 0x3) << 14) | ((address_command & 0x3f) << 8) | data); // send command
- (void)SPI_DR(SPI(SENSOR_AS3935_SPI)); // clear RXNE flag (by reading previously received data (not done by spi_read or spi_xref)
- while (!(SPI_SR(SPI(SENSOR_AS3935_SPI)) & SPI_SR_TXE)); // wait until Tx buffer is empty before clearing the (previous) RXNE flag
- while (!(SPI_SR(SPI(SENSOR_AS3935_SPI)) & SPI_SR_RXNE)); // wait for next data to be available
- gpio_set(SPI_NSS_PORT(SENSOR_AS3935_SPI), SPI_NSS_PIN(SENSOR_AS3935_SPI)); // set CS high to unselect device
- return SPI_DR(SPI(SENSOR_AS3935_SPI)); // return received data
-}
-
-uint8_t sensor_as3935_read_register(enum sensor_as3935_register_t name)
-{
- if (name >= LENGTH(sensor_as3935_register_infos)) { // check if register exists
- return 0;
- }
- if (SENSOR_AS3935_REGISTER_INT == name) { // you need to wait 2 ms after an interrupt before reading the register
- sleep_ms(2);
- }
- struct sensor_as3935_register_info_t register_info = sensor_as3935_register_infos[name]; // get register information
- uint8_t value = sensor_as3935_command(SENSOR_AS3935_OPERATION_READ, register_info.address, 0); // get register value
- value &= register_info.mask; // only keep relevant bits
- value >>= (ffs(register_info.mask) - 1); // shit value bits
- return value;
-}
-
-bool sensor_as3935_write_register(enum sensor_as3935_register_t name, uint8_t value)
-{
- if (name >= LENGTH(sensor_as3935_register_infos)) { // check if register exists
- return false;
- }
- struct sensor_as3935_register_info_t register_info = sensor_as3935_register_infos[name]; // get register information
- if (!register_info.writable) {
- return false;
- }
- uint8_t data = sensor_as3935_command(SENSOR_AS3935_OPERATION_READ, register_info.address, 0); // get register data
- value <<= (ffs(register_info.mask) - 1); // shit value bits
- value &= register_info.mask; // only keep relevant bits
- data &= ~register_info.mask; // clear relevant bit is final data
- data |= value; // put value in data
- sensor_as3935_command(SENSOR_AS3935_OPERATION_WRITE, register_info.address, data); // write register data
- return true;
-}
-
-void sensor_as3935_power_down(void)
-{
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_PWD, 1);
-}
-
-int8_t sensor_as3935_power_up(void)
-{
- nvic_disable_irq(GPIO_NVIC_EXTI_IRQ(SENSOR_AS3935_GPIO_IRQ)); // no need to count the next clock calibration
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_PWD, 0); // power up
- sensor_as3935_command(SENSOR_AS3935_OPERATION_DIRECT_COMMAND, SENSOR_AS3935_DIRECT_COMMAND_CALIB_RCO, SENSOR_AS3935_DIRECT_COMMAND_VALUE); // start RCO calibration
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_DISP_SRCO, 1); // output SRCO to start calibration
- sleep_ms(2); // as defined in the calibration procedure
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_DISP_SRCO, 0); // stop SRCO output
- nvic_enable_irq(GPIO_NVIC_EXTI_IRQ(SENSOR_AS3935_GPIO_IRQ)); // re-enable interrupt
- sensor_as3935_interrupt = (0 != gpio_get(GPIO_PORT(SENSOR_AS3935_GPIO_IRQ), GPIO_PIN(SENSOR_AS3935_GPIO_IRQ))); // update interrupt status
- // check if calibration succeeded
- if (0 == sensor_as3935_read_register(SENSOR_AS3935_REGISTER_SRCO_CALIB_DONE)) {
- return -1;
- }
- if (1 == sensor_as3935_read_register(SENSOR_AS3935_REGISTER_SRCO_CALIB_NOK)) {
- return -2;
- }
- // the datasheet does not mention how to calibrate TRCO, but it is not equivalent to the SRCO mechanism and just happens if you try it often enough
- if (0 == sensor_as3935_read_register(SENSOR_AS3935_REGISTER_TRCO_CALIB_DONE)) {
- return -3;
- }
- if (1 == sensor_as3935_read_register(SENSOR_AS3935_REGISTER_TRCO_CALIB_NOK)) {
- return -4;
- }
- return 0;
-}
-
-bool sensor_as3935_tune(void)
-{
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_PWD, 0); // power up (without calibration)
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_LCO_FDIV, 0); // divide LCO by 16 (500 kHz LCO becomes 31250 Hz output)
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_DISP_LCO, 1); // output LCO on INT to measure frequency
- uint8_t best_tune = 0; // remember best internal tuning capacitor setting
- uint16_t best_offset = UINT16_MAX; // remember best LCO frequency offset
- sensor_as3935_calibrating = true; // count the pulses now
- for (uint8_t tune_cap = 0; tune_cap < 16; tune_cap++) { // test all internal tuning capacitor settings
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_TUN_CAP, tune_cap); // set internal capacitor
- sleep_ms(1); // wait a bit until the output stabilize
- sensor_as3935_interrupt_count = 0; // start counting
- sleep_ms(100); // wait to measure frequency precisely enough (3.5% corresponds to 109 pulses)
- uint16_t offset = abs(sensor_as3935_interrupt_count - 3125); // calculate offset to ideal frequency (500 kHz / 16 during 100 ms)
- if (offset < best_offset) { // check if the tune frequency is closed to the ideal
- best_offset = offset; // remember new best offset
- best_tune = tune_cap; // remember we found a new better tuning setting
- }
- }
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_DISP_LCO, 0); // switch back INT output for interrupts
- sensor_as3935_calibrating = false; // stop counting the pulses
- if (best_offset > 109 + 10) { // no setting has an error < 3.5% for 500 kHz (500 kHz / 16 * 3.5% during 100 ms, plus some measurement error margin)
- return false;
- }
- sensor_as3935_write_register(SENSOR_AS3935_REGISTER_TUN_CAP, best_tune); // set best capacitor tuning setting
- return true;
-}
-
-/** interrupt service routine called when IRQ does high to indicate interrupt (or clock outputs) */
-void GPIO_EXTI_ISR(SENSOR_AS3935_GPIO_IRQ)(void)
-{
- if (sensor_as3935_calibrating) {
- sensor_as3935_interrupt_count++; // increment pulse count to calculate to frequency
- } else {
- sensor_as3935_interrupt = true; // notify user
- }
- exti_reset_request(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ)); // reset interrupt
-}
diff --git a/lib/sensor_as3935.h b/lib/sensor_as3935.h
deleted file mode 100644
index 00507e8..0000000
--- a/lib/sensor_as3935.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/** library to communication with ams AS3935 Franklin lightning sensor IC using SPI
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2019
- * @note peripherals used: SPI @ref sensor_as3935_spi, GPIO @ref sensor_as3935_gpio
- */
-#pragma once
-#error not converted for STM32F4
-
-/** a interrupt has been received */
-extern volatile bool sensor_as3935_interrupt;
-
-/** SPI operation mode */
-enum sensor_as3935_operation_t {
- SENSOR_AS3935_OPERATION_WRITE = 0, /**< write to register */
- SENSOR_AS3935_OPERATION_DIRECT_COMMAND = 0, /**< send direct command (equivalent to write to register) */
- SENSOR_AS3935_OPERATION_READ = 1, /**< read from register */
-};
-
-/** register names */
-enum sensor_as3935_register_t {
- SENSOR_AS3935_REGISTER_AFE_GB, /**< AFE Gain Boost */
- SENSOR_AS3935_REGISTER_PWD, /**< Power-down */
- SENSOR_AS3935_REGISTER_NF_LEV, /**< Noise Floor Level */
- SENSOR_AS3935_REGISTER_WDTH, /**< Watchdog threshold */
- SENSOR_AS3935_REGISTER_CL_STAT, /**< Clear statistics */
- SENSOR_AS3935_REGISTER_MIN_NUM_LIGH, /**< Minimum number of lightning */
- SENSOR_AS3935_REGISTER_SREJ, /**< Spike rejection */
- SENSOR_AS3935_REGISTER_LCO_FDIV, /**< Frequency division ration for antenna tuning */
- SENSOR_AS3935_REGISTER_MASK_DIST, /**< Mask Disturber */
- SENSOR_AS3935_REGISTER_INT, /**< Interrupt */
- SENSOR_AS3935_REGISTER_S_LIG_L, /**< Energy of the Single Lightning LSBYTE */
- SENSOR_AS3935_REGISTER_S_LIG_M, /**< Energy of the Single Lightning MSBYTE */
- SENSOR_AS3935_REGISTER_S_LIG_MM, /**< Energy of the Single Lightning MMSBYTE */
- SENSOR_AS3935_REGISTER_DISTANCE, /**< Distance estimation */
- SENSOR_AS3935_REGISTER_DISP_LCO, /**< Display LCO on IRQ pin */
- SENSOR_AS3935_REGISTER_DISP_SRCO, /**< Display SRCO on IRQ pin */
- SENSOR_AS3935_REGISTER_DISP_TRCO, /**< Display TRCO on IRQ pin */
- SENSOR_AS3935_REGISTER_TUN_CAP, /**< Internal Tuning Capacitors */
- SENSOR_AS3935_REGISTER_LDLUT1, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT2, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT3, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT4, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT5, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT6, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT7, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT8, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT9, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT10, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT11, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT12, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT13, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT14, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT15, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT16, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT17, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT18, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT19, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT20, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT21, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT22, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT23, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT24, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT25, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT26, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT27, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT28, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT29, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT30, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT31, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT32, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT33, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT34, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT35, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT36, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT37, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT38, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT39, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT40, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT41, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_LDLUT42, /**< Lightning Detection Look-up table */
- SENSOR_AS3935_REGISTER_TRCO_CALIB_DONE, /**< Calibration of TRCO done (1=successful) */
- SENSOR_AS3935_REGISTER_TRCO_CALIB_NOK, /**< Calibration of TRCO unsuccessful (1=not successful) */
- SENSOR_AS3935_REGISTER_SRCO_CALIB_DONE, /**< Calibration of SRCO done (1=successful) */
- SENSOR_AS3935_REGISTER_SRCO_CALIB_NOK, /**< Calibration of SRCO unsuccessful (1=not successful) */
-};
-
-/** direct command to sets all registers in default mode */
-#define SENSOR_AS3935_DIRECT_COMMAND_PRESET_DEFAULT 0x3C
-/** direct command to calibrate automatically the internal RC oscillators */
-#define SENSOR_AS3935_DIRECT_COMMAND_CALIB_RCO 0x3D
-/** value to be used for direct commands */
-#define SENSOR_AS3935_DIRECT_COMMAND_VALUE 0x96
-
-/** interrupt meaning
- * @note use as bit mask
- * @note if IRQ is high but no bit is set, a new front calculation is available
- */
-enum sensor_as3935_interrupt_t {
- SENSOR_AS3935_INT_NH = 0x01, /**< noise level too high */
- SENSOR_AS3935_INT_D = 0x04, /**< disturber detected */
- SENSOR_AS3935_INT_L = 0x08, /**< lightning detected */
-};
-
-/** register value for indoor AFE setting */
-#define SENSOR_AS3935_REGISTER_AFE_INDOOR 0x12
-/** register value for outdoor AFE setting */
-#define SENSOR_AS3935_REGISTER_AFE_OUTDOOR 0x0e
-
-/** setup peripherals to communicate with sensor
- * @return false if communication with sensor failed
- * @note the sensor configuration will be set to default and powered down
- */
-bool sensor_as3935_setup(void);
-/** release peripherals used to communicate with sensor */
-void sensor_as3935_release(void);
-/** send command
- * @param[in] operation operation mode
- * @param[in] address_command register address or direct command
- * @param[in] data register data
- * @return register value
- */
-uint8_t sensor_as3935_command(enum sensor_as3935_operation_t operation, uint8_t address_command, uint8_t data);
-/** read register
- * @param[in] name register name
- * @return register value
- */
-uint8_t sensor_as3935_read_register(enum sensor_as3935_register_t name);
-/** read register
- * @param[in] name register name
- * @param[in] value register value
- * @return if write is allowed and succeeded
- */
-bool sensor_as3935_write_register(enum sensor_as3935_register_t name, uint8_t value);
-/** power down sensor
- * @note after a power down the sensor needs to be calibrated again
- */
-void sensor_as3935_power_down(void);
-/** power up sensor and calibrate RCO
- * @return 0 if calibration succeeded, < 0 else
- * @warning the antenna should be tuned before
- */
-int8_t sensor_as3935_power_up(void);
-/** tune antenna
- * @return if calibration succeeded (false if no capacitor value leading to a frequency error < 3.5% has been found)
- * @note powers the sensor (but does not calibrates it)
- * @warning should be run after setup and before power up
- */
-bool sensor_as3935_tune(void);
diff --git a/lib/sensor_dht11.c b/lib/sensor_dht11.c
deleted file mode 100644
index 20364d8..0000000
--- a/lib/sensor_dht11.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/** library to query measurements from Aosong DHT11 temperature and relative humidity sensor
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: timer channel @ref sensor_dht11_timer
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/timer.h> // timer utilities
-
-/* own libraries */
-#include "sensor_dht11.h" // PZEM electricity meter header and definitions
-#include "global.h" // common methods
-
-/** @defgroup sensor_dht11_timer timer peripheral used to measure signal timing for bit decoding
- * @{
- */
-#define SENSOR_DHT11_TIMER 3 /**< timer peripheral */
-#define SENSOR_DHT11_CHANNEL 1 /**< channel used as input capture */
-#define SENSOR_DHT11_JITTER 0.1 /**< signal timing jitter tolerated in timing */
-/** @} */
-
-volatile bool sensor_dht11_measurement_received = false;
-
-/** communication states */
-volatile enum sensor_dht11_state_t {
- SENSOR_DHT11_OFF, // no request has started
- SENSOR_DHT11_HOST_START, // host starts request (and waits >18ms)
- SENSOR_DHT11_HOST_STARTED, // host started request and waits for slave answer
- SENSOR_DHT11_SLAVE_START, // slave responds to request and puts signal low for 80 us and high for 80 us
- SENSOR_DHT11_SLAVE_BIT, // slave is sending bit by putting signal low for 50 us and high (26-28 us = 0, 70 us = 1)
- SENSOR_DHT11_MAX
-} sensor_dht11_state = SENSOR_DHT11_OFF; /**< current communication state */
-
-/** the bit number being sent (MSb first), up to 40 */
-volatile uint8_t sensor_dht11_bit = 0;
-
-/** the 40 bits (5 bytes) being sent by the device */
-volatile uint8_t sensor_dht11_bits[5] = {0};
-
-/** reset all states */
-static void sensor_dht11_reset(void)
-{
- // reset states
- sensor_dht11_state = SENSOR_DHT11_OFF;
- sensor_dht11_bit = 0;
- sensor_dht11_measurement_received = false;
- gpio_set(TIM_CH_PORT(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL), TIM_CH_PIN(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL)); // idle is high (using pull-up resistor), pull-up before setting as output else the signal will be low for short
- gpio_set_mode(TIM_CH_PORT(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, TIM_CH_PIN(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL)); // setup GPIO pin as output (host starts communication before slave replies)
- timer_ic_disable(TIM(SENSOR_DHT11_TIMER), TIM_IC(SENSOR_DHT11_CHANNEL)); // enable capture interrupt only when receiving data
- timer_disable_counter(TIM(SENSOR_DHT11_TIMER)); // disable timer
-}
-
-void sensor_dht11_setup(void)
-{
- // setup timer to measure signal timing for bit decoding (use timer channel as input capture)
- rcc_periph_clock_enable(RCC_TIM_CH(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL)); // enable clock for GPIO peripheral
- rcc_periph_clock_enable(RCC_TIM(SENSOR_DHT11_TIMER)); // enable clock for timer peripheral
- rcc_periph_reset_pulse(RST_TIM(SENSOR_DHT11_TIMER)); // reset timer state
- timer_set_mode(TIM(SENSOR_DHT11_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(SENSOR_DHT11_TIMER), 20 - 1); // set the prescaler so this 16 bits timer allows to wait for 18 ms for the start signal ( 1/(72E6/20/(2**16))=18.20ms )
- timer_ic_set_input(TIM(SENSOR_DHT11_TIMER), TIM_IC(SENSOR_DHT11_CHANNEL), TIM_IC_IN_TI(SENSOR_DHT11_CHANNEL)); // configure ICx to use TIn
- timer_ic_set_filter(TIM(SENSOR_DHT11_TIMER), TIM_IC(SENSOR_DHT11_CHANNEL), TIM_IC_OFF); // use no filter input (precise timing needed)
- timer_ic_set_polarity(TIM(SENSOR_DHT11_TIMER), TIM_IC(SENSOR_DHT11_CHANNEL), TIM_IC_FALLING); // capture on rising edge
- timer_ic_set_prescaler(TIM(SENSOR_DHT11_TIMER), TIM_IC(SENSOR_DHT11_CHANNEL), TIM_IC_PSC_OFF); // don't use any prescaler since we want to capture every pulse
-
- timer_clear_flag(TIM(SENSOR_DHT11_TIMER), TIM_SR_UIF); // clear flag
- timer_update_on_overflow(TIM(SENSOR_DHT11_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout)
- timer_enable_irq(TIM(SENSOR_DHT11_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
-
- timer_clear_flag(TIM(SENSOR_DHT11_TIMER), TIM_SR_CCIF(SENSOR_DHT11_CHANNEL)); // clear input compare flag
- timer_enable_irq(TIM(SENSOR_DHT11_TIMER), TIM_DIER_CCIE(SENSOR_DHT11_CHANNEL)); // enable capture interrupt
-
- nvic_enable_irq(NVIC_TIM_IRQ(SENSOR_DHT11_TIMER)); // catch interrupt in service routine
-
- sensor_dht11_reset(); // reset state
-}
-
-bool sensor_dht11_measurement_request(void)
-{
- if (sensor_dht11_state != SENSOR_DHT11_OFF) { // not the right state to start (wait up until timeout to reset state)
- return false;
- }
- if (gpio_get(TIM_CH_PORT(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL), TIM_CH_PIN(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL)) == 0) { // signal should be high per default
- return false;
- }
- if (TIM_CR1(TIM(SENSOR_DHT11_TIMER)) & (TIM_CR1_CEN)) { // timer should be off
- return false;
- }
- sensor_dht11_reset(); // reset states
-
- // send start signal (pull low for > 18 ms)
- gpio_clear(TIM_CH_PORT(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL), TIM_CH_PIN(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL)); // set signal to low
- timer_set_counter(TIM(SENSOR_DHT11_TIMER), 0); // reset timer counter
- timer_enable_counter(TIM(SENSOR_DHT11_TIMER)); // enable timer to wait for 18 ms until overflow
- sensor_dht11_state = SENSOR_DHT11_HOST_START; // remember we started sending signal
-
- return true;
-}
-
-struct sensor_dht11_measurement_t sensor_dht11_measurement_decode(void)
-{
- struct sensor_dht11_measurement_t measurement = { 0xff, 0xff }; // measurement to return
- if (sensor_dht11_bit < 40) { // not enough bits received
- return measurement;
- }
- if ((uint8_t)(sensor_dht11_bits[0] + sensor_dht11_bits[1] + sensor_dht11_bits[2] + sensor_dht11_bits[3]) != sensor_dht11_bits[4]) { // error in checksum (not really parity bit, as mentioned in the datasheet)
- return measurement;
- }
- // calculate measured values (byte 1 and 3 should be the factional value but they are always 0)
- measurement.humidity = sensor_dht11_bits[0];
- measurement.temperature = sensor_dht11_bits[2];
-
- return measurement;
-}
-
-/** interrupt service routine called for timer */
-void TIM_ISR(SENSOR_DHT11_TIMER)(void)
-{
- if (timer_get_flag(TIM(SENSOR_DHT11_TIMER), TIM_SR_UIF)) { // overflow update event happened
- timer_clear_flag(TIM(SENSOR_DHT11_TIMER), TIM_SR_UIF); // clear flag
- if (sensor_dht11_state == SENSOR_DHT11_HOST_START) { // start signal sent
- gpio_set_mode(TIM_CH_PORT(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, TIM_CH_PIN(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL)); // switch pin to input (the external pull up with also set the signal high)
- sensor_dht11_state = SENSOR_DHT11_HOST_STARTED; // switch to next state
- timer_ic_enable(TIM(SENSOR_DHT11_TIMER), TIM_IC(SENSOR_DHT11_CHANNEL)); // enable capture interrupt only when receiving data
- } else { // timeout occurred
- sensor_dht11_reset(); // reset states
- }
- } else if (timer_get_flag(TIM(SENSOR_DHT11_TIMER), TIM_SR_CCIF(SENSOR_DHT11_CHANNEL))) { // edge detected on input capture
- uint16_t time = TIM_CCR(SENSOR_DHT11_TIMER,SENSOR_DHT11_CHANNEL); // save captured bit timing (this clear also the flag)
- timer_set_counter(TIM(SENSOR_DHT11_TIMER), 0); // reset timer counter
- time = (time * 1E6) / (rcc_ahb_frequency / (TIM_PSC(TIM(SENSOR_DHT11_TIMER)) + 1)); // calculate time in us
- switch (sensor_dht11_state) {
- case (SENSOR_DHT11_HOST_STARTED): // the host query data and the slave is responding
- sensor_dht11_state = SENSOR_DHT11_SLAVE_START; // set new state
- break;
- case (SENSOR_DHT11_SLAVE_START): // the slave sent the start signal
- if (time >= ((80 + 80) * (1 - SENSOR_DHT11_JITTER)) && time <= ((80 + 80)*(1 + SENSOR_DHT11_JITTER))) { // response time should be 80 us low and 80 us high
- sensor_dht11_state = SENSOR_DHT11_SLAVE_BIT; // set new state
- } else {
- goto error;
- }
- break;
- case (SENSOR_DHT11_SLAVE_BIT): // the slave sent a bit
- if (sensor_dht11_bit >= 40) { // no bits should be received after 40 bits
- goto error;
- }
- if (time >= ((50 + 26) * (1 - SENSOR_DHT11_JITTER)) && time <= ((50 + 28) * (1 + SENSOR_DHT11_JITTER))) { // bit 0 time should be 50 us low and 26-28 us high
- sensor_dht11_bits[sensor_dht11_bit / 8] &= ~(1 << (7 - (sensor_dht11_bit % 8))); // clear bit
- } else if (time >= ((50 + 70)*(1 - SENSOR_DHT11_JITTER)) && time <= ((50 + 70) * (1 + SENSOR_DHT11_JITTER))) { // bit 1 time should be 50 us low and 70 us high
- sensor_dht11_bits[sensor_dht11_bit / 8] |= (1 << (7 - (sensor_dht11_bit % 8))); // set bit
- } else {
- goto error;
- }
- sensor_dht11_bit++;
- if (sensor_dht11_bit >= 40) { // all bits received
- sensor_dht11_reset(); // reset states
- sensor_dht11_bit = 40; // signal decoder all bits have been received
- sensor_dht11_measurement_received = true; // signal user all bits have been received
- }
- break;
- default: // unexpected state
-error:
- sensor_dht11_reset(); // reset states
- }
- } else { // no other interrupt should occur
- while (true); // unhandled exception: wait for the watchdog to bite
- }
-}
diff --git a/lib/sensor_dht11.h b/lib/sensor_dht11.h
deleted file mode 100644
index 47e33f4..0000000
--- a/lib/sensor_dht11.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/** library to query measurements from Aosong DHT11 temperature and relative humidity sensor
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: timer channel @ref sensor_dht11_timer (add external pull-up resistor)
- */
-#pragma once
-#error not converted for STM32F4
-
-/** a measurement response has been received */
-extern volatile bool sensor_dht11_measurement_received;
-
-/** measurement returned by sensor */
-struct sensor_dht11_measurement_t {
- uint8_t humidity; /**< relative humidity in %RH (20-95) */
- uint8_t temperature; /**< temperature in °C (0-50) */
-};
-
-/** setup peripherals to communicate with sensor */
-void sensor_dht11_setup(void);
-/** request measurement from sensor
- * @return request started successfully
- */
-bool sensor_dht11_measurement_request(void);
-/** decode received measurement
- * @return decoded measurement (0xff,0xff if invalid)
- */
-struct sensor_dht11_measurement_t sensor_dht11_measurement_decode(void);
diff --git a/lib/sensor_dht22.c b/lib/sensor_dht22.c
deleted file mode 100644
index bacb100..0000000
--- a/lib/sensor_dht22.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/** library to query measurements from Aosong DHT22 temperature and relative humidity sensor
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: GPIO and timer @ref sensor_dht22_timer
- * @note the DHT22 protocol is very similar but nit completely compatible with the DHT22 protocol: only 1 ms initial host pull low is required (vs. 18 ms), the data is encoded as int16_t (vs. uint8_t), and the signal has more jitter
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <math.h> // maths utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/timer.h> // timer utilities
-
-/* own libraries */
-#include "sensor_dht22.h" // PZEM electricity meter header and definitions
-#include "global.h" // common methods
-
-/** @defgroup sensor_dht22_timer timer peripheral used to measure signal timing for bit decoding
- * @{
- */
-#define SENSOR_DHT22_TIMER 4 /**< timer peripheral */
-#define SENSOR_DHT22_CHANNEL 3 /**< channel used as input capture */
-#define SENSOR_DHT22_JITTER 0.2 /**< signal timing jitter tolerated in timing */
-/** @} */
-
-volatile bool sensor_dht22_measurement_received = false;
-
-/** communication states */
-volatile enum sensor_dht22_state_t {
- SENSOR_DHT22_OFF, // no request has started
- SENSOR_DHT22_HOST_START, // host starts request (and waits >18ms)
- SENSOR_DHT22_HOST_STARTED, // host started request and waits for slave answer
- SENSOR_DHT22_SLAVE_START, // slave responds to request and puts signal low for 80 us and high for 80 us
- SENSOR_DHT22_SLAVE_BIT, // slave is sending bit by putting signal low for 50 us and high (26-28 us = 0, 70 us = 1)
- SENSOR_DHT22_MAX
-} sensor_dht22_state = SENSOR_DHT22_OFF; /**< current communication state */
-
-/** the bit number being sent (MSb first), up to 40 */
-volatile uint8_t sensor_dht22_bit = 0;
-
-/** the 40 bits (5 bytes) being sent by the device */
-volatile uint8_t sensor_dht22_bits[5] = {0};
-
-/** reset all states */
-static void sensor_dht22_reset(void)
-{
- // reset states
- sensor_dht22_state = SENSOR_DHT22_OFF;
- sensor_dht22_bit = 0;
- sensor_dht22_measurement_received = false;
-
- gpio_set(TIM_CH_PORT(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL), TIM_CH_PIN(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL)); // idle is high (using pull-up resistor), pull-up before setting as output else the signal will be low for short
- gpio_set_mode(TIM_CH_PORT(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, TIM_CH_PIN(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL)); // setup GPIO pin as output (host starts communication before slave replies)
-
- timer_ic_disable(TIM(SENSOR_DHT22_TIMER), TIM_IC(SENSOR_DHT22_CHANNEL)); // enable capture interrupt only when receiving data
- timer_disable_counter(TIM(SENSOR_DHT22_TIMER)); // disable timer
-}
-
-void sensor_dht22_setup(void)
-{
- // setup timer to measure signal timing for bit decoding (use timer channel as input capture)
- rcc_periph_clock_enable(RCC_TIM_CH(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL)); // enable clock for GPIO peripheral
- rcc_periph_clock_enable(RCC_TIM(SENSOR_DHT22_TIMER)); // enable clock for timer peripheral
- rcc_periph_reset_pulse(RST_TIM(SENSOR_DHT22_TIMER)); // reset timer state
- timer_set_mode(TIM(SENSOR_DHT22_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(SENSOR_DHT22_TIMER), 2 - 1); // set the prescaler so this 16 bits timer allows to wait for 18 ms for the start signal ( 1/(72E6/2/(2**16))=1.820ms )
- timer_ic_set_input(TIM(SENSOR_DHT22_TIMER), TIM_IC(SENSOR_DHT22_CHANNEL), TIM_IC_IN_TI(SENSOR_DHT22_CHANNEL)); // configure ICx to use TIn
- timer_ic_set_filter(TIM(SENSOR_DHT22_TIMER), TIM_IC(SENSOR_DHT22_CHANNEL), TIM_IC_OFF); // use no filter input (precise timing needed)
- timer_ic_set_polarity(TIM(SENSOR_DHT22_TIMER), TIM_IC(SENSOR_DHT22_CHANNEL), TIM_IC_FALLING); // capture on rising edge
- timer_ic_set_prescaler(TIM(SENSOR_DHT22_TIMER), TIM_IC(SENSOR_DHT22_CHANNEL), TIM_IC_PSC_OFF); // don't use any prescaler since we want to capture every pulse
-
- timer_clear_flag(TIM(SENSOR_DHT22_TIMER), TIM_SR_UIF); // clear flag
- timer_update_on_overflow(TIM(SENSOR_DHT22_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout)
- timer_enable_irq(TIM(SENSOR_DHT22_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
-
- timer_clear_flag(TIM(SENSOR_DHT22_TIMER), TIM_SR_CCIF(SENSOR_DHT22_CHANNEL)); // clear input compare flag
- timer_enable_irq(TIM(SENSOR_DHT22_TIMER), TIM_DIER_CCIE(SENSOR_DHT22_CHANNEL)); // enable capture interrupt
-
- nvic_enable_irq(NVIC_TIM_IRQ(SENSOR_DHT22_TIMER)); // catch interrupt in service routine
-
- sensor_dht22_reset(); // reset state
-}
-
-bool sensor_dht22_measurement_request(void)
-{
- if (sensor_dht22_state != SENSOR_DHT22_OFF) { // not the right state to start (wait up until timeout to reset state)
- return false;
- }
- if (gpio_get(TIM_CH_PORT(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL), TIM_CH_PIN(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL)) == 0) { // signal should be high per default
- return false;
- }
- if (TIM_CR1(TIM(SENSOR_DHT22_TIMER)) & (TIM_CR1_CEN)) { // timer should be off
- return false;
- }
- sensor_dht22_reset(); // reset states
-
- // send start signal (pull low for > 1 ms)
- gpio_clear(TIM_CH_PORT(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL), TIM_CH_PIN(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL)); // set signal to low
- timer_set_counter(TIM(SENSOR_DHT22_TIMER), 0); // reset timer counter
- timer_enable_counter(TIM(SENSOR_DHT22_TIMER)); // enable timer to wait for 1.8 ms until overflow
- sensor_dht22_state = SENSOR_DHT22_HOST_START; // remember we started sending signal
-
- return true;
-}
-
-struct sensor_dht22_measurement_t sensor_dht22_measurement_decode(void)
-{
- struct sensor_dht22_measurement_t measurement = { NAN, NAN }; // measurement to return
- if (sensor_dht22_bit < 40) { // not enough bits received
- return measurement;
- }
- if ((uint8_t)(sensor_dht22_bits[0] + sensor_dht22_bits[1] + sensor_dht22_bits[2] + sensor_dht22_bits[3]) != sensor_dht22_bits[4]) { // error in checksum (not really parity bit, as mentioned in the datasheet)
- return measurement;
- }
- // calculate measured values (stored as uint16_t deci-value)
- measurement.humidity = (int16_t)((sensor_dht22_bits[0] << 8) + sensor_dht22_bits[1]) / 10.0;
- measurement.temperature = (int16_t)((sensor_dht22_bits[2] << 8) + sensor_dht22_bits[3]) / 10.0;
-
- return measurement;
-}
-
-/** interrupt service routine called for timer */
-void TIM_ISR(SENSOR_DHT22_TIMER)(void)
-{
- if (timer_get_flag(TIM(SENSOR_DHT22_TIMER), TIM_SR_UIF)) { // overflow update event happened
- timer_clear_flag(TIM(SENSOR_DHT22_TIMER), TIM_SR_UIF); // clear flag
- if (sensor_dht22_state==SENSOR_DHT22_HOST_START) { // start signal sent
- gpio_set_mode(TIM_CH_PORT(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, TIM_CH_PIN(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL)); // switch pin to input (the external pull up with also set the signal high)
- sensor_dht22_state = SENSOR_DHT22_HOST_STARTED; // switch to next state
- timer_ic_enable(TIM(SENSOR_DHT22_TIMER), TIM_IC(SENSOR_DHT22_CHANNEL)); // enable capture interrupt only when receiving data
- } else { // timeout occurred
- sensor_dht22_reset(); // reset states
- }
- } else if (timer_get_flag(TIM(SENSOR_DHT22_TIMER), TIM_SR_CCIF(SENSOR_DHT22_CHANNEL))) { // edge detected on input capture
- uint16_t time = TIM_CCR(SENSOR_DHT22_TIMER,SENSOR_DHT22_CHANNEL); // save captured bit timing (this clear also the flag)
- timer_set_counter(TIM(SENSOR_DHT22_TIMER), 0); // reset timer counter
- time = (time * 1E6) / (rcc_ahb_frequency / (TIM_PSC(TIM(SENSOR_DHT22_TIMER)) + 1)); // calculate time in us
- switch (sensor_dht22_state) {
- case (SENSOR_DHT22_HOST_STARTED): // the host query data and the slave is responding
- sensor_dht22_state = SENSOR_DHT22_SLAVE_START; // set new state
- break;
- case (SENSOR_DHT22_SLAVE_START): // the slave sent the start signal
- if (time >= ((80 + 80) * (1 - SENSOR_DHT22_JITTER)) && time <= ((80 + 80) * (1 + SENSOR_DHT22_JITTER))) { // response time should be 80 us low and 80 us high
- sensor_dht22_state = SENSOR_DHT22_SLAVE_BIT; // set new state
- } else {
- goto error;
- }
- break;
- case (SENSOR_DHT22_SLAVE_BIT): // the slave sent a bit
- if (sensor_dht22_bit >= 40) { // no bits should be received after 40 bits
- goto error;
- }
- if (time >= ((50 + 26) * (1 - SENSOR_DHT22_JITTER)) && time <= ((50 + 28) * (1 + SENSOR_DHT22_JITTER))) { // bit 0 time should be 50 us low and 26-28 us high
- sensor_dht22_bits[sensor_dht22_bit / 8] &= ~(1 << (7 - (sensor_dht22_bit % 8))); // clear bit
- } else if (time >= ((50 + 70) * (1 - SENSOR_DHT22_JITTER)) && time <= ((50 + 70) * (1 + SENSOR_DHT22_JITTER))) { // bit 1 time should be 50 us low and 70 us high
- sensor_dht22_bits[sensor_dht22_bit / 8] |= (1 << (7 - (sensor_dht22_bit % 8))); // set bit
- } else {
- goto error;
- }
- sensor_dht22_bit++;
- if (sensor_dht22_bit >= 40) { // all bits received
- sensor_dht22_reset(); // reset states
- sensor_dht22_bit = 40; // signal decoder all bits have been received
- sensor_dht22_measurement_received = true; // signal user all bits have been received
- }
- break;
- default: // unexpected state
-error:
- sensor_dht22_reset(); // reset states
- }
- } else { // no other interrupt should occur
- while (true); // unhandled exception: wait for the watchdog to bite
- }
-}
diff --git a/lib/sensor_dht22.h b/lib/sensor_dht22.h
deleted file mode 100644
index 5c39576..0000000
--- a/lib/sensor_dht22.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/** library to query measurements from Aosong DHT22 (aka. AM2302) temperature and relative humidity sensor
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: timer channel @ref sensor_dht22_timer (add external pull-up resistor)
- */
-#pragma once
-#error not converted for STM32F4
-
-/** a measurement response has been received */
-extern volatile bool sensor_dht22_measurement_received;
-
-/** measurement returned by sensor */
-struct sensor_dht22_measurement_t {
- float humidity; /**< relative humidity in %RH (0-100) */
- float temperature; /**< temperature in °C (-40-80) */
-};
-
-/** setup peripherals to communicate with sensor */
-void sensor_dht22_setup(void);
-/** request measurement from sensor
- * @return request started successfully
- */
-bool sensor_dht22_measurement_request(void);
-/** decode received measurement
- * @return decoded measurement (0xff,0xff if invalid)
- */
-struct sensor_dht22_measurement_t sensor_dht22_measurement_decode(void);
diff --git a/lib/sensor_ds18b20.c b/lib/sensor_ds18b20.c
deleted file mode 100644
index 1ef6a11..0000000
--- a/lib/sensor_ds18b20.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/** library for Maxim DS18B20 digital temperature sensor (using 1-Wire protocol) (code)
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: 1-Wire (timer @ref onewire_master_timer, GPIO @ref onewire_master_gpio)
- * @warning this library does not support parasite power mode and alarms
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdbool.h> // boolean type
-#include <stdlib.h> // size_t definition
-#include <math.h> // NAN definition
-
-/* own libraries */
-#include "global.h" // help macros
-#include "onewire_master.h" // 1-Wire utilities
-#include "sensor_ds18b20.h" // own definitions
-
-/** remember number of DS18B20 sensors on 1-Wire bus for certain functions */
-uint64_t sensors = 0;
-/** remember if only DS18B20 sensors on 1-Wire bus for certain functions */
-bool only = false;
-/** remember code of last sensor **/
-uint64_t last = 0;
-
-void sensor_ds18b20_setup(void)
-{
- onewire_master_setup(); // setup 1-Wire peripheral to communicate with sensors on bus
- sensor_ds18b20_number(); // scan for sensor (remembers sensor number and exclusivity)
-}
-
-uint64_t sensor_ds18b20_number(void)
-{
- sensors = 0; // reset number
- only = true; // reset state
- uint64_t code = 0; // ROM code found (use 0 to start from scratch)
- bool more = true; // save if other additional slaves exist
-
- while (more) { // scan for all 1-Wire slaves
- if (!onewire_master_reset()) { // send reset to start communication
- return 0; // no slave presence detected
- }
- more = onewire_master_rom_search(&code, false); // get next slave ROM code (without alarm)
- if (0 == code) { // error occurred
- return 0;
- }
- if (0x28 == (code & 0xff)) { // family code (8-LSb) for DS18B20 sensors is 0x28
- last = code; // save last found code
- sensors++; // we found an additional sensor
- } else {
- only = false; // we found a slave which is not a sensor
- }
- }
-
- return sensors;
-}
-
-bool sensor_ds18b20_only(void)
-{
- sensor_ds18b20_number(); // this also checks for exclusivity
- return only;
-}
-
-bool sensor_ds18b20_list(uint64_t* code)
-{
- if (!onewire_master_reset()) { // send reset to start communication
- return false; // no slave presence detected
- }
- onewire_master_rom_search(code, false); // get next code
- return (last != *code); // verify if the last has been found
-}
-
-bool sensor_ds18b20_convert(uint64_t code)
-{
- if (0 == code && !only) { // asked for broadcast but there are different slaves on bus
- return false; // broadcast not possible when there are also different slaves on bus
- }
-
- // send reset pulse
- if (!onewire_master_reset()) { // send reset to start communication
- return false; // no slave presence detected
- }
-
- // send ROM command to select slave(s)
- if (0 == code) { // broadcast convert
- if (!onewire_master_rom_skip()) { // select all slaves
- return false; // ROM command failed
- }
- } else {
- if (!onewire_master_rom_match(code)) { // select specific slave
- return false; // ROM command failed
- }
- }
-
- // send convert T function command
- return onewire_master_function_read(0x44, NULL, 0);
-}
-
-float sensor_ds18b20_temperature(uint64_t code)
-{
- if (0 == code && (sensors > 1 || !only)) { // broadcast read requested
- return NAN; // this function is not possible when several sensors or other devices are present
- }
-
- // send reset pulse
- if (!onewire_master_reset()) { // send reset to start communication
- return NAN; // no slave presence detected
- }
-
- // send ROM command to select slave
- if (0 == code) { // broadcast convert
- if (!onewire_master_rom_skip()) { // select all slaves
- return false; // ROM command failed
- }
- } else {
- if (!onewire_master_rom_match(code)) { // select specific slave
- return false; // ROM command failed
- }
- }
-
- // read scratchpad to get temperature (on byte 0 and 1)
- uint8_t scratchpad[9] = {0}; // to store read scratchpad
- if (!onewire_master_function_read(0xbe, scratchpad, sizeof(scratchpad) * 8)) { // read complete scratchpad
- return NAN; // error occurred during read
- }
-
- // verify if data is valid
- if (onewire_master_crc(scratchpad, sizeof(scratchpad))) { // check CRC checksum
- return NAN; // data corrupted
- }
-
- // calculate temperature (stored as int16_t but on 0.125 C steps)
- return ((int16_t)(scratchpad[1] << 8) + scratchpad[0]) / 16.0; // get temperature (on < 16 precision the last bits are undefined, but that doesn't matter for the end result since the lower precision is still provided)
-}
-
-bool sensor_ds18b20_precision(uint64_t code, uint8_t precision)
-{
- if (precision < 9 || precision > 12) { // check input
- return false; // wrong precision value
- }
-
- if (0 == code && !only) { // asked for broadcast but there are different slaves on bus
- return false; // broadcast not possible when there are also different slaves on bus
- }
-
- // send reset pulse
- if (!onewire_master_reset()) { // send reset to start communication
- return false; // no slave presence detected
- }
-
- // send ROM command to select slave(s)
- if (0 == code) { // broadcast convert
- if (!onewire_master_rom_skip()) { // select all slaves
- return false; // ROM command failed
- }
- } else {
- if (!onewire_master_rom_match(code)) { // select specific slave
- return false; // ROM command failed
- }
- }
-
- // read scratchpad to get alarm values (on byte 2 and 3)
- uint8_t scratchpad[9] = {0}; // to store read scratchpad
- if (!onewire_master_function_read(0xbe, scratchpad, sizeof(scratchpad) * 8)) { // read complete scratchpad
- return false; // error occurred during read
- }
-
- // verify if data is valid
- if (onewire_master_crc(scratchpad, sizeof(scratchpad))) { // check CRC checksum
- return false; // data corrupted
- }
-
- // send new configuration (and keep the alarm values)
- uint8_t configuration[3] = {0}; // to store T_HIGH, T_LOW, and configuration
- configuration[0] = scratchpad[2]; // keep T_HIGH
- configuration[1] = scratchpad[3]; // keep T_LOW
- configuration[2] = 0x1f + ((precision - 9) << 5); // set precision bit (R1-R0 on bit 6-5)
- if (!onewire_master_function_write(0x4e, configuration, sizeof(configuration) * 8)) { // write scratchpad with new configuration (all three bytes must be written)
- return false; // error occurred during write
- }
-
- // store new configuration into sensor's EEPROM for retrieval on next power up
- if (!onewire_master_function_read(0x48, NULL, 0)) { // copy scratchpad (to EEPROM)
- return false; // error during copy
- }
-
- return true;
-}
diff --git a/lib/sensor_ds18b20.h b/lib/sensor_ds18b20.h
deleted file mode 100644
index 8b7add7..0000000
--- a/lib/sensor_ds18b20.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/** library for Maxim DS18B20 digital temperature sensor (using 1-Wire protocol)
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: 1-Wire (timer @ref onewire_master_timer, GPIO @ref onewire_master_gpio)
- * @warning this library does not support parasite power mode and alarms
- */
-#pragma once
-
-/** setup 1-Wire peripheral to communicate with sensors on bus */
-void sensor_ds18b20_setup(void);
-/** get number of DS18B20 sensors on bus
- * @return number of DS18B20 sensors on bus
- */
-uint64_t sensor_ds18b20_number(void);
-/** verify if only DS18B20 sensors are on the bus
- * @return if only DS18B20 sensors are on the bus
- */
-bool sensor_ds18b20_only(void);
-/** send all DS18B20 slaves on the bus
- * @param[out] code ROM code for sensor (0 if error occurred)
- * @return if an additional sensors have been detected
- */
-bool sensor_ds18b20_list(uint64_t* code);
-/** start converting (e.g. measuring) temperature
- * @warning conversion time to wait before reading temperature depends on the resolution set (9 bits: 93.75ms, 10 bits: 187.5ms, 11 bits: 375ms, 12 bits: 950ms)
- * @param[in] code ROM code of sensor to start conversion on (0 for all, if only DS18B20 sensors are on the bus)
- * @return if conversion started
- */
-bool sensor_ds18b20_convert(uint64_t code);
-/** get converted temperature
- * @note 85.0 C is the default temperature when no conversion has been performed
- * @param[in] code ROM code of sensor
- * @return temperature (NaN if error)
- */
-float sensor_ds18b20_temperature(uint64_t code);
-/** set conversion precision
- * @param[in] code ROM code of sensor to start conversion on (0 for single DS18B20 sensor are on the bus)
- * @param[in] precision precision in bits (9-12)
- * @return if operation succeeded
- */
-bool sensor_ds18b20_precision(uint64_t code, uint8_t precision);
diff --git a/lib/sensor_max1247.c b/lib/sensor_max1247.c
deleted file mode 100644
index b7b674d..0000000
--- a/lib/sensor_max1247.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/** library to communication with Maxim MAX1247 12-bit 4-channel ADC using SPI
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2020
- * @note peripherals used: SPI @ref sensor_max1247_spi
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <stdbool.h> // boolean utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/spi.h> // SPI library
-
-/* own libraries */
-#include "global.h" // common methods
-#include "sensor_max1247.h" // own definitions
-
-/** @defgroup sensor_max1247_spi SPI peripheral used to communicate with the AS3935
- * @{
- */
-#define SENSOR_MAX1247_SPI 2 /**< SPI peripheral */
-/** @} */
-
-void sensor_max1247_setup(void)
-{
- // setup SPI
- rcc_periph_clock_enable(RCC_SPI_SCK_PORT(SENSOR_MAX1247_SPI)); // enable clock for GPIO peripheral for clock signal
- gpio_set_mode(SPI_SCK_PORT(SENSOR_MAX1247_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(SENSOR_MAX1247_SPI)); // set SCK as output (clock speed will be negotiated later)
- rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(SENSOR_MAX1247_SPI)); // enable clock for GPIO peripheral for MOSI signal
- gpio_set_mode(SPI_MOSI_PORT(SENSOR_MAX1247_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(SENSOR_MAX1247_SPI)); // set MOSI as output
- rcc_periph_clock_enable(RCC_SPI_MISO_PORT(SENSOR_MAX1247_SPI)); // enable clock for GPIO peripheral for MISO signal
- gpio_set_mode(SPI_MISO_PORT(SENSOR_MAX1247_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SPI_MISO_PIN(SENSOR_MAX1247_SPI)); // set MISO as input
- rcc_periph_clock_enable(RCC_SPI_NSS_PORT(SENSOR_MAX1247_SPI)); // enable clock for GPIO peripheral for NSS (CS) signal
- gpio_set_mode(SPI_NSS_PORT(SENSOR_MAX1247_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, SPI_NSS_PIN(SENSOR_MAX1247_SPI)); // set NSS (CS) as output
- rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
- rcc_periph_clock_enable(RCC_SPI(SENSOR_MAX1247_SPI)); // enable clock for SPI peripheral
- spi_reset(SPI(SENSOR_MAX1247_SPI)); // clear SPI values to default
- spi_init_master(SPI(SENSOR_MAX1247_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_64, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); // initialise SPI as master, divide clock by 64 (72E6/64=1125 kHz, max MAX1247 SCK is 2 MHz, maximum SPI PCLK clock is 72 MHz, depending on which SPI is used), set clock polarity to idle low, set clock phase to do bit change on falling edge (polarity depends on clock phase), use 8 bits frames (the control is 8-bit long, and the conversion response 16-bit), use MSb first
- spi_set_full_duplex_mode(SPI(SENSOR_MAX1247_SPI)); // ensure we are in full duplex mode
- spi_enable_software_slave_management(SPI(SENSOR_MAX1247_SPI)); // control NSS (CS) manually
- spi_set_nss_high(SPI(SENSOR_MAX1247_SPI)); // set NSS high (internally) so we can output
- spi_disable_ss_output(SPI(SENSOR_MAX1247_SPI)); // disable NSS output since we control CS manually
- gpio_set(SPI_NSS_PORT(SENSOR_MAX1247_SPI), SPI_NSS_PIN(SENSOR_MAX1247_SPI)); // set CS high to unselect device
- // sadly we can't use the interrupts as events to sleep (WFE) since sleep disables also communication (e.g. going to sleep until Rx buffer is not empty prevents transmission)
- spi_enable(SPI(SENSOR_MAX1247_SPI)); // enable SPI
-}
-
-void sensor_max1247_release(void)
-{
- spi_reset(SPI(SENSOR_MAX1247_SPI));
- spi_disable(SPI(SENSOR_MAX1247_SPI));
- rcc_periph_clock_disable(RCC_SPI(SENSOR_MAX1247_SPI));
- gpio_set_mode(SPI_NSS_PORT(SENSOR_MAX1247_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_NSS_PIN(SENSOR_MAX1247_SPI));
- gpio_set_mode(SPI_MISO_PORT(SENSOR_MAX1247_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_MISO_PIN(SENSOR_MAX1247_SPI));
- gpio_set_mode(SPI_MOSI_PORT(SENSOR_MAX1247_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_MOSI_PIN(SENSOR_MAX1247_SPI));
- gpio_set_mode(SPI_SCK_PORT(SENSOR_MAX1247_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_SCK_PIN(SENSOR_MAX1247_SPI));
-}
-
-uint16_t sensor_max1247_read(uint8_t channel)
-{
- if (channel > 3) { // ensure we read only from one of the 4 available channels
- return UINT16_MAX;
- }
-
- gpio_clear(SPI_NSS_PORT(SENSOR_MAX1247_SPI), SPI_NSS_PIN(SENSOR_MAX1247_SPI)); // set CS low to select device
- const uint8_t channels[4] = { 1, 5, 2, 6 }; // SEL bits corresponding to channel (in single ended mode)
- uint8_t spi_in = spi_xfer(SPI(SENSOR_MAX1247_SPI), 0x8e | (channels[channel] << 4)); // send conversion control (START bit set, unipolar, single ended, internal clock mode)
- sleep_us(8); // wait for conversion to finish (max. 7.5 µs using internal clock)
- spi_in = spi_xfer(SPI(SENSOR_MAX1247_SPI), 0); // read first conversion bytes
- const uint16_t value = (spi_in << 8) + spi_xfer(SPI(SENSOR_MAX1247_SPI), 0); // read second conversion byte
- gpio_set(SPI_NSS_PORT(SENSOR_MAX1247_SPI), SPI_NSS_PIN(SENSOR_MAX1247_SPI)); // set CS high to select device
- if ((value & 0x8000) || (value & 0x0007)) { // ensure it has one leading and 3 trailing zeros
- return UINT16_MAX;
- }
- return value >> 3;
-}
-
diff --git a/lib/sensor_max1247.h b/lib/sensor_max1247.h
deleted file mode 100644
index a0ac002..0000000
--- a/lib/sensor_max1247.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/** library to communication with Maxim MAX1247 12-bit 4-channel ADC using SPI
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2020
- * @note peripherals used: SPI @ref sensor_max1247_spi
- */
-#pragma once
-#error not converted for STM32F4
-
-/** setup peripherals to communicate with sensor
- * @note the sensor configuration will be set to default and powered down
- */
-void sensor_max1247_setup(void);
-/** release peripherals used to communicate with sensor */
-void sensor_max1247_release(void);
-/** read conversion from channel
- * @param[in] channel which of the 4 channels to convert
- * @return 12-bit conversion value (0xffff if error)
- */
-uint16_t sensor_max1247_read(uint8_t channel);
diff --git a/lib/sensor_mlx90614.c b/lib/sensor_mlx90614.c
deleted file mode 100644
index d079c2e..0000000
--- a/lib/sensor_mlx90614.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/** library to communicate with MLX90614 infra-red thermometer
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2020
- * @note peripherals used: GPIO @ref sensor_mlx90614_gpio, I2C @ref i2c_master_i2c
- * @note this library only uses the I²C interface, not the PWM output
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdbool.h> // boolean type
-#include <stdlib.h> // general utilities
-#include <math.h> // NaN definition
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/i2c.h> // I²C library
-
-/* own libraries */
-#include "global.h" // global utilities
-#include "sensor_mlx90614.h" // own definitions
-#include "smbus_master.h" // SMBus utilities
-
-/** @defgroup sensor_mlx90614_gpio GPIO pin used to control the MLX90614
- * @{
- */
-#define SENSOR_MLX90614_SCL PA8 /**< GPIO pin for SMBus SCL, use to send request condition to switch mode from PWM to SMBus (must be the same as used for SMBus communication) */
-/** @} */
-
-/** MLX90614 I²C slave address */
-static uint8_t sensor_mlx90614_slave_addr = 0x5a;
-
-bool sensor_mlx90614_setup(uint8_t slave_addr)
-{
- if (!smbus_master_check_signals()) { // check if there are pull-ups to operate I²C
- return false;
- }
-
- // send request condition to switch to I²C mode
- rcc_periph_clock_enable(GPIO_RCC(SENSOR_MLX90614_SCL)); // enable clock for GPIO port domain
- gpio_mode_setup(GPIO_PORT(SENSOR_MLX90614_SCL), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(SENSOR_MLX90614_SCL)); // set pin as output
- gpio_set_output_options(GPIO_PORT(SENSOR_MLX90614_SCL), GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO_PIN(SENSOR_MLX90614_SCL)); // set pin output as open-drain (should be pulled up by external resistors required for I²C communication
- gpio_clear(GPIO_PORT(SENSOR_MLX90614_SCL), GPIO_PIN(SENSOR_MLX90614_SCL)); // set low to send request condition
- sleep_us(1024 + 500); // SMBus Request is min. 1.024 ms
- gpio_set(GPIO_PORT(SENSOR_MLX90614_SCL), GPIO_PIN(SENSOR_MLX90614_SCL)); // set back high to end request condition
-
- if (slave_addr < 0x80) { // only the least 7-bit are valid (use default address else)
- sensor_mlx90614_slave_addr = slave_addr; // save I²C slave address of MLX90614
- }
- smbus_master_setup(100, true); // setup SMBus with PEC
- uint8_t response[2]; // response is always 2 bytes
- // test if the device is present
- smbus_master_command_read(sensor_mlx90614_slave_addr, 0x20 | 0x0e, response, LENGTH(response)); // I don't know whey, but the PEC for the first transfer is erroneous, maybe because it has some old bits in the calculation buffer
- const enum smbus_master_rc rc = smbus_master_command_read(sensor_mlx90614_slave_addr, 0x20 | 0x0e, response, LENGTH(response)); // read its own slave address
- if (SMBUS_MASTER_RC_NONE != rc) { // read failed
- return false; // could not read from SMBus device
- }
-
- if (sensor_mlx90614_slave_addr != response[0]) { // the used slave address does not match the one in the ROM
- return false; // this is probably not a MLX90614
- }
- return true;
-}
-
-float sensor_mlx90614_temperature_ambient(void)
-{
- uint8_t response[2]; // response is always 2 bytes
- const enum smbus_master_rc rc = smbus_master_command_read(sensor_mlx90614_slave_addr, 0x00 | 0x06, response, LENGTH(response)); // read Ta from RAM
- if (SMBUS_MASTER_RC_NONE != rc) { // read failed
- return NAN;
- }
- const uint16_t temp = response[0] + (response[1] << 8); // low byte is transferred first
- return temp * 0.02 - 273.15; // calculated temperature according to specification 7.7.1
-}
-
-float sensor_mlx90614_temperature_object(void)
-{
- uint8_t response[2]; // response is always 2 bytes
- const enum smbus_master_rc rc = smbus_master_command_read(sensor_mlx90614_slave_addr, 0x00 | 0x07, response, LENGTH(response)); // read Tobj1 from RAM
- if (SMBUS_MASTER_RC_NONE != rc) { // read failed
- return NAN;
- }
- const uint16_t temp = response[0] + (response[1] << 8); // low byte is transferred first
- return temp * 0.02 - 273.15; // calculated temperature according to specification 7.7.1
-}
diff --git a/lib/sensor_mlx90614.h b/lib/sensor_mlx90614.h
deleted file mode 100644
index 7966c18..0000000
--- a/lib/sensor_mlx90614.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/** library to communicate with MLX90614 infra-red thermometer
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2020
- * @note peripherals used: GPIO @ref sensor_mlx90614_gpio, I2C @ref i2c_master_i2c
- * @note this library only uses the I²C interface, not the PWM output
- */
-#pragma once
-
-/** setup I²C bus to communicated with MLX90614 Infra-Red thermometer
- * @param[in] slave_addr I²C slave address of MLX90614 device (least significant 7-bit, 0xff for default)
- * @return if the display setup is successful, else the display is probably not on the I²C bus
- * @warning only one display on the I²C bus is currently supported
- * @note I²C frequency is 100 kHz
- */
-bool sensor_mlx90614_setup(uint8_t slave_addr);
-/** get ambient temperature of sensor
- * @return ambient temperature in °C
- * @note uses internal thermistor
- */
-float sensor_mlx90614_temperature_ambient(void);
-/** get measured object temperature
- * @return object temperature in °C
- * @note uses IR sensor
- */
-float sensor_mlx90614_temperature_object(void);
diff --git a/lib/sensor_pzem.c b/lib/sensor_pzem.c
deleted file mode 100644
index 30f34a4..0000000
--- a/lib/sensor_pzem.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/** library to query measurements from peacefair PZEM-004 and PZEM-004T electricity meter
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: USART @ref sensor_pzem_usart, timer @ref sensor_pzem_timer
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/usart.h> // universal synchronous asynchronous receiver transmitter library
-#include <libopencm3/stm32/timer.h> // timer utilities
-
-/* own libraries */
-#include "sensor_pzem.h" // PZEM electricity meter header and definitions
-#include "global.h" // common methods
-
-/** @defgroup sensor_pzem_usart USART peripheral used for communication with electricity meter
- * @{
- */
-#define SENSOR_PZEM_USART 2 /**< USART peripheral */
-/** @} */
-
-/** @defgroup sensor_pzem_timer timer peripheral used for waiting before sending the next request
- * @{
- */
-#define SENSOR_PZEM_TIMER 2 /**< timer peripheral */
-/** @} */
-
-/* input and output ring buffer, indexes, and available memory */
-static uint8_t rx_buffer[7] = {0}; /**< buffer for received response */
-static volatile uint8_t rx_i = 0; /**< current position of read received data */
-static uint8_t tx_buffer[7] = {0}; /**< buffer for request to transmit */
-static volatile uint8_t tx_i = 0; /**< current position of transmitted data */
-
-volatile bool sensor_pzem_measurement_received = false;
-
-void sensor_pzem_setup(void)
-{
- /* enable USART I/O peripheral */
- rcc_periph_clock_enable(RCC_AFIO); // enable pin alternate function (USART)
- rcc_periph_clock_enable(RCC_USART(SENSOR_PZEM_USART)); // enable clock for USART peripheral
- rcc_periph_clock_enable(RCC_USART_PORT(SENSOR_PZEM_USART)); // enable clock for USART port peripheral
- gpio_set_mode(USART_TX_PORT(SENSOR_PZEM_USART), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USART_TX_PIN(SENSOR_PZEM_USART)); // setup GPIO pin USART transmit
- gpio_set_mode(USART_RX_PORT(SENSOR_PZEM_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, USART_RX_PIN(SENSOR_PZEM_USART)); // setup GPIO pin USART receive
- gpio_set(USART_RX_PORT(SENSOR_PZEM_USART), USART_RX_PIN(SENSOR_PZEM_USART)); // pull up to avoid noise when not connected
-
- /* setup USART parameters for electricity meter: 9600 8N1 */
- usart_set_baudrate(USART(SENSOR_PZEM_USART), 9600); // the electricity meter uses a fixed baud rate of 9600 bps
- usart_set_databits(USART(SENSOR_PZEM_USART), 8);
- usart_set_stopbits(USART(SENSOR_PZEM_USART), USART_STOPBITS_1);
- usart_set_mode(USART(SENSOR_PZEM_USART), USART_MODE_TX_RX);
- usart_set_parity(USART(SENSOR_PZEM_USART), USART_PARITY_NONE);
- usart_set_flow_control(USART(SENSOR_PZEM_USART), USART_FLOWCONTROL_NONE);
-
- nvic_enable_irq(USART_IRQ(SENSOR_PZEM_USART)); // enable the USART interrupt
- usart_enable_rx_interrupt(USART(SENSOR_PZEM_USART)); // enable receive interrupt
- usart_enable(USART(SENSOR_PZEM_USART)); // enable USART
-
- // setup timer to wait for minimal time before next transmission (after previous transmission or reception)
- rcc_periph_clock_enable(RCC_TIM(SENSOR_PZEM_TIMER)); // enable clock for timer block
- rcc_periph_reset_pulse(RST_TIM(SENSOR_PZEM_TIMER)); // reset timer state
- timer_set_mode(TIM(SENSOR_PZEM_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_one_shot_mode(TIM(SENSOR_PZEM_TIMER)); // stop counter after update event (we only need to count down once)
- timer_set_prescaler(TIM(SENSOR_PZEM_TIMER), 550-1); // set the prescaler so this 16 bits timer allows to wait for maximum 500 ms ( 1/(72E6/550/(2**16))=500.62ms )
- timer_set_period(TIM(SENSOR_PZEM_TIMER), 0xffff/2); // the timing is not defined in the specification. I tested until the communication was reliable (all requests get an response)
- timer_clear_flag(TIM(SENSOR_PZEM_TIMER), TIM_SR_UIF); // clear flag
- timer_enable_irq(TIM(SENSOR_PZEM_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
- nvic_enable_irq(NVIC_TIM_IRQ(SENSOR_PZEM_TIMER)); // catch interrupt in service routine
-
- /* reset buffer states */
- tx_i = LENGTH(tx_buffer);
- rx_i = 0;
- sensor_pzem_measurement_received = false;
-}
-
-void sensor_pzem_measurement_request(uint32_t address, enum sensor_pzem_measurement_type_t type)
-{
- if (tx_i<LENGTH(tx_buffer)) { // transmission is ongoing
- return;
- }
- if (type>=SENSOR_PZEM_MAX) { // invalid type
- return;
- }
- tx_buffer[0] = 0xB0+type; // set request nibble and type nibble
- tx_buffer[1] = (address>>24)&0xff; // set address
- tx_buffer[2] = (address>>16)&0xff; // set address
- tx_buffer[3] = (address>>8)&0xff; // set address
- tx_buffer[4] = (address>>0)&0xff; // set address
- tx_buffer[5] = 0; // only used to set alarm
- tx_buffer[6] = 0; // to calculate checksum (sum of all previous bytes)
- for (uint8_t i=0; i<LENGTH(tx_buffer)-1; i++) {
- tx_buffer[6] += tx_buffer[i]; // calculate buffer
- }
- tx_i = 0; // remember we have a message to send
-
- if (TIM_CR1(TIM(SENSOR_PZEM_TIMER))&TIM_CR1_CEN) { // timer is already running
- // at the end of the timer the transmission will start automatically
- } else { // no timer is running
- usart_enable_tx_interrupt(USART(SENSOR_PZEM_USART)); // enable interrupt to start sending bytes
- //usart_send(USART(SENSOR_PZEM_USART),tx_buffer[tx_i++]); // start transmission
- }
-
- sensor_pzem_measurement_received = false; // reset flag
- rx_i = 0; // prepare buffer to receive next measurement
-}
-
-struct sensor_pzem_measurement_t sensor_pzem_measurement_decode(void)
-{
- struct sensor_pzem_measurement_t measurement; // decoded measurement to return
- measurement.valid = false; // wait until the end to ensure validity
- if (rx_i<LENGTH(rx_buffer)) { // buffer is not full, thus no measurement received
- return measurement;
- }
- if ((rx_buffer[0]&0xf0)!=0xa0) { // not a response received
- return measurement;
- }
- if ((rx_buffer[0]&0x0f)>=SENSOR_PZEM_MAX) { // not a valid response type received (actually 4 and 5 are valid, but should not happen when using this code
- return measurement;
- }
- uint8_t checksum = 0; // calculate checksum (sum of all other bytes)
- for (uint8_t i=0; i<LENGTH(rx_buffer)-1; i++) {
- checksum += rx_buffer[i]; // calculate buffer
- }
- if (checksum!=rx_buffer[6]) { // checksum does not match
- return measurement;
- }
- measurement.valid = true; // all checks passed
- measurement.type = rx_buffer[0]&0x0f; // save type
- switch (measurement.type) { // decode value depending on type
- case SENSOR_PZEM_VOLTAGE:
- measurement.value.voltage = ((uint16_t)rx_buffer[1]<<8)+rx_buffer[2]+rx_buffer[3]*0.1;
- break;
- case SENSOR_PZEM_CURRENT:
- measurement.value.current = rx_buffer[2]+rx_buffer[3]*0.01;
- break;
- case SENSOR_PZEM_POWER:
- measurement.value.power = ((uint16_t)rx_buffer[1]<<8)+rx_buffer[2];
- break;
- case SENSOR_PZEM_ENERGY:
- measurement.value.energy = ((uint32_t)rx_buffer[1]<<16)+((uint16_t)rx_buffer[2]<<8)+rx_buffer[3];
- break;
-/* not used in this application
- case SENSOR_PZEM_ADDRESS:
- case SENSOR_PZEM_ALARM:
- break; // no value is returned
-*/
- default:
- measurement.valid = false; // unexpected type
- }
- sensor_pzem_measurement_received = false; // reset flag
- rx_i = 0; // prepare buffer to receive next measurement
- return measurement;
-}
-
-/** USART interrupt service routine called when data has been transmitted or received */
-void USART_ISR(SENSOR_PZEM_USART)(void)
-{
- if (usart_get_flag(USART(SENSOR_PZEM_USART), USART_SR_TXE)) { // data has been transmitted
- if (tx_i<LENGTH(tx_buffer)) { // not all bytes transmitted
- usart_send(USART(SENSOR_PZEM_USART),tx_buffer[tx_i++]); // transmit next byte
- } else { // request transmitted
- usart_disable_tx_interrupt(USART(SENSOR_PZEM_USART)); // disable transmit interrupt
- timer_set_counter(TIM(SENSOR_PZEM_TIMER), 0); // reset timer counter to get preset waiting time
- timer_enable_counter(TIM(SENSOR_PZEM_TIMER)); // start timer between requests
-
- }
- }
- if (usart_get_flag(USART(SENSOR_PZEM_USART), USART_SR_RXNE)) { // data has been received
- if (rx_i<LENGTH(rx_buffer)) { // receiving response
- rx_buffer[rx_i++] = usart_recv(USART(SENSOR_PZEM_USART)); // put received byte in buffer
- if (rx_i>=LENGTH(rx_buffer)) { // buffer full
- sensor_pzem_measurement_received = true; // notify used response has been received
- }
- } else { // previous response not read before receiving the next
- usart_recv(USART(SENSOR_PZEM_USART)); // drop received buffer
- }
- timer_set_counter(TIM(SENSOR_PZEM_TIMER), 0); // reset timer counter to get preset waiting time
- timer_enable_counter(TIM(SENSOR_PZEM_TIMER)); // start timer between requests
- }
-}
-
-/** interrupt service routine called on timeout */
-void TIM_ISR(SENSOR_PZEM_TIMER)(void)
-{
- if (timer_get_flag(TIM(SENSOR_PZEM_TIMER), TIM_SR_UIF)) { // update event happened
- timer_clear_flag(TIM(SENSOR_PZEM_TIMER), TIM_SR_UIF); // clear flag
- if (tx_i<LENGTH(tx_buffer)) { // bytes are waiting to be sent
- usart_enable_tx_interrupt(USART(SENSOR_PZEM_USART)); // enable interrupt to start sending bytes
- }
- }
-}
-
-
diff --git a/lib/sensor_pzem.h b/lib/sensor_pzem.h
deleted file mode 100644
index da791c2..0000000
--- a/lib/sensor_pzem.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/** library to query measurements from peacefair PZEM-004 and PZEM-004T electricity meter
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: USART @ref sensor_pzem_usart, timer @ref sensor_pzem_timer
- */
-#pragma once
-#error not converted for STM32F4
-
-/** a measurement response has been received */
-extern volatile bool sensor_pzem_measurement_received;
-
-/** measurements (and configurations) offered by electricity meter */
-enum sensor_pzem_measurement_type_t {
- SENSOR_PZEM_VOLTAGE = 0,
- SENSOR_PZEM_CURRENT = 1,
- SENSOR_PZEM_POWER = 2,
- SENSOR_PZEM_ENERGY = 3,
-// SENSOR_PZEM_ADDRESS = 4, // this is a setting, not a measurement
-// SENSOR_PZEM_ALARM = 5, // this is a setting, not a measurement
- SENSOR_PZEM_MAX
-};
-
-/** measurement returned by electricity meter */
-struct sensor_pzem_measurement_t {
- enum sensor_pzem_measurement_type_t type; /**< measurement type */
- bool valid; /**< is the measurement valid (e.g. format and checksum are correct) */
- /** possible measurement values */
- union measurement_t {
- float voltage; /**< measured voltage in volts */
- float current; /**< measured current in amperes */
- uint16_t power; /**< measured power in watts */
- uint32_t energy; /**< measured energy in watts/hour (24 bits) */
- } value; /**< measurement value */
-};
-
-/** setup peripherals to communicate with electricity meter */
-void sensor_pzem_setup(void);
-/** request measurement from electricity meter
- * @param[in] address electricity meter device address
- * @param[in] type measurement type to request
- */
-void sensor_pzem_measurement_request(uint32_t address, enum sensor_pzem_measurement_type_t type);
-/** decode received measurement
- * @return decoded measurement (invalid if no new measurement has been received)
- */
-struct sensor_pzem_measurement_t sensor_pzem_measurement_decode(void);
diff --git a/lib/sensor_sdm120.c b/lib/sensor_sdm120.c
deleted file mode 100644
index de591f0..0000000
--- a/lib/sensor_sdm120.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/** library to query measurements from eastron SDM120-ModBus electricity meter
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: USART @ref sensor_sdm120_usart , GPIO @ref sensor_sdm120_gpio , timer @ref sensor_sdm120_timer
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <math.h> // mathematical utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/usart.h> // universal synchronous asynchronous receiver transmitter library
-#include <libopencm3/stm32/timer.h> // timer utilities
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-
-#include "sensor_sdm120.h" // SDM120 electricity meter header and definitions
-#include "global.h" // common methods
-
-/** @defgroup sensor_sdm120_usart USART peripheral used for communication with electricity meter
- * @{
- */
-#define SENSOR_SDM120_USART 3 /**< USART peripheral */
-/** @} */
-
-/** @defgroup sensor_sdm120_gpio GPIO peripheral used for controlling RS-485 adapter
- * @note driver output is enabled on high while receiver output is enabled on low, thus one pin can be used to control both
- * @{
- */
-#define SENSOR_SDM120_REDE_PIN PB12 /**< GPIO pin for RS-485 receiver and driver output enable signal */
-/** @} */
-
-/** @defgroup sensor_sdm120_timer timer peripheral to enforce waiting time between messages
- * @note 60 ms are recommended between messages in SDM630 ModBus protocol implementation and this seem to also apply to SDM120
- * @{
- */
-#define SENSOR_SDM120_TIMER 3 /**< timer number to count time */
-/** @} */
-
-/* input and output ring buffer, indexes, and available memory */
-static uint8_t rx_buffer[9] = {0}; /**< buffer for received response (ModBus response messages can be 2+256+2 long but we will only read up to 2 registers) */
-static volatile uint8_t rx_used = 0; /**< number of received data bytes in buffer */
-static uint8_t tx_buffer[13] = {0}; /**< buffer for request to transmit (ModBus request messages can be 7+256+2 long but we will only write up to 2 registers */
-static volatile uint8_t tx_used = 0; /**< number of byte to transmit */
-
-volatile bool sensor_sdm120_measurement_received = false;
-
-/** the ModBus timeouts to respect for sending messages **/
-static enum timeout_t {
- TIMEOUT_BEGIN = 0, /**< silent time before sending data */
- TIMEOUT_END, /**< silent time after sending data */
- TIMEOUT_BETWEEN, /**< time to wait between messages */
- TIMEOUT_MAX /**< last element (useful to no the number of elements) */
-} timeout; /**< the current timeout used */
-/** current timeout used */
-static uint16_t timeout_times[TIMEOUT_MAX] = {0};
-
-/** SDM120 3xxxx input register start addresses for the measurement types */
-static const uint16_t register_input[] = {
- 0x0000, // 30001 voltage (in volts)
- 0x0006, // 30007 current (in amperes)
- 0x000c, // 30013 active power (in watts)
- 0x0012, // 30019 apparent power (in volt amperes)
- 0x0018, // 30025 reactive power (in volt amperes reactive)
- 0x001e, // 30031 power factor (0-1)
- 0x0046, // 30071 frequency (in hertz)
- 0x0048, // 30073 import active energy (in kWh)
- 0x004a, // 30075 export active energy (in kWh)
- 0x004c, // 30077 import reactive energy (in kVArh)
- 0x004e, // 30079 export reactive energy (in kVArh)
- 0x0156, // 30343 total active energy (in kWh)
- 0x0158 // 30345 total reactive energy (in kVArh)
-};
-
-/** SDM120 4xxxx holding register start addresses for the configuration types */
-static const uint16_t register_holding[] = {
- 0x000c, // relay pulse width (60, 100, or 200 ms)
- 0x0012, // network parity stop (0: 1 stop bit no parity, 1: one stop bit even parity, 2: one stop bit odd parity, 3: two stop bits no parity)
- 0x0014, // meter slave address (1-247)
- 0x001c, // baud rate (0: 2400 bps, 1: 4800 bps, 2: 9600 bps, 5: 1200 bps)
- 0x0056, // pulse 1 output mode (1: import active energy, 2: import+export active energy, 4: export active energy, 5: import reactive energy, 6: import+export reactive energy, 8: export reactive energy)
- 0xf900, // time of scroll display (0-30 s)
- 0xf910, // pulse 1 output (0: 0.001 kWh/imp, 1: 0.01 kWh/imp, 2: 0.1 kWh/imp, 3: 1 kWh/imp)
- 0xf920 // measurement mode (1: total=import, 2: total=import+export, 3: total=import-export)
-};
-
-/** compute CRC for ModBus
- * @note ModBus uses ANSi/IBM 16-bits CRC (with normal polynomial 0x8005, reverse polynomial 0xA001, start value 0xfff)
- * @param[in] buffer data on which to compute the CRC for
- * @param[in] size number of byte to compute the CRC for
- * @return computed CRC checksum
- */
-static uint16_t crc_modbus(uint8_t* buffer, uint8_t size)
-{
- uint16_t crc = 0xffff; // initial value (for ModBus)
- for (uint8_t i = 0; i < size; i++) { // go through every byte
- crc ^= (uint16_t)buffer[i]; // XOR byte
- for (uint8_t b = 0; b < 8; b++) { // go through every bit
- if (crc & 0x0001) { // least significant bit is set (we are using the reverse way)
- crc = (crc >> 1) ^ 0xA001; // // shift to the right (for the next bit) and XOR with (reverse) polynomial
- } else {
- crc >>= 1; // just shift right (for the next bit)
- }
- }
- }
- return crc;
-}
-
-void sensor_sdm120_setup(uint32_t baudrate)
-{
- // enable USART I/O peripheral
- rcc_periph_clock_enable(RCC_AFIO); // enable pin alternate function (USART)
- rcc_periph_clock_enable(RCC_USART_PORT(SENSOR_SDM120_USART)); // enable clock for USART port peripheral
- rcc_periph_clock_enable(RCC_USART(SENSOR_SDM120_USART)); // enable clock for USART peripheral
- gpio_set_mode(USART_TX_PORT(SENSOR_SDM120_USART), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USART_TX_PIN(SENSOR_SDM120_USART)); // setup GPIO pin USART transmit
- gpio_set_mode(USART_RX_PORT(SENSOR_SDM120_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, USART_RX_PIN(SENSOR_SDM120_USART)); // setup GPIO pin USART receive
- gpio_clear(USART_RX_PORT(SENSOR_SDM120_USART), USART_RX_PIN(SENSOR_SDM120_USART)); // pull down to avoid noise when not connected (it will be set low by RS485 chip when RO is enabled)
-
- // setup USART parameters for electricity meter
- usart_set_baudrate(USART(SENSOR_SDM120_USART), baudrate); // get baud rate by scrolling through the measurements on the electricity meter's screen (default 2400)
- usart_set_databits(USART(SENSOR_SDM120_USART), 8);
- usart_set_stopbits(USART(SENSOR_SDM120_USART), USART_STOPBITS_1);
- usart_set_mode(USART(SENSOR_SDM120_USART), USART_MODE_TX_RX);
- usart_set_parity(USART(SENSOR_SDM120_USART), USART_PARITY_NONE); // get parity by scrolling through the measurements on the electricity meter's screen (default none)
- usart_set_flow_control(USART(SENSOR_SDM120_USART), USART_FLOWCONTROL_NONE);
-
- nvic_enable_irq(USART_IRQ(SENSOR_SDM120_USART)); // enable the USART interrupt
- usart_enable_rx_interrupt(USART(SENSOR_SDM120_USART)); // enable receive interrupt
- usart_enable(USART(SENSOR_SDM120_USART)); // enable USART
-
- // setup GPIO
- rcc_periph_clock_enable(GPIO_RCC(SENSOR_SDM120_REDE_PIN)); // enable clock for GPIO peripheral
- gpio_set_mode(GPIO_PORT(SENSOR_SDM120_REDE_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(SENSOR_SDM120_REDE_PIN)); // setup GPIO pin for receiver and driver output enable pin
- gpio_clear(GPIO_PORT(SENSOR_SDM120_REDE_PIN),GPIO_PIN(SENSOR_SDM120_REDE_PIN)); // disable driver output and enable receive output
-
- // setup timer to wait for minimal time before next transmission
- rcc_periph_clock_enable(RCC_TIM(SENSOR_SDM120_TIMER)); // enable clock for timer block
- rcc_periph_reset_pulse(RST_TIM(SENSOR_SDM120_TIMER)); // reset timer state
- timer_set_mode(TIM(SENSOR_SDM120_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_one_shot_mode(TIM(SENSOR_SDM120_TIMER)); // stop counter after update event (we only need to count down once)
- timer_set_prescaler(TIM(SENSOR_SDM120_TIMER), 66 - 1); // set the prescaler so this 16 bits timer allows to wait for 60 ms ( 1/(72E6/66/(2**16))=60.07ms )
- timeout_times[TIMEOUT_BEGIN] = (rcc_ahb_frequency / (TIM_PSC(TIM(SENSOR_SDM120_TIMER)) + 1)) / baudrate / 8 / 2.5; // wait at least 2.5 characters before sending data
- timeout_times[TIMEOUT_END] = (rcc_ahb_frequency / (TIM_PSC(TIM(SENSOR_SDM120_TIMER)) + 1)) / baudrate / 8 / 2.5; // wait at least 2.5 characters after sending data
- timeout_times[TIMEOUT_BETWEEN] = 0.06 * (rcc_ahb_frequency / (TIM_PSC(TIM(SENSOR_SDM120_TIMER)) + 1)); // wait at least 60 ms before sending the next message
- timer_clear_flag(TIM(SENSOR_SDM120_TIMER), TIM_SR_UIF); // clear flag
- timer_enable_irq(TIM(SENSOR_SDM120_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
- nvic_enable_irq(NVIC_TIM_IRQ(SENSOR_SDM120_TIMER)); // catch interrupt in service routine
-
- // reset states
- tx_used = 0;
- rx_used = 0;
- sensor_sdm120_measurement_received = false;
-}
-
-/** send request to electricity meter
- * @param[in] meter_id electricity meter device id (ModBus salve address)
- * @param[in] function ModBus function: 0x03 read two 16 bits holding registers, 0x04 read two 16 bits input registers, 0x10 write two 16 bits holding registers
- * @param[in] address register start point address
- * @param[in] value value to store in holding register (if function 0x10 is used)
- * @return if request is correct and transmission started
- */
-static bool sensor_sdm120_transmit_request(uint8_t meter_id, uint8_t function, uint16_t address, float value)
-{
- if (0 == meter_id) { // broadcast request are not supported
- return false;
- }
- if (function != 0x03 && function != 0x04 && function != 0x10) { // function not supported
- return false;
- }
- if (address % 2) { // even register addresses are not supported by device
- return false;
- }
- while (tx_used) { // transmission is ongoing
- __WFI(); // wait until something happens (transmission ended)
- }
- // build request packet
- uint8_t packet[11]; // buffer to build ModBus message (without error check)
- uint8_t packet_size = 0; // ModBus message size (without error check)
- packet[0] = meter_id; // set slave device address
- packet[1] = function; // set function
- packet[2] = address >> 8; // set high register address
- packet[3] = address; // set low register address
- packet[4] = 0; // set high number of registers to read
- packet[5] = 2; // set low number of register to read (the measurement are encoded using 32 bits IEE745 float, and register hold 16 bits, thus we want to read 2 registers
- if (function == 0x03 || function == 0x04) { // read register
- packet_size = 6; // set message size
- } else if (function == 0x10) { // write register
- packet[6] = 4; // byte count (writing two 16 bits registers)
- // store little endian encoded value in big endian encoded data
- uint8_t* data = (uint8_t*)&value;
- packet[7] = data[3];
- packet[8] = data[2];
- packet[9] = data[1];
- packet[10] = data[0];
- packet_size = 11; // set message size
- }
- uint16_t crc = crc_modbus(packet, packet_size); // compute error check
- for (uint8_t i = 0; i < packet_size; i++) {
- tx_buffer[packet_size-i + 1] = packet[i]; // copy packet to tx buffer in reverse order (this is how sending is implemented)
- }
- tx_buffer[1] = crc; // set low error check
- tx_buffer[0] = crc >> 8; // set high error check
- tx_used = packet_size + 2; // set request size
- rx_used = 0; // reset reset buffer
- sensor_sdm120_measurement_received = false; // reset measurement flag
- while (TIM_CR1(TIM(SENSOR_SDM120_TIMER))&TIM_CR1_CEN) { // timer is already used
- __WFI(); // wait until something happens (timer is available again)
- }
- gpio_set(GPIO_PORT(SENSOR_SDM120_REDE_PIN), GPIO_PIN(SENSOR_SDM120_REDE_PIN)); // enable driver output and disable receive output
- // start timeout
- timeout = TIMEOUT_BEGIN; // select time before sending message
- timer_set_period(TIM(SENSOR_SDM120_TIMER), timeout_times[timeout]); // set corresponding timeout
- timer_set_counter(TIM(SENSOR_SDM120_TIMER), 0); // reset timer counter to get preset waiting time
- timer_enable_counter(TIM(SENSOR_SDM120_TIMER)); // wait
-
- return true;
-}
-
-bool sensor_sdm120_measurement_request(uint8_t meter_id, enum sensor_sdm120_measurement_type_t type)
-{
- if (type >= SENSOR_SDM120_MEASUREMENT_MAX) { // invalid type
- return false;
- }
- return sensor_sdm120_transmit_request(meter_id, 0x04, register_input[type], 0);
-}
-
-bool sensor_sdm120_configuration_request(uint8_t meter_id, enum sensor_sdm120_configuration_type_t type)
-{
- if (type >= SENSOR_SDM120_CONFIGURATION_MAX) { // invalid type
- return false;
- }
- return sensor_sdm120_transmit_request(meter_id, 0x03, register_holding[type], 0);
-}
-
-bool sensor_sdm120_configuration_set(uint8_t meter_id, enum sensor_sdm120_configuration_type_t type, float value)
-{
- if (type >= SENSOR_SDM120_CONFIGURATION_MAX) { // invalid type
- return false;
- }
- return sensor_sdm120_transmit_request(meter_id, 0x10, register_holding[type], value);
-}
-
-float sensor_sdm120_measurement_decode(void)
-{
- float measurement = NAN; // decoded measurement to return (invalid in the beginning)
- if (!sensor_sdm120_measurement_received) { // no measurement received
- return NAN;
- } else {
- sensor_sdm120_measurement_received = false; // reset flag
- }
- if (rx_used < 5) { // not a complete response (minimum is address, function, size/error, error check low, error check high)
- return NAN;
- }
- // a complete message has been received
- if (crc_modbus(rx_buffer,rx_used)) { // checksum error, error check failed
- measurement = NAN;
- } else if (rx_buffer[1] & 0x80) { // error condition received
- measurement = INFINITY; // indicate we received and error
- } else {
- switch (rx_buffer[1]) {
- case 0x03: // read 4xxx holding register response received
- case 0x04: // read 3xxxx input register response received
- if (rx_buffer[2] == 0x04 && rx_used >= (4 + 5)) { // 2 registers received, corresponds to implemented request
- // convert big endian received float value to little endian return value
- uint8_t* convert = (uint8_t*)&measurement;
- convert[0] = rx_buffer[6];
- convert[1] = rx_buffer[5];
- convert[2] = rx_buffer[4];
- convert[3] = rx_buffer[3];
- }
- break;
- case 0x10: // write 4xxx holding register response received
- measurement = (rx_buffer[4] << 8) + rx_buffer[5]; // number of registers written
- break; // not supported currently
- default: // unknown function response received
- measurement = INFINITY;
- break; // nothing to do
- }
- }
- rx_used = 0; // reset rx_buffer usage
- return measurement;
-}
-
-/** USART interrupt service routine called when data has been transmitted or received */
-void USART_ISR(SENSOR_SDM120_USART)(void)
-{
- if (usart_get_flag(USART(SENSOR_SDM120_USART), USART_SR_TXE)) { // data has been transmitted
- if (tx_used) { // not all bytes transmitted
- usart_send(USART(SENSOR_SDM120_USART),tx_buffer[--tx_used]); // transmit next byte (clears flag)
- } else { // all bytes transmitted
- usart_disable_tx_interrupt(USART(SENSOR_SDM120_USART)); // disable transmit interrupt
- USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_TXE; // clear flag
- USART_CR1(USART(SENSOR_SDM120_USART)) |= USART_CR1_TCIE; // enable transfer complete interrupt
- }
- }
- if (usart_get_flag(USART(SENSOR_SDM120_USART), USART_SR_TC)) { // data has been completely transmitted
- USART_CR1(USART(SENSOR_SDM120_USART)) |= USART_CR1_TCIE; // disable transfer complete interrupt
- USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_TC; // clear flag
- timeout = TIMEOUT_END; // select wait time after sending data
- timer_set_period(TIM(SENSOR_SDM120_TIMER), timeout_times[timeout]); // set corresponding timeout
- timer_set_counter(TIM(SENSOR_SDM120_TIMER), 0); // reset timer counter to get preset waiting time
- timer_enable_counter(TIM(SENSOR_SDM120_TIMER)); // wait
- }
- if (usart_get_flag(USART(SENSOR_SDM120_USART), USART_SR_RXNE)) { // data has been received
- if (gpio_get(GPIO_PORT(SENSOR_SDM120_REDE_PIN),GPIO_PIN(SENSOR_SDM120_REDE_PIN))) { // not in receiver mode
- USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_RXNE; // clear flag, ignore received data
- } else if (rx_used<LENGTH(rx_buffer)) { // receiving response
- rx_buffer[rx_used++] = usart_recv(USART(SENSOR_SDM120_USART)); // put received byte in buffer (clears flag)
- if (rx_used == 1 && rx_buffer[0] == 0) { // this is wrong decoding because the signal is going low on idle, which is misinterpreted as start bit (and the 0 broadcast device address is not supported by this device)
- rx_used = 0; // reset buffer
- } else if (rx_used >= 5 && (rx_buffer[1] & 0x80)) { // error condition response received
- sensor_sdm120_measurement_received = true; // notify used response has been received
- } else if (rx_used >= 5 && (uint8_t)(rx_used - 5) >= rx_buffer[2] && (rx_buffer[1] == 0x04 || rx_buffer[1] == 0x03)) { // read input or holding register response received
- sensor_sdm120_measurement_received = true; // notify used response has been receive
- } else if (rx_used >= 8 && rx_buffer[1] == 0x10) { // write holding register response received
- sensor_sdm120_measurement_received = true; // notify used response has been receive
- }
- } else { // buffer full and unknown response received
- USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_RXNE; // clear flag (wait for user to read measurement, this clears the buffer)
- }
- timeout = TIMEOUT_END; // select time after receiving data
- timer_set_period(TIM(SENSOR_SDM120_TIMER), timeout_times[timeout]); // set corresponding timeout
- timer_set_counter(TIM(SENSOR_SDM120_TIMER), 0); // reset timer counter to get preset waiting time
- timer_enable_counter(TIM(SENSOR_SDM120_TIMER)); // wait
- }
-}
-
-/** interrupt service routine called on timeout */
-void TIM_ISR(SENSOR_SDM120_TIMER)(void)
-{
- if (timer_get_flag(TIM(SENSOR_SDM120_TIMER), TIM_SR_UIF)) { // update event happened
- timer_clear_flag(TIM(SENSOR_SDM120_TIMER), TIM_SR_UIF); // clear flag
- // because of the one pulse mode the timer is stopped automatically
- switch (timeout) { // timeout before action passed
- case (TIMEOUT_BEGIN): // we can now send the data
- USART_SR(USART(SENSOR_SDM120_USART)) &= USART_SR_TXE; // clear interrupt flag
- usart_enable_tx_interrupt(USART(SENSOR_SDM120_USART)); // enable interrupt to send other bytes
- usart_send(USART(SENSOR_SDM120_USART), tx_buffer[--tx_used]); // start transmission
- break;
- case (TIMEOUT_END): // we now have to wait before sending the next message
- gpio_clear(GPIO_PORT(SENSOR_SDM120_REDE_PIN), GPIO_PIN(SENSOR_SDM120_REDE_PIN)); // disable driver output (and enable receive output)
- timeout = TIMEOUT_BETWEEN; // select time between sending message
- timer_set_period(TIM(SENSOR_SDM120_TIMER), timeout_times[timeout]); // set corresponding timeout
- timer_set_counter(TIM(SENSOR_SDM120_TIMER), 0); // reset timer counter to get preset waiting time
- timer_enable_counter(TIM(SENSOR_SDM120_TIMER)); // wait
- case (TIMEOUT_BETWEEN): // nothing to do, we are allowed to send the next message
- break;
- default:
- break;
- }
- }
-}
diff --git a/lib/sensor_sdm120.h b/lib/sensor_sdm120.h
deleted file mode 100644
index b5b149e..0000000
--- a/lib/sensor_sdm120.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/** library to query measurements from eastron SDM120-ModBus electricity meter
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: USART @ref sensor_sdm120_usart , GPIO @ref sensor_sdm120_gpio , timer @ref sensor_sdm120_timer
- */
-#pragma once
-#error not converted for STM32F4
-
-/** a measurement response has been received */
-extern volatile bool sensor_sdm120_measurement_received;
-
-/** measurement types offered by electricity meter in 3xxx input registers */
-enum sensor_sdm120_measurement_type_t {
- SENSOR_SDM120_VOLTAGE = 0,
- SENSOR_SDM120_CURRENT,
- SENSOR_SDM120_POWER_ACTIVE,
- SENSOR_SDM120_POWER_APPARENT,
- SENSOR_SDM120_POWER_REACTIVE,
- SENSOR_SDM120_POWER_FACTOR,
- SENSOR_SDM120_FREQUENCY,
- SENSOR_SDM120_ENERGY_ACTIVE_IMPORT,
- SENSOR_SDM120_ENERGY_ACTIVE_EXPORT,
- SENSOR_SDM120_ENERGY_REACTIVE_IMPORT,
- SENSOR_SDM120_ENERGY_REACTIVE_EXPORT,
- SENSOR_SDM120_ENERGY_ACTIVE_TOTAL,
- SENSOR_SDM120_ENERGY_REACTIVE_TOTAL,
- SENSOR_SDM120_MEASUREMENT_MAX
-};
-
-/** configuration types for electricity meter in 4xxx holding registers */
-enum sensor_sdm120_configuration_type_t {
- SENSOR_SDM120_RELAY_PULSE_WIDTH = 0,
- SENSOR_SDM120_NETWORK_PARITY_STOP,
- SENSOR_SDM120_METER_ID,
- SENSOR_SDM120_BAUD_RATE,
- SENSOR_SDM120_PULSE_1_OUTPUT_MODE,
- SENSOR_SDM120_TIME_OF_SCROLL_DISPLAY,
- SENSOR_SDM120_PULSE_1_OUTPUT,
- SENSOR_SDM120_MEASUREMENT_MODE,
- SENSOR_SDM120_CONFIGURATION_MAX
-};
-
-/** setup peripherals to communicate with electricity meter
- * @param[in] baudrate baud rate of RS485 serial communication
- */
-void sensor_sdm120_setup(uint32_t baudrate);
-/** request measurement from electricity meter
- * @param[in] meter_id electricity meter device ID
- * @param[in] type measurement type to request
- * @return if transmission started
- */
-bool sensor_sdm120_measurement_request(uint8_t meter_id, enum sensor_sdm120_measurement_type_t type);
-/** request configuration from electricity meter
- * @param[in] meter_id electricity meter device ID
- * @param[in] type configuration type to request
- * @return if transmission started
- */
-bool sensor_sdm120_configuration_request(uint8_t meter_id, enum sensor_sdm120_configuration_type_t type);
-/** set configuration in electricity meter
- * @param[in] meter_id electricity meter device ID
- * @param[in] type configuration type to set
- * @param[in] value configuration value to set
- * @return if transmission started
- */
-bool sensor_sdm120_configuration_set(uint8_t meter_id, enum sensor_sdm120_configuration_type_t type, float value);
-/** decode received measurement
- * @return decoded measurement or number of registers written, NaN if message has error or no new measurement has been received, infinity if an error or unknown message has been received
- */
-float sensor_sdm120_measurement_decode(void);
diff --git a/lib/sensor_sr04.c b/lib/sensor_sr04.c
deleted file mode 100644
index 20dcc8b..0000000
--- a/lib/sensor_sr04.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/** library to determine range using HC-SR04 ultrasonic range sensor
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2020
- * @note peripherals used: timer @ref sensor_sr04_timer, GPIO @ref sensor_sr04_gpio
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <stdbool.h> // boolean utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/timer.h> // timer utilities
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-
-/* own libraries */
-#include "global.h" // common methods
-#include "sensor_sr04.h" // own definitions
-
-/** @defgroup sensor_sr04_timer timer used to measure echo response length
- * @{
- */
-#define SENSOR_SR04_TIMER 11 /**< timer ID peripheral peripheral */
-#define SENSOR_SR04_CHANNEL 1 /**< timer channel used for echo input capture */
-#define SENSOR_SR04_AF GPIO_AF3 /**< timer alternate function for the capture channel */
-//PB9 TIM11_CH1
-/** @} */
-
-/** @defgroup sensor_sr04_gpio GPIO used to trigger measurement and get echo
- * @{
- */
-#define SENSOR_SR04_TRIGGER PB8 /**< GPIO used to trigger measurement (pulled up to 5V by HC-SR04 module) */
-#define SENSOR_SR04_ECHO PB9 /**< GPIO used to get echo (active high), must be an timer input capture */
-/** @} */
-
-volatile uint16_t sensor_sr04_distance = 0;
-
-/** if an echo has been received */
-static volatile bool sensor_sr04_echo = false;
-
-void sensor_sr04_setup(void)
-{
- // setup trigger GPIO
- rcc_periph_clock_enable(GPIO_RCC(SENSOR_SR04_TRIGGER)); // enable clock for GPIO port domain
- gpio_mode_setup(GPIO_PORT(SENSOR_SR04_TRIGGER), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(SENSOR_SR04_TRIGGER)); // set pin as output
- gpio_set_output_options(GPIO_PORT(SENSOR_SR04_TRIGGER), GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO_PIN(SENSOR_SR04_TRIGGER)); // set pin output as open-drain
- gpio_clear(GPIO_PORT(SENSOR_SR04_TRIGGER), GPIO_PIN(SENSOR_SR04_TRIGGER)); // idle low
-
- // setup echo GPIO
- rcc_periph_clock_enable(GPIO_RCC(SENSOR_SR04_ECHO)); // enable clock for GPIO port domain
- gpio_mode_setup(GPIO_PORT(SENSOR_SR04_ECHO), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(SENSOR_SR04_ECHO)); // set pin to alternate function input capture
- gpio_set_af(GPIO_PORT(SENSOR_SR04_ECHO), SENSOR_SR04_AF, GPIO_PIN(SENSOR_SR04_ECHO)); // set alternate function for input capture
-
- // setup timer
- rcc_periph_clock_enable(RCC_TIM(SENSOR_SR04_TIMER)); // enable clock for timer peripheral
- rcc_periph_reset_pulse(RST_TIM(SENSOR_SR04_TIMER)); // reset timer peripheral to default
- // the timers use clock from APB1 or APB2 (see memory map to figure out), derivate from AHB
- // in case of STM32F401, AHB is max. 84 MHz, APB1 is max. AHB / 2 = 42 MHz but the clock is twice the speed thus 84 MHz, APB2 is max. AHB = 84 MHz
- // for simplicity we use AHB for the calculation, but in fact it could be more complicated
- timer_set_prescaler(TIM(SENSOR_SR04_TIMER), 36 - 1); // set prescaler so we can measure up to 28 ms (1.0 / (84E6 / 36) * 2**16 = 28.1 ms), this above the maximum distance 400 cm (400 cm * 58 us/cm ) = 23200 us, datasheet says the maximum is 25 ms)
- timer_set_mode(TIM(SENSOR_SR04_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // count up
- timer_enable_update_event(TIM(SENSOR_SR04_TIMER)); // use update event to catch the overflow
- timer_update_on_overflow(TIM(SENSOR_SR04_TIMER)); // only set update event on overflow
- timer_one_shot_mode(TIM(SENSOR_SR04_TIMER)); // stop running after overflow
- timer_set_period(TIM(SENSOR_SR04_TIMER), UINT16_MAX); // use full range
-
- // setup input capture
- timer_ic_set_input(TIM(SENSOR_SR04_TIMER), TIM_IC(SENSOR_SR04_CHANNEL), TIM_IC_IN_TI(SENSOR_SR04_CHANNEL)); // configure ICx to use TIn
- timer_ic_set_filter(TIM(SENSOR_SR04_TIMER), TIM_IC(SENSOR_SR04_CHANNEL), TIM_IC_OFF); // use no filter input (precise timing needed)
-
- timer_ic_set_prescaler(TIM(SENSOR_SR04_TIMER), TIM_IC(SENSOR_SR04_CHANNEL), TIM_IC_PSC_OFF); // don't use any prescaler since we want to capture every pulse
- timer_ic_enable(TIM(SENSOR_SR04_TIMER), TIM_IC(SENSOR_SR04_CHANNEL)); // enable input capture
- timer_clear_flag(TIM(SENSOR_SR04_TIMER), TIM_SR_UIF); // clear update flag
- timer_enable_irq(TIM(SENSOR_SR04_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
- timer_clear_flag(TIM(SENSOR_SR04_TIMER), TIM_SR_CCIF(SENSOR_SR04_CHANNEL)); // clear input compare flag
- timer_enable_irq(TIM(SENSOR_SR04_TIMER), TIM_DIER_CCIE(SENSOR_SR04_CHANNEL)); // enable capture interrupt
- nvic_enable_irq(NVIC_TIM_IRQ(SENSOR_SR04_TIMER)); // catch interrupt in service routine
-}
-
-void sensor_sr04_release(void)
-{
- gpio_mode_setup(GPIO_PORT(SENSOR_SR04_TRIGGER), GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN(SENSOR_SR04_TRIGGER)); // release pin
- rcc_periph_reset_pulse(RST_TIM(SENSOR_SR04_TIMER)); // reset timer peripheral to default
- rcc_periph_clock_disable(RCC_TIM(SENSOR_SR04_TIMER)); // enable clock for timer peripheral
-}
-
-void sensor_sr04_trigger(void)
-{
- // prepare timer
- timer_disable_counter(TIM(SENSOR_SR04_TIMER)); // disable timer to prepare it
- timer_clear_flag(TIM(SENSOR_SR04_TIMER), TIM_SR_UIF); // clear update flag
- timer_clear_flag(TIM(SENSOR_SR04_TIMER), TIM_SR_CCIF(SENSOR_SR04_CHANNEL)); // clear input compare flag
- timer_set_counter(TIM(SENSOR_SR04_TIMER), 0); // reset counter
- timer_generate_event(TIM(SENSOR_SR04_TIMER), TIM_EGR_UG); // clear shadow register
- timer_ic_set_polarity(TIM(SENSOR_SR04_TIMER), TIM_IC(SENSOR_SR04_CHANNEL), TIM_IC_RISING); // capture on incoming echo (rising edge)
- sensor_sr04_echo = false; // echo has not been received yet
-
- // send pulse to trigger measurement
- gpio_set(GPIO_PORT(SENSOR_SR04_TRIGGER), GPIO_PIN(SENSOR_SR04_TRIGGER)); // start pull
- sleep_us(10 + 1); // pulse duration
- gpio_clear(GPIO_PORT(SENSOR_SR04_TRIGGER), GPIO_PIN(SENSOR_SR04_TRIGGER)); // end pulse
-
- // start timer to measure the echo (the rest is done in the ISR)
- timer_enable_counter(TIM(SENSOR_SR04_TIMER)); // start timer
-}
-
-/** interrupt service routine called for timer */
-void TIM_ISR(SENSOR_SR04_TIMER)(void)
-{
- if (timer_get_flag(TIM(SENSOR_SR04_TIMER), TIM_SR_UIF)) { // timeout reached
- timer_clear_flag(TIM(SENSOR_SR04_TIMER), TIM_SR_UIF); // clear flag
- if (!sensor_sr04_echo) { // no echo has been received
- sensor_sr04_distance = 1; // provide measurement to user: object is probably too near
- } else {
- sensor_sr04_distance = UINT16_MAX; // provide measurement to user: object is probably too far
- }
- } else if (timer_get_flag(TIM(SENSOR_SR04_TIMER), TIM_SR_CCIF(SENSOR_SR04_CHANNEL))) { // edge detected on input capture
- timer_clear_flag(TIM(SENSOR_SR04_TIMER), TIM_SR_CCIF(SENSOR_SR04_CHANNEL)); // clear input compare flag
- if (!sensor_sr04_echo) { // echo is incoming
- timer_disable_counter(TIM(SENSOR_SR04_TIMER)); // disable while reconfiguring
- timer_set_counter(TIM(SENSOR_SR04_TIMER), 0); // reset timer counter
- timer_generate_event(TIM(SENSOR_SR04_TIMER), TIM_EGR_UG); // clear shadow register
- timer_ic_set_polarity(TIM(SENSOR_SR04_TIMER), TIM_IC(SENSOR_SR04_CHANNEL), TIM_IC_FALLING); // capture on end of echo (falling edge)
- timer_enable_counter(TIM(SENSOR_SR04_TIMER)); // re-enable
- sensor_sr04_echo = true; // remember echo is incoming
- } else { // end of echo
- timer_disable_counter(TIM(SENSOR_SR04_TIMER)); // disable counter now that measurement is complete
- const uint16_t count = TIM_CCR(SENSOR_SR04_TIMER,SENSOR_SR04_CHANNEL); // save captured bit timing (this clear also the flag)
- sensor_sr04_distance =(count * (TIM_PSC(TIM(SENSOR_SR04_TIMER)) + 1) * 343 / 2) / (rcc_ahb_frequency / 1000); // calculate distance and provide result to user
- }
- } else { // no other interrupt should occur
- while (true); // unhandled exception: wait for the watchdog to bite
- }
-}
-
diff --git a/lib/sensor_sr04.h b/lib/sensor_sr04.h
deleted file mode 100644
index e0c7701..0000000
--- a/lib/sensor_sr04.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/** library to determine range using HC-SR04 ultrasonic range sensor
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2020
- * @note peripherals used: timer @ref sensor_sr04_timer, GPIO @ref sensor_sr04_gpio
- */
-#pragma once
-
-/** distance in mm once an echo has been received
- * @note distance set 1 when the object is too near (no echo received)
- * @note distance set UINT16_MAX when the object is too far (echo received to late)
- * @warning to be clear by user
- */
-extern volatile uint16_t sensor_sr04_distance;
-
-/** configure MCU peripherals to communicate with HC-SR04 sensor
- */
-void sensor_sr04_setup(void);
-/** configure MCU peripherals used to communicate with HC-SR04 sensor
- */
-void sensor_sr04_release(void);
-/** trigger measurement
- * @note the resulting measurement will be set in sensor_sr04_distance
- */
-void sensor_sr04_trigger(void);
diff --git a/lib/smbus_master.c b/lib/smbus_master.c
deleted file mode 100644
index 56fad7f..0000000
--- a/lib/smbus_master.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/** library to communicate using SMBus as master
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: I²C/SMBus @ref smbus_master_i2c
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/cm3/systick.h> // SysTick library
-#include <libopencm3/cm3/assert.h> // assert utilities
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/i2c.h> // SMBus library
-
-/* own libraries */
-#include "global.h" // global utilities
-#include "smbus_master.h" // SMBus header and definitions
-
-/** @defgroup smbus_master_i2c I²C/SMBus peripheral used for SMBus communication
- * @{
- */
-#define SMBUS_MASTER_I2C 3 /**< I²C peripheral ID */
-#define SMBUS_MASTER_SCL PA8 /**< GPIO pin for SMBus SCL */
-#define SMBUS_MASTER_SCL_AF GPIO_AF4 /**< GPIO pin alternate funtion for SMBus SCL */
-#define SMBUS_MASTER_SDA PB4 /**< GPIO pin for SMBus SDA */
-#define SMBUS_MASTER_SDA_AF GPIO_AF9 /**< GPIO pin alternate funtion for SMBus SDA */
-/** @} */
-
-/** if Packet Error Code is used */
-static bool smbus_master_pec = false;
-
-void smbus_master_setup(uint8_t frequency, bool pec)
-{
- // configure SMBus peripheral
- rcc_periph_clock_enable(GPIO_RCC(SMBUS_MASTER_SCL)); // enable clock for SMBus I/O peripheral
- gpio_set(GPIO_PORT(SMBUS_MASTER_SCL), GPIO_PIN(SMBUS_MASTER_SCL)); // already put signal high to avoid small pulse
- gpio_mode_setup(GPIO_PORT(SMBUS_MASTER_SCL), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(SMBUS_MASTER_SCL)); // set SCL pin to alternate function
- gpio_set_output_options(GPIO_PORT(SMBUS_MASTER_SCL), GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN(SMBUS_MASTER_SCL)); // set SCL pin output as open-drain
- gpio_set_af(GPIO_PORT(SMBUS_MASTER_SCL), SMBUS_MASTER_SCL_AF, GPIO_PIN(SMBUS_MASTER_SCL)); // set alternate function to SMBus SCL pin
- rcc_periph_clock_enable(GPIO_RCC(SMBUS_MASTER_SDA)); // enable clock for SMBus I/O peripheral
- gpio_set(GPIO_PORT(SMBUS_MASTER_SDA), GPIO_PIN(SMBUS_MASTER_SDA)); // already put signal high to avoid small pulse
- gpio_mode_setup(GPIO_PORT(SMBUS_MASTER_SDA), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(SMBUS_MASTER_SDA)); // set SDA pin to alternate function
- gpio_set_output_options(GPIO_PORT(SMBUS_MASTER_SDA), GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN(SMBUS_MASTER_SDA)); // set SDA pin output as open-drain
- gpio_set_af(GPIO_PORT(SMBUS_MASTER_SDA), SMBUS_MASTER_SDA_AF, GPIO_PIN(SMBUS_MASTER_SDA)); // set alternate function to SMBus SDA pin
- rcc_periph_clock_enable(RCC_I2C(SMBUS_MASTER_I2C)); // enable clock for SMBus peripheral
- i2c_reset(I2C(SMBUS_MASTER_I2C)); // reset peripheral domain
- i2c_peripheral_disable(I2C(SMBUS_MASTER_I2C)); // SMBus needs to be disable to be configured
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) |= I2C_CR1_SWRST; // reset peripheral
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) &= ~I2C_CR1_SWRST; // clear peripheral reset
- if (frequency < 10) { // enforce minimum SMBus frequency
- frequency = 10;
- } else if (frequency > 100) { // enforce maximum SMBus frequency
- frequency = 100;
- }
- i2c_set_clock_frequency(I2C(SMBUS_MASTER_I2C), rcc_apb1_frequency / 1000000); // configure the peripheral clock to the APB1 freq (where it is connected to)
- // use standard mode for frequencies below 100 kHz
- i2c_set_standard_mode(I2C(SMBUS_MASTER_I2C)); // set standard mode (Sm)
- i2c_set_ccr(I2C(SMBUS_MASTER_I2C), rcc_apb1_frequency / (frequency * 1000 * 2)); // set Thigh/Tlow to generate frequency of 100 kHz
- i2c_set_trise(I2C(SMBUS_MASTER_I2C), (1000 / (1000 / (rcc_apb1_frequency / 1000000))) + 1); // max rise time for Sm mode (< 100 kHz) is 1000 ns (~1 MHz)
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) |= I2C_CR1_SMBUS; // set I²C peripheral in SMBus mode (not host type, not using ARP)
- smbus_master_pec = pec; // remember if PEC is used
- if (smbus_master_pec) {
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) |= I2C_CR1_ENPEC; // enable PEC calculation
- }
- i2c_peripheral_enable(I2C(SMBUS_MASTER_I2C)); // enable SMBus after configuration completed
-
-}
-
-void smbus_master_release(void)
-{
- i2c_reset(I2C(SMBUS_MASTER_I2C)); // reset SMBus peripheral configuration
- i2c_peripheral_disable(I2C(SMBUS_MASTER_I2C)); // disable SMBus peripheral
- rcc_periph_clock_disable(RCC_I2C(SMBUS_MASTER_I2C)); // disable clock for SMBus peripheral
- gpio_mode_setup(GPIO_PORT(SMBUS_MASTER_SCL), GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN(SMBUS_MASTER_SCL)); // set SCL pin back to input
- gpio_mode_setup(GPIO_PORT(SMBUS_MASTER_SDA), GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN(SMBUS_MASTER_SDA)); // set SDA pin back to input
-}
-
-bool smbus_master_check_signals(void)
-{
- // enable GPIOs to read SDA and SCL
- rcc_periph_clock_enable(GPIO_RCC(SMBUS_MASTER_SDA)); // enable clock for SMBus I/O peripheral
- rcc_periph_clock_enable(GPIO_RCC(SMBUS_MASTER_SCL)); // enable clock for SMBus I/O peripheral
-
- // pull SDA and SDC low to check if there are pull-up resistors
- const uint32_t sda_moder = GPIO_MODER(GPIO_PORT(SMBUS_MASTER_SDA)); // backup port configuration
- const uint32_t sda_pupdr = GPIO_PUPDR(GPIO_PORT(SMBUS_MASTER_SDA)); // backup port configuration
- const uint32_t scl_moder = GPIO_MODER(GPIO_PORT(SMBUS_MASTER_SCL)); // backup port configuration
- const uint32_t scl_pupdr = GPIO_PUPDR(GPIO_PORT(SMBUS_MASTER_SCL)); // backup port configuration
- gpio_mode_setup(GPIO_PORT(SMBUS_MASTER_SDA), GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN(SMBUS_MASTER_SDA)); // set SDA to input and pull down (weak) to check if there is an external pull up (strong)
- gpio_mode_setup(GPIO_PORT(SMBUS_MASTER_SCL), GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN(SMBUS_MASTER_SCL)); // set SCL to input and pull down (weak) to check if there is an external pull up (strong)
- sleep_us(100); // let signal settle
- const bool to_return = (gpio_get(GPIO_PORT(SMBUS_MASTER_SCL), GPIO_PIN(SMBUS_MASTER_SCL)) && gpio_get(GPIO_PORT(SMBUS_MASTER_SDA), GPIO_PIN(SMBUS_MASTER_SDA))); // check if the signals are still pulled high by external stronger pull-up resistors
- GPIO_MODER(GPIO_PORT(SMBUS_MASTER_SDA)) = sda_moder; // restore port configuration
- GPIO_PUPDR(GPIO_PORT(SMBUS_MASTER_SDA)) = sda_pupdr; // restore port configuration
- GPIO_MODER(GPIO_PORT(SMBUS_MASTER_SCL)) = scl_moder; // restore port configuration
- GPIO_PUPDR(GPIO_PORT(SMBUS_MASTER_SCL)) = scl_pupdr; // restore port configuration
-
- return to_return;
-}
-
-void smbus_master_reset(void)
-{
- i2c_peripheral_disable(I2C(SMBUS_MASTER_I2C)); // disable SMBus peripheral
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) |= I2C_CR1_SWRST; // reset device
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) &= ~I2C_CR1_SWRST; // reset device
- i2c_peripheral_enable(I2C(SMBUS_MASTER_I2C)); // re-enable device
-}
-
-enum smbus_master_rc smbus_master_start(void)
-{
- bool retry = true; // retry after reset if first try failed
- enum smbus_master_rc to_return; // return code
- uint16_t sr1; // read register once, since reading/writing other registers or other events clears some flags
-try:
- to_return = SMBUS_MASTER_RC_NONE; // return code
- // send (re-)start condition
- if (I2C_CR1(I2C(SMBUS_MASTER_I2C)) & (I2C_CR1_START | I2C_CR1_STOP)) { // ensure start or stop operations are not in progress
- return SMBUS_MASTER_RC_START_STOP_IN_PROGESS;
- }
- // prepare timer in case the peripheral hangs on sending stop condition (see errata 2.14.4 Wrong behavior of SMBus peripheral in master mode after a misplaced Stop)
- systick_counter_disable(); // disable SysTick to reconfigure it
- systick_set_frequency(500, rcc_ahb_frequency); // set timer to 2 ms (that should be long enough to send a start condition)
- systick_clear(); // reset SysTick (set to 0)
- systick_interrupt_disable(); // disable interrupt to prevent ISR to read the flag
- systick_get_countflag(); // reset flag (set when counter is going for 1 to 0)
- i2c_send_start(I2C(SMBUS_MASTER_I2C)); // send start condition to start transaction
- bool timeout = false; // remember if the timeout has been reached
- systick_counter_enable(); // start timer
- while ((I2C_CR1(I2C(SMBUS_MASTER_I2C)) & I2C_CR1_START) && !((sr1 = I2C_SR1(I2C(SMBUS_MASTER_I2C))) & (I2C_SR1_BERR | I2C_SR1_ARLO)) && !timeout) { // wait until start condition has been accepted and cleared
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- sr1 = I2C_SR1(I2C(SMBUS_MASTER_I2C)); // be sure to get the current value
- if (sr1 & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- to_return = SMBUS_MASTER_RC_BUS_ERROR;
- }
- while (!((sr1 = I2C_SR1(I2C(SMBUS_MASTER_I2C))) & (I2C_SR1_SB | I2C_SR1_BERR | I2C_SR1_ARLO)) && !timeout && SMBUS_MASTER_RC_NONE == to_return) { // wait until start condition is transmitted
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- sr1 = I2C_SR1(I2C(SMBUS_MASTER_I2C)); // be sure to get the current value
- if (sr1 & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
- to_return = SMBUS_MASTER_RC_BUS_ERROR;
- } else if (!(sr1 & I2C_SR1_SB)) { // the start bit has not been set although we the peripheral is not busy anymore
- to_return = SMBUS_MASTER_RC_BUS_ERROR;
- } else if (!(sr1 & I2C_SR2_MSL)) { // verify if in master mode
- to_return = SMBUS_MASTER_RC_NOT_MASTER;
- } else if (timeout) { // timeout has been reached, i.e. the peripheral hangs
- to_return = SMBUS_MASTER_RC_NOT_MASTER;
- }
-
- if (SMBUS_MASTER_RC_NOT_MASTER == to_return && retry) { // error happened
- retry = false; // don't retry a second time
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) |= I2C_CR1_SWRST; // assert peripheral reset
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) &= ~I2C_CR1_SWRST; // release peripheral reset
- goto try;
- }
- systick_counter_disable(); // we don't need to timer anymore
- return to_return;
-}
-
-/** wait until stop is sent and bus is released
- * @return SMBus return code
- */
-static enum smbus_master_rc smbus_master_wait_stop(void)
-{
- enum smbus_master_rc to_return = SMBUS_MASTER_RC_NONE; // return code
- // prepare timer in case the peripheral hangs on sending stop condition (see errata 2.14.4 Wrong behavior of SMBus peripheral in master mode after a misplaced Stop)
- systick_counter_disable(); // disable SysTick to reconfigure it
- systick_set_frequency(500, rcc_ahb_frequency); // set timer to 2 ms (that should be long enough to send a stop condition)
- systick_clear(); // reset SysTick (set to 0)
- systick_interrupt_disable(); // disable interrupt to prevent ISR to read the flag
- systick_get_countflag(); // reset flag (set when counter is going for 1 to 0)
- bool timeout = false; // remember if the timeout has been reached
- systick_counter_enable(); // start timer
- while ((I2C_CR1(I2C(SMBUS_MASTER_I2C)) & I2C_CR1_STOP) && !(I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) && !timeout) { // wait until stop condition is accepted and cleared
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- if (I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- to_return = SMBUS_MASTER_RC_BUS_ERROR;
- }
- while ((I2C_SR2(I2C(SMBUS_MASTER_I2C)) & I2C_SR2_MSL) && !(I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) && !timeout) { // wait until bus released (non master mode)
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- if (I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- to_return = SMBUS_MASTER_RC_BUS_ERROR;
- }
- while ((I2C_SR2(I2C(SMBUS_MASTER_I2C)) & I2C_SR2_BUSY) && !(I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR)) && !timeout) { // wait until peripheral is not busy anymore
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
- if (I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- to_return = SMBUS_MASTER_RC_BUS_ERROR;
- }
- while ((0 == gpio_get(GPIO_PORT(SMBUS_MASTER_SCL), GPIO_PIN(SMBUS_MASTER_SCL)) || 0 == gpio_get(GPIO_PORT(SMBUS_MASTER_SDA), GPIO_PIN(SMBUS_MASTER_SDA))) && !timeout) { // wait until lines are really high again
- timeout |= systick_get_countflag(); // verify if timeout has been reached
- }
-
- if (timeout) { // I2C_CR1_STOP could also be used to detect a timeout, but I'm not sure when
- if (SMBUS_MASTER_RC_NONE == to_return) {
- to_return = SMBUS_MASTER_RC_TIMEOUT; // indicate timeout only when no more specific error has occurred
- }
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) |= I2C_CR1_SWRST; // assert peripheral reset
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) &= ~I2C_CR1_SWRST; // release peripheral reset
- }
- systick_counter_disable(); // we don't need to timer anymore
- return to_return;
-}
-
-enum smbus_master_rc smbus_master_stop(void)
-{
- // sanity check
- if (!(I2C_SR2(I2C(SMBUS_MASTER_I2C)) & I2C_SR2_BUSY)) { // release if not busy
- return SMBUS_MASTER_RC_NONE; // bus has probably already been released
- }
- if (I2C_CR1(I2C(SMBUS_MASTER_I2C)) & (I2C_CR1_START)) { // ensure start operation is not in progress
- return SMBUS_MASTER_RC_START_STOP_IN_PROGESS; // the stop is sent after a
- }
-
- if (!((I2C_SR2(I2C(SMBUS_MASTER_I2C)) & I2C_SR2_TRA))) { // if we are in receiver mode
- i2c_disable_ack(I2C(SMBUS_MASTER_I2C)); // disable ACK to be able to close the communication
- }
-
- if (!(I2C_CR1(I2C(SMBUS_MASTER_I2C)) & (I2C_CR1_STOP))) { // only send start if not already in progress
- i2c_send_stop(I2C(SMBUS_MASTER_I2C)); // send stop to release bus
- }
- return smbus_master_wait_stop();
-}
-
-enum smbus_master_rc smbus_master_select_slave(uint8_t slave, bool write)
-{
- enum smbus_master_rc rc = SMBUS_MASTER_RC_NONE; // to store SMBus return codes
- uint16_t sr1, sr2; // read register once, since reading/writing other registers or other events clears some flags
-
- if (!((sr1 = I2C_SR1(I2C(SMBUS_MASTER_I2C))) & I2C_SR1_SB)) { // start condition has not been sent
- rc = smbus_master_start(); // send start condition
- if (SMBUS_MASTER_RC_NONE != rc) {
- return rc;
- }
- }
- if (!((sr2 = I2C_SR2(I2C(SMBUS_MASTER_I2C))) & I2C_SR2_MSL)) { // SMBus device is not in master mode
- return SMBUS_MASTER_RC_NOT_MASTER;
- }
-
- // select slave
- I2C_SR1(I2C(SMBUS_MASTER_I2C)) &= ~(I2C_SR1_AF); // clear acknowledgement failure
- i2c_send_7bit_address(I2C(SMBUS_MASTER_I2C), slave, write ? I2C_WRITE : I2C_READ); // select slave, with read/write flag
- while (!((sr1 = I2C_SR1(I2C(SMBUS_MASTER_I2C))) & (I2C_SR1_ADDR | I2C_SR1_AF | I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until address is transmitted
- if (sr1 & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- return SMBUS_MASTER_RC_BUS_ERROR;
- }
- if (sr1 & I2C_SR1_AF) { // address has not been acknowledged
- return SMBUS_MASTER_RC_NAK;
- }
- // do not check I2C_SR2_TRA to verify if we really are in transmit or receive mode since reading SR2 also clears ADDR and starting the read/write transaction
- return SMBUS_MASTER_RC_NONE;
-}
-
-enum smbus_master_rc smbus_master_read(uint8_t* data, size_t data_size)
-{
- // sanity check
- if (NULL == data || 0 == data_size) { // no data to read
- return SMBUS_MASTER_RC_NONE;
- }
- if (smbus_master_pec && SIZE_MAX - 1 < data_size) { // too much data to send (we need one more byte to send the PEC)
- return SMBUS_MASTER_RC_OTHER;
- }
-
- // SMBus start condition check
- uint16_t sr1 = I2C_SR1(I2C(SMBUS_MASTER_I2C)); // read once
- if (!(sr1 & I2C_SR1_ADDR)) { // no slave have been selected
- return SMBUS_MASTER_RC_NOT_READY;
- }
- if (sr1 & I2C_SR1_AF) { // check if the previous transaction went well
- return SMBUS_MASTER_RC_NOT_READY;
- }
-
- // prepare (N)ACK (EV6_3 in RM0008)
- if (1 == data_size) {
- i2c_disable_ack(I2C(SMBUS_MASTER_I2C)); // NACK after first byte
- } else {
- i2c_enable_ack(I2C(SMBUS_MASTER_I2C)); // NAK after next byte
- }
- uint16_t sr2 = I2C_SR2(I2C(SMBUS_MASTER_I2C)); // reading SR2 will also also clear ADDR in SR1 and start the transaction
- if (!(sr2 & I2C_SR2_MSL)) { // SMBus device is not master
- return SMBUS_MASTER_RC_NOT_MASTER;
- }
- if ((sr2 & I2C_SR2_TRA)) { // SMBus device not in receiver mode
- return SMBUS_MASTER_RC_NOT_RECEIVE;
- }
-
- // read data
- if (smbus_master_pec) { // we want to read the PEC
- data_size++; // add one byte to read the PEC
- I2C_SR1(I2C(SMBUS_MASTER_I2C)) &= ~I2C_SR1_PECERR; // clear flag
- }
- for (size_t i = 0; i < data_size; i++) { // read bytes
- // set (N)ACK (EV6_3, EV6_1)
- if (1 == data_size - i) { // prepare to sent NACK for last byte
- i2c_send_stop(I2C(SMBUS_MASTER_I2C)); // already indicate we will send a stop (required to not send an ACK, and this must happen before the byte is transferred, see errata)
- if (smbus_master_pec) {
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) |= I2C_CR1_PEC; // prepare to receive PEC
- }
- i2c_nack_current(I2C(SMBUS_MASTER_I2C)); // (N)ACK current byte
- i2c_disable_ack(I2C(SMBUS_MASTER_I2C)); // NACK received byte to stop slave transmission
- } else if (2 == data_size - i) { // prepare to sent NACK for second last byte
- i2c_nack_next(I2C(SMBUS_MASTER_I2C)); // NACK next byte
- i2c_disable_ack(I2C(SMBUS_MASTER_I2C)); // NACK received byte to stop slave transmission
- } else {
- i2c_enable_ack(I2C(SMBUS_MASTER_I2C)); // ACK received byte to continue slave transmission
- }
- while (!((sr1 = I2C_SR1(I2C(SMBUS_MASTER_I2C))) & (I2C_SR1_RxNE | I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until byte has been received
- if (sr1 & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
- return SMBUS_MASTER_RC_BUS_ERROR;
- }
- if (!smbus_master_pec || i < data_size - 1) { // don't save the PEC
- data[i] = i2c_get_data(I2C(SMBUS_MASTER_I2C)); // read received byte
- }
- }
-
- if (smbus_master_pec) { // check if the PEC is correct
- if (I2C_SR1(I2C(SMBUS_MASTER_I2C)) & I2C_SR1_PECERR) {
- return SMBUS_MASTER_RC_PECERR;
- }
- }
-
- return smbus_master_stop();
-}
-
-enum smbus_master_rc smbus_master_write(const uint8_t* data, size_t data_size)
-{
- // sanity check
- if (NULL == data || 0 == data_size) { // no data to write
- return SMBUS_MASTER_RC_NONE;
- }
-
- // SMBus start condition check
- uint16_t sr1 = I2C_SR1(I2C(SMBUS_MASTER_I2C)); // read once
- if (!(sr1 & I2C_SR1_ADDR)) { // no slave have been selected
- return SMBUS_MASTER_RC_NOT_READY;
- }
- if (sr1 & I2C_SR1_AF) { // check if the previous transaction went well
- return SMBUS_MASTER_RC_NOT_READY;
- }
-
- // master check
- uint16_t sr2 = I2C_SR2(I2C(SMBUS_MASTER_I2C)); // reading SR2 will also also clear ADDR in SR1 and start the transaction
- if (!(sr2 & I2C_SR2_MSL)) { // SMBus device is not master
- return SMBUS_MASTER_RC_NOT_MASTER;
- }
- if (!(sr2 & I2C_SR2_TRA)) { // SMBus device not in transmitter mode
- return SMBUS_MASTER_RC_NOT_TRANSMIT;
- }
-
- // write data
- for (size_t i = 0; i < data_size; i++) { // write bytes
- I2C_SR1(I2C(SMBUS_MASTER_I2C)) &= ~(I2C_SR1_AF); // clear acknowledgement failure
- i2c_send_data(I2C(SMBUS_MASTER_I2C), data[i]); // send byte to be written in memory
- while (!(I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_TxE | I2C_SR1_AF)) && !(I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until byte has been transmitted
- if (I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
- return SMBUS_MASTER_RC_BUS_ERROR;
- }
- if (I2C_SR1(I2C(SMBUS_MASTER_I2C)) & I2C_SR1_AF) { // data has not been acknowledged
- return SMBUS_MASTER_RC_NAK;
- }
- }
-
- return SMBUS_MASTER_RC_NONE;
-}
-
-enum smbus_master_rc smbus_master_slave_read(uint8_t slave, uint8_t* data, size_t data_size)
-{
- enum smbus_master_rc rc = SMBUS_MASTER_RC_NONE; // to store SMBus return codes
- rc = smbus_master_start(); // send (re-)start condition
- if (SMBUS_MASTER_RC_NONE != rc) {
- return rc;
- }
- rc = smbus_master_select_slave(slave, false); // select slave to read
- if (SMBUS_MASTER_RC_NONE != rc) {
- goto error;
- }
- if (NULL != data && data_size > 0) { // only read data if needed
- rc = smbus_master_read(data, data_size); // read data (includes stop)
- if (SMBUS_MASTER_RC_NONE != rc) {
- goto error;
- }
- } else {
- smbus_master_stop(); // sent stop condition
- }
-
- rc = SMBUS_MASTER_RC_NONE; // all went well
-error:
- if (SMBUS_MASTER_RC_NONE != rc) {
- smbus_master_stop(); // sent stop condition
- }
- return rc;
-}
-
-enum smbus_master_rc smbus_master_slave_write(uint8_t slave, const uint8_t* data, size_t data_size)
-{
- enum smbus_master_rc rc = SMBUS_MASTER_RC_NONE; // to store SMBus return codes
- rc = smbus_master_start(); // send (re-)start condition
- if (SMBUS_MASTER_RC_NONE != rc) {
- return rc;
- }
-
- // select slave to write
- rc = smbus_master_select_slave(slave, true);
- if (SMBUS_MASTER_RC_NONE != rc) {
- goto error;
- }
-
- // write data only is some is available
- if (NULL != data && data_size > 0) {
- rc = smbus_master_write(data, data_size); // write data
- if (SMBUS_MASTER_RC_NONE != rc) {
- goto error;
- }
- }
-
- // send optional PEC
- if (smbus_master_pec) {
- I2C_SR1(I2C(SMBUS_MASTER_I2C)) &= ~(I2C_SR1_AF); // clear acknowledgement failure
- I2C_CR1(I2C(SMBUS_MASTER_I2C)) |= I2C_CR1_PEC; // start transmitting PEC
- while ((I2C_CR1(I2C(SMBUS_MASTER_I2C)) & I2C_CR1_PEC) && // PEC is still being transmitted
- !(I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_AF)) && // no NAK received
- !(I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO))); // no bus error received
- if (I2C_SR1(I2C(SMBUS_MASTER_I2C)) & (I2C_SR1_BERR | I2C_SR1_ARLO)) { // bus error has been received
- return SMBUS_MASTER_RC_BUS_ERROR;
- }
- if (I2C_SR1(I2C(SMBUS_MASTER_I2C)) & I2C_SR1_AF) { // no ACK received
- return SMBUS_MASTER_RC_NAK;
- }
- }
-
- rc = SMBUS_MASTER_RC_NONE; // all went well
-error:
- smbus_master_stop(); // sent stop condition
- return rc;
-}
-
-enum smbus_master_rc smbus_master_command_read(uint8_t slave, uint8_t command, uint8_t* data, size_t data_size)
-{
- enum smbus_master_rc rc = SMBUS_MASTER_RC_NONE; // to store SMBus return codes
- rc = smbus_master_start(); // send (re-)start condition
- if (SMBUS_MASTER_RC_NONE != rc) {
- return rc;
- }
- rc = smbus_master_select_slave(slave, true); // select slave to write
- if (SMBUS_MASTER_RC_NONE != rc) {
- goto error;
- }
-
- // write command
- rc = smbus_master_write(&command, 1); // send memory address
- if (SMBUS_MASTER_RC_NONE != rc) {
- goto error;
- }
- // read data
- if (NULL != data && data_size > 0) {
- rc = smbus_master_start(); // send re-start condition
- if (SMBUS_MASTER_RC_NONE != rc) {
- return rc;
- }
- rc = smbus_master_select_slave(slave, false); // select slave to read
- if (SMBUS_MASTER_RC_NONE != rc) {
- goto error;
- }
- rc = smbus_master_read(data, data_size); // read memory (includes stop)
- if (SMBUS_MASTER_RC_NONE != rc) {
- goto error;
- }
- } else {
- smbus_master_stop(); // sent stop condition
- }
-
- rc = SMBUS_MASTER_RC_NONE;
-error:
- if (SMBUS_MASTER_RC_NONE != rc) { // only send stop on error
- smbus_master_stop(); // sent stop condition
- }
- return rc;
-}
-
-enum smbus_master_rc smbus_master_command_write(uint8_t slave, uint8_t command, const uint8_t* data, size_t data_size)
-{
- if (SIZE_MAX - 1 < data_size) { // prevent integer overflow
- return SMBUS_MASTER_RC_OTHER;
- }
- if (data_size > 0 && NULL == data) {
- return SMBUS_MASTER_RC_OTHER;
- }
- uint8_t buffer[1 + data_size]; // single buffer to write command and all data
- buffer[0] = command; // save command in buffer
- if (data) {
- for (size_t i = 0; i < data_size; i++) {
- buffer[1 + i] = data[i];
- }
- }
- return smbus_master_slave_write(slave, buffer, 1 + data_size); // send command and data
-}
diff --git a/lib/smbus_master.h b/lib/smbus_master.h
deleted file mode 100644
index 08466be..0000000
--- a/lib/smbus_master.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/** library to communicate using SMBus as master
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2017-2020
- * @note peripherals used: I²C/SMBus @ref smbus_master_i2c
- * @note SMBus functions not used: alert, ARP; SMBus functions used: PEC
- */
-#pragma once
-
-/** SMBus return codes */
-enum smbus_master_rc {
- SMBUS_MASTER_RC_NONE = 0, /**< no error */
- SMBUS_MASTER_RC_START_STOP_IN_PROGESS, /**< a start or stop condition is already in progress */
- SMBUS_MASTER_RC_NOT_MASTER, /**< not in master mode */
- SMBUS_MASTER_RC_NOT_TRANSMIT, /**< not in transmit mode */
- SMBUS_MASTER_RC_NOT_RECEIVE, /**< not in receive mode */
- SMBUS_MASTER_RC_NOT_READY, /**< slave is not read (previous operations has been NACKed) */
- SMBUS_MASTER_RC_NAK, /**< not acknowledge received */
- SMBUS_MASTER_RC_PECERR, /**< device dais the PER is corrupted */
- SMBUS_MASTER_RC_BUS_ERROR, /**< an error on the SMBus bus occurred */
- SMBUS_MASTER_RC_TIMEOUT, /**< a timeout has occurred because an operation has not completed in the expected time */
- SMBUS_MASTER_RC_OTHER, /** any other error (does not have to be SMBus related) */
-};
-
-/** setup SMBus peripheral
- * @param[in] frequency frequency to use in kHz (10-100)
- * @param[in] pec if Packet Error Code is used
- */
-void smbus_master_setup(uint8_t frequency, bool pec);
-/** release SMBus peripheral
- */
-void smbus_master_release(void);
-/** reset SMBus peripheral, fixing any locked state
- * @warning the SMBus peripheral needs to be re-setup
- * @note to be used after failed start or stop, and bus error
- */
-void smbus_master_reset(void);
-/** check if SDA and SCL signals are pulled up externally
- * @return SDA and SCL signals are pulled up externally
- */
-bool smbus_master_check_signals(void);
-/** send start condition
- * @return SMBus return code
- */
-enum smbus_master_rc smbus_master_start(void);
-/** select SMBus slave device
- * @warning a start condition should be sent before this operation
- * @param[in] slave SMBus 7-bit address of slave device to select
- * @param[in] write this transaction will be followed by a read (false) or write (true) operation
- * @note 10-bit address are not specified by SMBus 3.1
- * @return SMBus return code
- */
-enum smbus_master_rc smbus_master_select_slave(uint8_t slave, bool write);
-/** read data over SMBus
- * @param[out] data array to store bytes read
- * @param[in] data_size number of bytes to read
- * @return SMBus return code
- * @warning the slave device must be selected before this operation
- * @note a stop condition will be sent at the end (I²C peripheral does not permit multiple reads, and this is necessary for 1-byte transfer)
- */
-enum smbus_master_rc smbus_master_read(uint8_t* data, size_t data_size);
-/** write data over SMBus
- * @param[in] data array of byte to write to slave
- * @param[in] data_size number of bytes to write
- * @return SMBus return code
- * @warning the slave device must be selected before this operation
- * @note no stop condition or optional PEC are sent at the end, allowing multiple writes
- */
-enum smbus_master_rc smbus_master_write(const uint8_t* data, size_t data_size);
-/** sent stop condition
- * @return SMBus return code
- */
-enum smbus_master_rc smbus_master_stop(void);
-/** read data from slave device
- * @param[in] slave SMBus 7-bit address of slave device to select
- * @param[out] data array to store bytes read
- * @param[in] data_size number of bytes to read
- * @return SMBus return code
- * @note start and stop conditions, and optional PEC are included
- * @note 10-bit address are not specified by SMBus 3.1
- */
-enum smbus_master_rc smbus_master_slave_read(uint8_t slave, uint8_t* data, size_t data_size);
-/** write data to slave device
- * @param[in] slave SMBus 7-bit address of slave device to select
- * @param[in] data array of byte to write to slave
- * @param[in] data_size number of bytes to write
- * @return SMBus return code
- * @note start and stop conditions, and optional PEC are included
- * @note 10-bit address are not specified by SMBus 3.1
- */
-enum smbus_master_rc smbus_master_slave_write(uint8_t slave, const uint8_t* data, size_t data_size);
-/** read data after sending read command from on an SMBus memory slave
- * @param[in] slave SMBus 7-bit address of slave device to select
- * @param[in] command command code
- * @param[out] data array to store bytes read
- * @param[in] data_size number of bytes to read
- * @return SMBus return code
- * @note start and stop conditions, and optional PEC are included
- * @note 10-bit address are not specified by SMBus 3.1
- */
-enum smbus_master_rc smbus_master_command_read(uint8_t slave, uint8_t command, uint8_t* data, size_t data_size);
-/** write data after sending write command on an SMBus memory slave
- * @param[in] slave SMBus 7-bit address of slave device to select
- * @param[in] command command code
- * @param[in] data array of byte to write to slave
- * @param[in] data_size number of bytes to write
- * @return SMBus return code
- * @note start and stop conditions, and optional PEC are included
- * @note 10-bit address are not specified by SMBus 3.1
- */
-enum smbus_master_rc smbus_master_command_write(uint8_t slave, uint8_t command, const uint8_t* data, size_t data_size);
diff --git a/lib/uart_soft.c b/lib/uart_soft.c
deleted file mode 100644
index 92c12fb..0000000
--- a/lib/uart_soft.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/** library to control up to 4 independent receive and transmit software UART ports
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: GPIO @ref uart_soft_gpio, timer @ref uart_soft_timer
- */
-
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-#include <string.h> // memory utilisites
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/timer.h> // timer library
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-#include <libopencm3/stm32/exti.h> // external interrupt defines
-#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
-
-#include "uart_soft.h" // software UART library API
-#include "global.h" // common methods
-
-/** @defgroup uart_soft_gpio GPIO used for the software 4 UART ports
- * @note comment if unused
- * @warning only one port must be used per line (pin number)
- * @{
- */
-#define UART_SOFT_RX0_GPIO PB14 /**< pin for receive signal for UART port 0 */
-//#define UART_SOFT_RX1_GPIO PA0 /**< pin for receive signal for UART port 1 */
-//#define UART_SOFT_RX2_GPIO PA0 /**< pin for receive signal for UART port 2 */
-//#define UART_SOFT_RX3_GPIO PA0 /**< pin for receive signal for UART port 3 */
-#define UART_SOFT_TX0_GPIO PB13 /**< pin for transmit signal for UART port 0 */
-//#define UART_SOFT_TX1_GPIO PA0 /**< pin for transmit signal for UART port 1 */
-//#define UART_SOFT_TX2_GPIO PA0 /**< pin for transmit signal for UART port 2 */
-//#define UART_SOFT_TX3_GPIO PA0 /**< pin for transmit signal for UART port 3 */
-/** @} */
-
-#if defined(UART_SOFT_RX3_GPIO) || defined(UART_SOFT_TX3_GPIO)
-#define UART_NB 4 /*< number of UART ports */
-#elif defined(UART_SOFT_RX2_GPIO) || defined(UART_SOFT_TX2_GPIO)
-#define UART_NB 3 /*< number of UART ports */
-#elif defined(UART_SOFT_RX1_GPIO) || defined(UART_SOFT_TX1_GPIO)
-#define UART_NB 2 /*< number of UART ports */
-#elif defined(UART_SOFT_RX0_GPIO) || defined(UART_SOFT_TX0_GPIO)
-#define UART_NB 1 /*< number of UART ports */
-#else
-#define UART_NB 0 /*< number of UART ports */
-#endif
-
-/** buffer size for receive and transmit buffers (must be a power of 2) */
-#define UART_SOFT_BUFFER 128
-
-/** UART receive state definition */
-struct soft_uart_rx_state {
- uint32_t port; /**< UART receive port */
- uint16_t pin; /**< UART receive pin */
- uint32_t rcc; /**< UART receive port peripheral clock */
- uint32_t exti; /**< UART receive external interrupt */
- uint32_t irq; /**< UART receive interrupt request */
- uint32_t baudrate; /**< UART receive baud rate (in timer ticks, not bps) */
- volatile uint16_t state; /**< GPIO state for receive pin */
- volatile uint8_t bit; /**< next UART frame bit to receive */
- volatile uint8_t byte; /**< byte being received */
- volatile uint8_t buffer[UART_SOFT_BUFFER]; /**< receive buffer */
- volatile uint8_t buffer_i; /**< index of current data to be read out */
- volatile uint8_t buffer_used; /**< how much data is available */
-
-};
-/** UART transmit state definition */
-struct soft_uart_tx_state {
- uint32_t port; /**< UART receive port */
- uint16_t pin; /**< UART receive pin */
- uint32_t rcc; /**< UART receive port peripheral clock */
- uint32_t baudrate; /**< UART receive baud rate (in timer ticks, not bps) */
- volatile uint8_t bit; /**< next UART frame bit to transmit */
- volatile uint8_t byte; /**< byte being transmitted */
- volatile uint8_t buffer[UART_SOFT_BUFFER]; /**< receive buffer */
- volatile uint8_t buffer_i; /**< index of current data to be read out */
- volatile uint8_t buffer_used; /**< how much data is available */
- volatile bool transmit; /**< flag to know it transmission is ongoing */
-};
-
-static struct soft_uart_rx_state uart_soft_rx_states[UART_NB]; /**< states of UART receive ports */
-static struct soft_uart_tx_state uart_soft_tx_states[UART_NB]; /**< states of UART transmit ports */
-
-volatile bool uart_soft_received[4] = {false, false, false, false};
-
-/** @defgroup uart_soft_timer timer used to sample UART signals
- * @{
- */
-#if defined(UART_SOFT_RX0_GPIO) || defined(UART_SOFT_RX1_GPIO) || defined(UART_SOFT_RX2_GPIO) || defined(UART_SOFT_RX3_GPIO)
- #define UART_SOFT_RX_TIMER 3 /**< timer peripheral for receive signals */
-#endif
-#if defined(UART_SOFT_TX0_GPIO) || defined(UART_SOFT_TX1_GPIO) || defined(UART_SOFT_TX2_GPIO) || defined(UART_SOFT_TX3_GPIO)
- #define UART_SOFT_TX_TIMER 4 /**< timer peripheral for transmit signals */
-#endif
-/** @} */
-
-static const uint32_t timer_flags[4] = {TIM_SR_CC1IF, TIM_SR_CC2IF, TIM_SR_CC3IF, TIM_SR_CC4IF}; /**< the interrupt flags for the compare units */
-static const uint32_t timer_interrupt[4] = {TIM_DIER_CC1IE, TIM_DIER_CC2IE, TIM_DIER_CC3IE, TIM_DIER_CC4IE}; /**< the interrupt enable for the compare units */
-static const enum tim_oc_id timer_oc[4] = {TIM_OC1, TIM_OC2, TIM_OC3, TIM_OC4}; /**< the output compares for the compare units */
-
-bool uart_soft_setup(const uint32_t* rx_baudrates, const uint32_t* tx_baudrates)
-{
- // save UART receive definition
- memset(&uart_soft_rx_states, 0, sizeof(uart_soft_rx_states)); // initialize receiver configuration array
-#if defined(UART_SOFT_RX0_GPIO)
- uart_soft_rx_states[0].port = GPIO_PORT(UART_SOFT_RX0_GPIO); // save receive port
- uart_soft_rx_states[0].pin = GPIO_PIN(UART_SOFT_RX0_GPIO); // save receive pin
- uart_soft_rx_states[0].rcc = GPIO_RCC(UART_SOFT_RX0_GPIO); // save receive port peripheral clock
- uart_soft_rx_states[0].exti = GPIO_EXTI(UART_SOFT_RX0_GPIO); // save receive external interrupt
- uart_soft_rx_states[0].irq = GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX0_GPIO); // save receive interrupt request
-#endif
-#if defined(UART_SOFT_RX1_GPIO)
- uart_soft_rx_states[1].port = GPIO_PORT(UART_SOFT_RX1_GPIO); // save receive port
- uart_soft_rx_states[1].pin = GPIO_PIN(UART_SOFT_RX1_GPIO); // save receive pin
- uart_soft_rx_states[1].rcc = GPIO_RCC(UART_SOFT_RX1_GPIO); // save receive port peripheral clock
- uart_soft_rx_states[1].exti = GPIO_EXTI(UART_SOFT_RX1_GPIO); // save receive external interrupt
- uart_soft_rx_states[1].irq = GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX1_GPIO); // save receive interrupt request
-#endif
-#if defined(UART_SOFT_RX2_GPIO)
- uart_soft_rx_states[2].port = GPIO_PORT(UART_SOFT_RX2_GPIO); // save receive port
- uart_soft_rx_states[2].pin = GPIO_PIN(UART_SOFT_RX2_GPIO); // save receive pin
- uart_soft_rx_states[2].rcc = GPIO_RCC(UART_SOFT_RX2_GPIO); // save receive port peripheral clock
- uart_soft_rx_states[2].exti = GPIO_EXTI(UART_SOFT_RX2_GPIO); // save receive external interrupt
- uart_soft_rx_states[2].irq = GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX2_GPIO); // save receive interrupt request
-#endif
-#if defined(UART_SOFT_RX3_GPIO)
- uart_soft_rx_states[3].port = GPIO_PORT(UART_SOFT_RX3_GPIO); // save receive port
- uart_soft_rx_states[3].pin = GPIO_PIN(UART_SOFT_RX3_GPIO); // save receive pin
- uart_soft_rx_states[3].rcc = GPIO_RCC(UART_SOFT_RX3_GPIO); // save receive port peripheral clock
- uart_soft_rx_states[3].exti = GPIO_EXTI(UART_SOFT_RX3_GPIO); // save receive external interrupt
- uart_soft_rx_states[3].irq = GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX3_GPIO); // save receive interrupt request
-#endif
-
- // setup UART receive GPIO
- for (uint8_t rx = 0; rx < UART_NB; rx++) {
- if (0 == uart_soft_rx_states[rx].port) { // verify is receive UART is defined
- continue; // skip configuration if not defined
- }
- if (!rx_baudrates || 0 == rx_baudrates[rx]) { // verify if receive baud rate has been defined
- return false;
- }
- uart_soft_rx_states[rx].baudrate = rcc_ahb_frequency / rx_baudrates[rx] - 1; // save baud rate
- rcc_periph_clock_enable(uart_soft_rx_states[rx].rcc); // enable clock for GPIO peripheral
- gpio_set(uart_soft_rx_states[rx].port, uart_soft_rx_states[rx].pin); // pull up to avoid noise when not connected
- gpio_set_mode(uart_soft_rx_states[rx].port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, uart_soft_rx_states[rx].pin); // setup GPIO pin UART receive
- rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
- exti_select_source(uart_soft_rx_states[rx].exti, uart_soft_rx_states[rx].port); // mask external interrupt of this pin only for this port
- exti_enable_request(uart_soft_rx_states[rx].exti); // enable external interrupt
- exti_set_trigger(uart_soft_rx_states[rx].exti, EXTI_TRIGGER_BOTH); // trigger when button is pressed
- nvic_enable_irq(uart_soft_rx_states[rx].irq); // enable interrupt
- uart_soft_rx_states[rx].state = gpio_get(uart_soft_rx_states[rx].port, uart_soft_rx_states[rx].pin); // save state of GPIO
- uart_soft_rx_states[rx].bit = 0; // reset bits received
- }
-
- // save UART transmit definition
- memset(&uart_soft_tx_states, 0, sizeof(uart_soft_tx_states)); // initialize transmitter configuration array
-#if defined(UART_SOFT_TX0_GPIO)
- uart_soft_tx_states[0].port = GPIO_PORT(UART_SOFT_TX0_GPIO); // save receive port
- uart_soft_tx_states[0].pin = GPIO_PIN(UART_SOFT_TX0_GPIO); // save receive pin
- uart_soft_tx_states[0].rcc = GPIO_RCC(UART_SOFT_TX0_GPIO); // save receive port peripheral clock
-#endif
-#if defined(UART_SOFT_TX1_GPIO)
- uart_soft_tx_states[1].port = GPIO_PORT(UART_SOFT_TX1_GPIO); // save receive port
- uart_soft_tx_states[1].pin = GPIO_PIN(UART_SOFT_TX1_GPIO); // save receive pin
- uart_soft_tx_states[1].rcc = GPIO_RCC(UART_SOFT_TX1_GPIO); // save receive port peripheral clock
-#endif
-#if defined(UART_SOFT_TX2_GPIO)
- uart_soft_tx_states[2].port = GPIO_PORT(UART_SOFT_TX2_GPIO); // save receive port
- uart_soft_tx_states[2].pin = GPIO_PIN(UART_SOFT_TX2_GPIO); // save receive pin
- uart_soft_tx_states[2].rcc = GPIO_RCC(UART_SOFT_TX2_GPIO); // save receive port peripheral clock
-#endif
-#if defined(UART_SOFT_TX3_GPIO)
- uart_soft_tx_states[3].port = GPIO_PORT(UART_SOFT_TX3_GPIO); // save receive port
- uart_soft_tx_states[3].pin = GPIO_PIN(UART_SOFT_TX3_GPIO); // save receive pin
- uart_soft_tx_states[3].rcc = GPIO_RCC(UART_SOFT_TX3_GPIO); // save receive port peripheral clock
-#endif
-
- // setup UART transmit GPIO
- for (uint8_t tx = 0; tx < UART_NB; tx++) {
- if (0 == uart_soft_tx_states[tx].port) { // verify is transmit UART is defined
- continue; // skip configuration if not defined
- }
- if (!tx_baudrates || 0 == tx_baudrates[tx]) { // verify if transmit baud rate has been defined
- return false;
- }
- uart_soft_tx_states[tx].baudrate = rcc_ahb_frequency / tx_baudrates[tx] - 1; // save baud rate
- rcc_periph_clock_enable(uart_soft_tx_states[tx].rcc); // enable clock for GPIO peripheral
- gpio_set_mode(uart_soft_tx_states[tx].port, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, uart_soft_tx_states[tx].pin); // setup GPIO UART transmit pin
- gpio_set(uart_soft_tx_states[tx].port, uart_soft_tx_states[tx].pin); // idle high
- }
-
- rcc_periph_clock_enable(GPIO_RCC(PB12));
- gpio_set_mode(GPIO_PORT(PB12), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(PB12));
-
- // setup timer
-#if defined(UART_SOFT_RX_TIMER)
- rcc_periph_clock_enable(RCC_TIM(UART_SOFT_RX_TIMER)); // enable clock for timer peripheral
- rcc_periph_reset_pulse(RST_TIM(UART_SOFT_RX_TIMER)); // reset timer state
- timer_set_mode(TIM(UART_SOFT_RX_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(UART_SOFT_RX_TIMER), 0); // prescaler to be able to sample 2400-115200 bps (72MHz/2^16=1099<2400bps)
- nvic_enable_irq(NVIC_TIM_IRQ(UART_SOFT_RX_TIMER)); // allow interrupt for timer
- timer_enable_counter(TIM(UART_SOFT_RX_TIMER)); // start timer to generate interrupts for the receive pins
-#endif
-#if defined(UART_SOFT_TX_TIMER)
- rcc_periph_clock_enable(RCC_TIM(UART_SOFT_TX_TIMER)); // enable clock for timer peripheral
- rcc_periph_reset_pulse(RST_TIM(UART_SOFT_TX_TIMER)); // reset timer state
- timer_set_mode(TIM(UART_SOFT_TX_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(UART_SOFT_TX_TIMER), 0); // prescaler to be able to output 2400-115200 bps (72MHz/2^16=1099<2400bps)
- nvic_enable_irq(NVIC_TIM_IRQ(UART_SOFT_TX_TIMER)); // allow interrupt for timer
- timer_enable_counter(TIM(UART_SOFT_TX_TIMER)); // start timer to generate interrupts for the transmit pins
-#endif
-
- return true; // setup completed
-}
-
-#if defined(UART_SOFT_RX_TIMER)
-uint8_t uart_soft_getbyte(uint8_t uart)
-{
- if (uart >= UART_NB || 0 == uart_soft_rx_states[uart].port) { // ensure receive UART port is defined
- return 0;
- }
- if (0 == uart_soft_rx_states[uart].buffer_used) { // there is no data in the buffer
- return 0;
- }
- nvic_disable_irq(uart_soft_rx_states[uart].irq); // disable interrupt to protect the state of the buffer (interrupt can still get pending)
- uint8_t to_return = uart_soft_rx_states[uart].buffer[uart_soft_rx_states[uart].buffer_i]; // get the next available character
- uart_soft_rx_states[uart].buffer_i = (uart_soft_rx_states[uart].buffer_i + 1) & (LENGTH(uart_soft_rx_states[uart].buffer) - 1); // update used buffer
- uart_soft_rx_states[uart].buffer_used--; // update used buffer
- nvic_enable_irq(uart_soft_rx_states[uart].irq); // re-enable interrupt since critical part is finished
- uart_soft_received[uart] = (0 != uart_soft_rx_states[uart].buffer_used); // notify user if data is available
- return to_return;
-}
-
-/** timer interrupt service routine to generate parse receive signal */
-void TIM_ISR(UART_SOFT_RX_TIMER)(void)
-{
- for (uint8_t rx = 0; rx < UART_NB; rx++) {
- if (timer_interrupt_source(TIM(UART_SOFT_RX_TIMER), timer_flags[rx])) { // got a match on compare for receive pin
- timer_clear_flag(TIM(UART_SOFT_RX_TIMER), timer_flags[rx]); // clear flag
- if (0 == uart_soft_rx_states[rx].port) { // verify if RX exists
- continue; // skip if receive port is not defined it
- }
- gpio_toggle(GPIO_PORT(PB12), GPIO_PIN(PB12));
- uart_soft_rx_states[rx].byte += ((0 == gpio_get(uart_soft_rx_states[rx].port, uart_soft_rx_states[rx].pin) ? 0 : 1) << (uart_soft_rx_states[rx].bit - 1)); // save bit value
- if (uart_soft_rx_states[rx].bit < 8) { // not the last bit received
- timer_set_oc_value(TIM(UART_SOFT_RX_TIMER), timer_oc[rx], timer_get_counter(TIM(UART_SOFT_RX_TIMER)) + uart_soft_rx_states[rx].baudrate); // set timer to next bit
- uart_soft_rx_states[rx].bit++; // wait for next bit
- } else { // last bit received
- if (uart_soft_rx_states[rx].buffer_used >= LENGTH(uart_soft_rx_states[rx].buffer)) { // buffer is full
- uart_soft_rx_states[rx].buffer_i = (uart_soft_rx_states[rx].buffer_i + 1) & (LENGTH(uart_soft_rx_states[rx].buffer) - 1); // drop oldest byte
- uart_soft_rx_states[rx].buffer_used--; // update buffer usage
- }
- uart_soft_rx_states[rx].buffer[(uart_soft_rx_states[rx].buffer_i + uart_soft_rx_states[rx].buffer_used) & (LENGTH(uart_soft_rx_states[rx].buffer) - 1)] = uart_soft_rx_states[rx].byte; // put byte in buffer
- uart_soft_rx_states[rx].buffer_used++; // update used buffer
- uart_soft_received[rx] = true; // notify user data is available
- timer_disable_irq(TIM(UART_SOFT_RX_TIMER), timer_interrupt[rx]); // stop interrupting
- uart_soft_rx_states[rx].bit = 0; // next bit should be first bit of next byte
- }
- }
- }
-}
-#endif
-
-#if defined(UART_SOFT_TX_TIMER)
-void uart_soft_flush(uint8_t uart)
-{
- if (uart >= UART_NB || 0 == uart_soft_tx_states[uart].port) { // ensure transmit UART port is defined
- return; // return
- }
- while (uart_soft_tx_states[uart].buffer_used) { // idle until buffer is empty
- __WFI(); // sleep until interrupt
- }
- while (uart_soft_tx_states[uart].transmit) { // idle until transmission is complete
- __WFI(); // sleep until interrupt
- }
-}
-
-/** start transmitting a byte from the buffer
- * @param[in] uart UART port used for transmission
- */
-static void uart_soft_transmit(uint8_t uart) {
- if (uart >= UART_NB || 0 == uart_soft_tx_states[uart].port) { // ensure transmit UART port is defined
- return; // UART transmit port not defined
- }
- if (uart_soft_tx_states[uart].transmit) { // already transmitting
- return; // transmission is already ongoing
- }
- if (!uart_soft_tx_states[uart].buffer_used) { // no buffered data to transmit
- return; // nothing to transmit
- }
- timer_disable_irq(TIM(UART_SOFT_TX_TIMER), timer_interrupt[uart]); // disable interrupt to protect the state of the buffer (interrupt can still get pending)
- uart_soft_tx_states[uart].byte = uart_soft_tx_states[uart].buffer[uart_soft_tx_states[uart].buffer_i]; // get byte
- uart_soft_tx_states[uart].buffer_i = (uart_soft_tx_states[uart].buffer_i + 1) & (LENGTH(uart_soft_tx_states[uart].buffer) - 1); // update index
- uart_soft_tx_states[uart].buffer_used--; // update used buffer
- uart_soft_tx_states[uart].bit = 0; // LSb is transmitted first
- uart_soft_tx_states[uart].transmit = true; // start transmission
- gpio_clear(uart_soft_tx_states[uart].port, uart_soft_tx_states[uart].pin); // output start bit
- timer_set_oc_value(TIM(UART_SOFT_TX_TIMER), timer_oc[uart], timer_get_counter(TIM(UART_SOFT_TX_TIMER)) + uart_soft_tx_states[uart].baudrate); // set timer to output UART frame 1 (data bit 0) in 1 bit
- timer_clear_flag(TIM(UART_SOFT_TX_TIMER), timer_flags[uart]); // clear flag before enabling interrupt
- timer_enable_irq(TIM(UART_SOFT_TX_TIMER), timer_interrupt[uart]); // enable timer IRQ for TX for this UART
-}
-
-void uart_soft_putbyte_nonblocking(uint8_t uart, uint8_t byte)
-{
- if (uart >= UART_NB || 0 == uart_soft_tx_states[uart].port) { // ensure transmit UART port is defined
- return; // return
- }
- while (uart_soft_tx_states[uart].buffer_used >= LENGTH(uart_soft_tx_states[uart].buffer)); // wait until there is place in the buffer
- timer_disable_irq(TIM(UART_SOFT_TX_TIMER), timer_interrupt[uart]); // disable interrupt to protect the state of the buffer (interrupt can still get pending)
- uart_soft_tx_states[uart].buffer[(uart_soft_tx_states[uart].buffer_i + uart_soft_tx_states[uart].buffer_used) & (LENGTH(uart_soft_tx_states[uart].buffer) - 1)] = byte; // save byte to be transmitted
- uart_soft_tx_states[uart].buffer_used++; // update used buffer
- timer_enable_irq(TIM(UART_SOFT_TX_TIMER), timer_interrupt[uart]); // re-enable interrupts to resume transmission
- uart_soft_transmit(uart); // start transmission
-}
-
-void uart_soft_putbyte_blocking(uint8_t uart, uint8_t byte)
-{
- if (uart >= UART_NB || 0 == uart_soft_tx_states[uart].port) { // ensure transmit UART port is defined
- return; // return
- }
- uart_soft_putbyte_nonblocking(uart, byte); // put byte in queue
- uart_soft_flush(uart); // wait for all byte to be transmitted
-}
-
-/** timer interrupt service routine to transmit data */
-void TIM_ISR(UART_SOFT_TX_TIMER)(void)
-{
- for (uint8_t tx = 0; tx < UART_NB; tx++) {
- if (timer_interrupt_source(TIM(UART_SOFT_TX_TIMER), timer_flags[tx])) { // got a match on compare for transmit pin
- timer_clear_flag(TIM(UART_SOFT_TX_TIMER), timer_flags[tx]); // clear flag
- if (0 == uart_soft_tx_states[tx].port) { // verify if transmit is defined
- continue; // skip if transmit port is not defined it
- }
- if (uart_soft_tx_states[tx].bit < 8) { // there is a data bit to transmit
- if ((uart_soft_tx_states[tx].byte >> uart_soft_tx_states[tx].bit) & 0x01) { // bit to transmit is a 1
- gpio_set(uart_soft_tx_states[tx].port, uart_soft_tx_states[tx].pin); // set output to high
- } else { // bit to transmit is a 0
- gpio_clear(uart_soft_tx_states[tx].port, uart_soft_tx_states[tx].pin); // set output to low
- }
- timer_set_oc_value(TIM(UART_SOFT_TX_TIMER), timer_oc[tx], timer_get_counter(TIM(UART_SOFT_TX_TIMER)) + uart_soft_tx_states[tx].baudrate); // wait for the next frame bit
- uart_soft_tx_states[tx].bit++; // go to next bit
- } else if (8 == uart_soft_tx_states[tx].bit) { // transmit stop bit
- gpio_set(uart_soft_tx_states[tx].port, uart_soft_tx_states[tx].pin); // go idle high
- timer_set_oc_value(TIM(UART_SOFT_TX_TIMER), timer_oc[tx], timer_get_counter(TIM(UART_SOFT_TX_TIMER)) + uart_soft_tx_states[tx].baudrate); // wait for 1 stop bit
- uart_soft_tx_states[tx].bit++; // go to next bit
- } else { // UART frame is complete
- timer_disable_irq(TIM(UART_SOFT_TX_TIMER), timer_interrupt[tx]);// enable timer IRQ for TX for this UART
- uart_soft_tx_states[tx].transmit = false; // transmission finished
- uart_soft_transmit(tx); // start next transmission (if there is)
- }
- } // compare match
- } // go through UARTs
-}
-#endif
-
-/** central function handling receive signal activity */
-static void uart_soft_receive_activity(void)
-{
- for (uint8_t rx = 0; rx < UART_NB; rx++) {
- if (0 == uart_soft_rx_states[rx].port) { // verify if receive port is not configured
- continue; // skip if receive port is not defined it
- }
- const uint16_t state_new = gpio_get(uart_soft_rx_states[rx].port, uart_soft_rx_states[rx].pin); // get new state
- if (uart_soft_rx_states[rx].state != state_new) { // only do something if state changed
- uart_soft_rx_states[rx].state = state_new; // save new state
- if (0 == uart_soft_rx_states[rx].bit) { // start bit edge detected
- if (0 == uart_soft_rx_states[rx].state) { // start bit has to be low
- timer_set_oc_value(TIM(UART_SOFT_RX_TIMER), timer_oc[rx], timer_get_counter(TIM(UART_SOFT_RX_TIMER)) + (uart_soft_rx_states[rx].baudrate) * 3 / 2); // set timer to sample data bit 0 in 1.5 bits
- timer_clear_flag(TIM(UART_SOFT_RX_TIMER), timer_flags[rx]); // clear flag before enabling interrupt
- timer_enable_irq(TIM(UART_SOFT_RX_TIMER), timer_interrupt[rx]);// enable timer IRQ for RX for this UART
- uart_soft_rx_states[rx].byte = 0; // reset byte value
- uart_soft_rx_states[rx].bit = 1; // wait for first bit
- }
- } else { // data bit detected
- timer_set_oc_value(TIM(UART_SOFT_RX_TIMER), timer_oc[rx], timer_get_counter(TIM(UART_SOFT_RX_TIMER)) + (uart_soft_rx_states[rx].baudrate) / 2); // resync timer to half a bit (good for drifting transmission, bad if the line is noisy)
- }
- }
- }
-}
-
-/** GPIO interrupt service routine to detect UART receive activity */
-#if (defined(UART_SOFT_RX0_GPIO) && NVIC_EXTI0_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX0_GPIO)) || (defined(UART_SOFT_RX1_GPIO) && NVIC_EXTI0_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX1_GPIO)) || (defined(UART_SOFT_RX2_GPIO) && NVIC_EXTI0_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX2_GPIO)) || (defined(UART_SOFT_RX3_GPIO) && NVIC_EXTI0_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX3_GPIO))
-void exti0_isr(void)
-{
- exti_reset_request(EXTI0); // clear interrupt flag for pin triggers this ISR (pin state will be checked independently)
- uart_soft_receive_activity(); // check which GPIO changed
-}
-#endif
-#if (defined(UART_SOFT_RX0_GPIO) && NVIC_EXTI1_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX0_GPIO)) || (defined(UART_SOFT_RX1_GPIO) && NVIC_EXTI1_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX1_GPIO)) || (defined(UART_SOFT_RX2_GPIO) && NVIC_EXTI1_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX2_GPIO)) || (defined(UART_SOFT_RX3_GPIO) && NVIC_EXTI1_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX3_GPIO))
-void exti1_isr(void)
-{
- exti_reset_request(EXTI1); // clear interrupt flag for pin triggers this ISR (pin state will be checked independently)
- uart_soft_receive_activity(); // check which GPIO changed
-}
-#endif
-#if (defined(UART_SOFT_RX0_GPIO) && NVIC_EXTI2_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX0_GPIO)) || (defined(UART_SOFT_RX1_GPIO) && NVIC_EXTI2_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX1_GPIO)) || (defined(UART_SOFT_RX2_GPIO) && NVIC_EXTI2_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX2_GPIO)) || (defined(UART_SOFT_RX3_GPIO) && NVIC_EXTI2_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX3_GPIO))
-void exti2_isr(void)
-{
- exti_reset_request(EXTI2); // clear interrupt flag for pin triggers this ISR (pin state will be checked independently)
- uart_soft_receive_activity(); // check which GPIO changed
-}
-#endif
-#if (defined(UART_SOFT_RX0_GPIO) && NVIC_EXTI3_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX0_GPIO)) || (defined(UART_SOFT_RX1_GPIO) && NVIC_EXTI3_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX1_GPIO)) || (defined(UART_SOFT_RX2_GPIO) && NVIC_EXTI3_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX2_GPIO)) || (defined(UART_SOFT_RX3_GPIO) && NVIC_EXTI3_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX3_GPIO))
-void exti3_isr(void)
-{
- exti_reset_request(EXTI3); // clear interrupt flag for pin triggers this ISR (pin state will be checked independently)
- uart_soft_receive_activity(); // check which GPIO changed
-}
-#endif
-#if (defined(UART_SOFT_RX0_GPIO) && NVIC_EXTI4_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX0_GPIO)) || (defined(UART_SOFT_RX1_GPIO) && NVIC_EXTI4_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX1_GPIO)) || (defined(UART_SOFT_RX2_GPIO) && NVIC_EXTI4_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX2_GPIO)) || (defined(UART_SOFT_RX3_GPIO) && NVIC_EXTI4_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX3_GPIO))
-void exti4_isr(void)
-{
- exti_reset_request(EXTI4); // clear interrupt flag for pin triggers this ISR (pin state will be checked independently)
- uart_soft_receive_activity(); // check which GPIO changed
-}
-#endif
-#if (defined(UART_SOFT_RX0_GPIO) && NVIC_EXTI9_5_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX0_GPIO)) || (defined(UART_SOFT_RX1_GPIO) && NVIC_EXTI9_5_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX1_GPIO)) || (defined(UART_SOFT_RX2_GPIO) && NVIC_EXTI9_5_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX2_GPIO)) || (defined(UART_SOFT_RX3_GPIO) && NVIC_EXTI9_5_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX3_GPIO))
-void exti9_5_isr(void)
-{
- exti_reset_request(EXTI5 | EXTI6 | EXTI7 | EXTI8 | EXTI9); // clear interrupt flag for pin triggers this ISR (pin state will be checked independently)
- uart_soft_receive_activity(); // check which GPIO changed
-}
-#endif
-#if (defined(UART_SOFT_RX0_GPIO) && NVIC_EXTI15_10_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX0_GPIO)) || (defined(UART_SOFT_RX1_GPIO) && NVIC_EXTI15_10_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX1_GPIO)) || (defined(UART_SOFT_RX2_GPIO) && NVIC_EXTI15_10_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX2_GPIO)) || (defined(UART_SOFT_RX3_GPIO) && NVIC_EXTI15_10_IRQ == GPIO_NVIC_EXTI_IRQ(UART_SOFT_RX3_GPIO))
-void exti15_10_isr(void)
-{
- exti_reset_request(EXTI10 | EXTI11 | EXTI12 | EXTI13 | EXTI14 | EXTI15); // clear interrupt flag for pin triggers this ISR (pin state will be checked independently)
- uart_soft_receive_activity(); // check which GPIO changed
-}
-#endif
diff --git a/lib/uart_soft.h b/lib/uart_soft.h
deleted file mode 100644
index 7626993..0000000
--- a/lib/uart_soft.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/** library to control up to 4 independent receive and transmit software UART ports
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: GPIO @ref uart_soft_gpio, timer @ref uart_soft_timer
- */
-#pragma once
-#error not converted for STM32F4
-
-/** if data has been received from UART port and is available to be read */
-extern volatile bool uart_soft_received[4];
-
-/** setup software UART ports
- * @param[in] rx_baudrates baud rates of the 4 UART RX ports (0 if unused)
- * @param[in] tx_baudrates baud rates of the 4 UART TX ports (0 if unused)
- * @return is setup succeeded, else the configuration is wrong
- */
-bool uart_soft_setup(const uint32_t* rx_baudrates, const uint32_t* tx_baudrates);
-/** get received byte from UART port
- * @param[in] uart UART receive port to read byte from
- * @return received byte (0 if no byte is available)
- */
-uint8_t uart_soft_getbyte(uint8_t uart);
-/** ensure all bytes are transmitted for the UART
- * @param[in] uart UART port to flush
- */
-void uart_soft_flush(uint8_t uart);
-/** put byte in buffer to be transmitted on UART port
- * @note blocking if buffer is full
- * @param[in] uart UART port to transmit the byte from
- * @param[in] byte byte to put in transmit buffer
- */
-void uart_soft_putbyte_nonblocking(uint8_t uart, uint8_t byte);
-/** transmit byte on UART port
- * @note blocks until all buffered byte and this byte are transmitted
- * @param[in] uart UART port to transmit the byte from
- * @param[in] byte byte to transmit
- */
-void uart_soft_putbyte_blocking(uint8_t uart, uint8_t byte);
-
diff --git a/lib/usart_enhanced.c b/lib/usart_enhanced.c
deleted file mode 100644
index d77f1c9..0000000
--- a/lib/usart_enhanced.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/** library for enhanced USART communication (code)
- * @file usart_enhanced.c
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2018
- * @details the USART peripherals only support 8 or 9-bit word and even or odd parity (included in the data bits). The library adds support for 5 to 8-bit words, none/even/odd/mark/space parity (on top of the data bits)
- * @note since parity is handled in software, the parity error (PE) flag is unused and should be replaced by the value return by usart_enhanced_parity_error
- * @remark 9-bit raw communication is not supported since this is not common and can be done without this library
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/stm32/usart.h> // USART utilities
-
-/* own libraries */
-#include "usart_enhanced.h" // utilities for USART enhancements
-
-/** number of available USART peripherals */
-#define USART_PERIPHERALS_NB 3
-/** configured enhanced USART word size */
-static uint8_t usart_enhanced_databits[USART_PERIPHERALS_NB];
-/** configured enhanced USART parity */
-static enum usart_enhanced_parity_t usart_enhanced_parity[USART_PERIPHERALS_NB];
-/** last enhanced USART parity error status */
-static bool usart_enhanced_parity_errors[USART_PERIPHERALS_NB];
-
-const bool usart_enhanced_even_parity_lut[256] = { true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, };
-
-/** get index of corresponding enhanced USART configurations
- * @param[in] usart USART peripheral base address
- * @return index used for the individual USART configurations
- * @note the returned value is valid only is less than USART_PERIPHERALS_NB
- */
-static uint8_t usart_enhanced_id(uint32_t usart)
-{
- uint8_t to_return = USART_PERIPHERALS_NB;
- switch (usart) {
- case USART1:
- to_return = 0;
- break;
- case USART2:
- to_return = 1;
- break;
- case USART3:
- to_return = 2;
- break;
- default:
- to_return = USART_PERIPHERALS_NB;
- break;
- }
- return to_return;
-}
-
-bool usart_enhanced_config(uint32_t usart, uint8_t databits, enum usart_enhanced_parity_t parity)
-{
- /* sanity check */
- uint8_t id = usart_enhanced_id(usart);
- if (id>=USART_PERIPHERALS_NB) {
- return false;
- }
- if (databits<5 || databits>8) {
- return false;
- }
- if (parity>USART_ENHANCED_PARITY_SPACE) {
- return false;
- }
-
- // save configuration for later use
- usart_enhanced_databits[id] = databits;
- usart_enhanced_parity[id] = parity;
- // configure USART peripheral
- if (8 == databits && USART_ENHANCED_PARITY_NONE != parity) { // the parity bit is additional to the data bits
- usart_set_databits(usart, 9);
- } else {
- usart_set_databits(usart, 8);
- }
- usart_set_parity(usart, USART_PARITY_NONE); // set no parity since we will take care of it ourselves
- // we could also lower the number of stop bits when less than 8 bits are used, for higher throughput, but this is not a good idea since most UART transceiver parse 8 bits even is less is used
- return true;
-}
-
-void usart_enhanced_send(uint32_t usart, uint8_t data)
-{
- /* sanity check */
- uint8_t id = usart_enhanced_id(usart);
- if (id >= USART_PERIPHERALS_NB) {
- return;
- }
-
- data &= ~(0xff << usart_enhanced_databits[id]); // only keep the data bits
- uint16_t output = data; // put value in output buffer
- switch (usart_enhanced_parity[id]) {
- case USART_ENHANCED_PARITY_NONE: // a mark is also decoded as idle/stop
- case USART_ENHANCED_PARITY_MARK:
- output |= (1 << usart_enhanced_databits[id]); // add idle state
- break;
- case USART_ENHANCED_PARITY_EVEN:
- if (!usart_enhanced_even_parity_lut[data]) {
- output |= (1 << usart_enhanced_databits[id]);
- }
- // no need to clear a bit if the parity is even
- break;
- case USART_ENHANCED_PARITY_ODD:
- if (usart_enhanced_even_parity_lut[data]) {
- output |= (1 << usart_enhanced_databits[id]);
- }
- // no need to clear a bit if the parity is odd
- break;
- case USART_ENHANCED_PARITY_SPACE:
- // no need to clear the bit
- break;
- }
- output |= (0xffff << (usart_enhanced_databits[id] + 1)); // set additional bits to idle (high)
- usart_send(usart, output); // transmit character
-}
-
-uint8_t usart_enhanced_recv(uint32_t usart)
-{
- /* sanity check */
- uint8_t id = usart_enhanced_id(usart);
- if (id >= USART_PERIPHERALS_NB) {
- return 0xff;
- }
-
- uint16_t input = usart_recv(usart); // read received character (also clears the error flags)
- uint8_t data = input & ~(0xffff << usart_enhanced_databits[id]); // only keep the data bits
- // check the parity
- uint16_t parity = input & (1 << usart_enhanced_databits[id]); // only keep the parity bit
- usart_enhanced_parity_errors[id] = false;
- switch (usart_enhanced_parity[id]) {
- case USART_ENHANCED_PARITY_NONE:
- usart_enhanced_parity_errors[id] = false;
- break;
- case USART_ENHANCED_PARITY_EVEN:
- if (parity) {
- usart_enhanced_parity_errors[id] = !usart_enhanced_even_parity_lut[data];
- } else {
- usart_enhanced_parity_errors[id] = usart_enhanced_even_parity_lut[data];
- }
- break;
- case USART_ENHANCED_PARITY_ODD:
- if (parity) {
- usart_enhanced_parity_errors[id] = usart_enhanced_even_parity_lut[data];
- } else {
- usart_enhanced_parity_errors[id] = !usart_enhanced_even_parity_lut[data];
- }
- break;
- case USART_ENHANCED_PARITY_MARK:
- usart_enhanced_parity_errors[id] = !parity;
- break;
- case USART_ENHANCED_PARITY_SPACE:
- usart_enhanced_parity_errors[id] = parity;
- break;
- }
- return data;
-}
-
-bool usart_enhanced_parity_error(uint32_t usart)
-{
- /* sanity check */
- uint8_t id = usart_enhanced_id(usart);
- if (id >= USART_PERIPHERALS_NB) {
- return false;
- }
- return usart_enhanced_parity_errors[id];
-}
diff --git a/lib/usart_enhanced.h b/lib/usart_enhanced.h
deleted file mode 100644
index 41b0353..0000000
--- a/lib/usart_enhanced.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/** library for enhanced USART communication
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2018
- * @details the USART peripherals only support 8 or 9-bit word and even or odd parity (included in the data bits). The library adds support for 5 to 8-bit words, none/even/odd/mark/space parity (on top of the data bits)
- * @note since parity is handled in software, the parity error (PE) flag is unused and should be replaced by the value return by usart_enhanced_parity_error
- * @remark 9-bit raw communication is not supported since this is not common and can be done without this library
- */
-#pragma once
-#error not converted for STM32F4
-
-/** enhanced USART setting for the additional parity bit*/
-enum usart_enhanced_parity_t {
- /** no parity */
- USART_ENHANCED_PARITY_NONE,
- /** even parity
- * @note the number of 1's is even
- */
- USART_ENHANCED_PARITY_EVEN,
- /** odd parity
- * @note the number of 1's is odd
- */
- USART_ENHANCED_PARITY_ODD,
- /** mark parity
- * @note the parity bit is 1
- */
- USART_ENHANCED_PARITY_MARK,
- /** space parity
- * @note the parity bit is 0
- */
- USART_ENHANCED_PARITY_SPACE,
-};
-
-/** know if there is an even number of 1's in a integer
- * @note this look up table is only useful for up to 8-bit words, else use __builtin_parity
- * @remark a look-up is a lot faster than making the calculation and doesn't use a lot of (flash) memory
- */
-extern const bool usart_enhanced_even_parity_lut[256];
-
-/** configure enhanced USART
- * @param[in] usart USART peripheral base address
- * @param[in] databits word size in bits (5 to 8)
- * @param[in] parity additional parity bit
- * @return if the input settings are valid and the configuration is successful
- */
-bool usart_enhanced_config(uint32_t usart, uint8_t databits, enum usart_enhanced_parity_t parity);
-/** send data over the enhanced USART using the configuration
- * @param[in] usart USART peripheral base address
- * @param[in] data data to be sent
- * @note uses usart_send
- */
-void usart_enhanced_send(uint32_t usart, uint8_t data);
-/** receive data over the enhanced USART using the configuration
- * @param[in] usart USART peripheral base address
- * @return data received
- * @note uses usart_recv
- */
-uint8_t usart_enhanced_recv(uint32_t usart);
-/** get the parity status of the received data
- * @param[in] usart USART peripheral base address
- * @return if there is a parity error
- * @note the check only applies to the last data retrieved using usart_enhanced_recv
- */
-bool usart_enhanced_parity_error(uint32_t usart);
diff --git a/lib/vfd_hv518.c b/lib/vfd_hv518.c
deleted file mode 100644
index bbe8a28..0000000
--- a/lib/vfd_hv518.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/** library to drive vacuum fluorescent display using supertex HV518 shift register VFD drivers
- * @details the current configuration is for a VFD extracted from a Samsung SER-6500 cash register
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: SPI @ref vfd_hv518_spi , GPIO @ref vfd_hv518_gpio , timer @ref vfd_hv518_timer
- */
-/* standard libraries */
-#include <stdint.h> // standard integer types
-#include <stdlib.h> // general utilities
-
-/* STM32 (including CM3) libraries */
-#include <libopencm3/stm32/rcc.h> // real-time control clock library
-#include <libopencm3/stm32/gpio.h> // general purpose input output library
-#include <libopencm3/stm32/spi.h> // SPI library
-#include <libopencm3/stm32/timer.h> // timer library
-#include <libopencm3/cm3/nvic.h> // interrupt handler
-
-#include "global.h" // global definitions
-#include "vfd_hv518.h" // VFD library API
-
-/** @defgroup vfd_hv518_gpio GPIO to control supertex HV518 VFD drivers
- * @{
- */
-#define VFD_STR_PIN PA6 /**< strobe pin to enable high voltage output, high voltage is output on low */
-#define VFD_NLE_PIN PA4 /**< latch enable pin, stores the shifted data on low, output the parallel data on high */
-/** @} */
-
-/** @defgroup vfd_hv518_spi SPI to send data to supertex HV518 VFD drivers
- * @{
- */
-#define VFD_SPI 1 /**< SPI peripheral */
-/** @} */
-
-/** @defgroup vfd_hv518_timer timer for automatic display blocks refresh
- * @{
- */
-#define VFD_TIMER 2 /**< timer peripheral ID */
-/** @} */
-
-/** ASCII characters encoded for the 7 segments digit block
- * @note starts with space
- */
-static const uint8_t ascii_7segments[] = {
- 0x00, // 0b00000000, space
- 0x30, // 0b00110000, ! (I)
- 0x22, // 0b00100010, "
- 0x5c, // 0b01011100, # (o)
- 0x6d, // 0b01101101, $ (s)
- 0x52, // 0b01010010, % (/)
- 0x7d, // 0b01111101, & (6)
- 0x20, // 0b00100000, '
- 0x39, // 0b00111001, ( ([)
- 0x0f, // 0b00001111, )
- 0x70, // 0b01110000, *
- 0x46, // 0b01000110, +
- 0x10, // 0b00010000, ,
- 0x40, // 0b01000000, -
- 0x10, // 0b00010000, . (,)
- 0x52, // 0b01010010, /
- 0x3f, // 0b00111111, 0
- 0x06, // 0b00000110, 1
- 0x5b, // 0b01011011, 2
- 0x4f, // 0b01001111, 3
- 0x66, // 0b01100110, 4
- 0x6d, // 0b01101101, 5
- 0x7d, // 0b01111101, 6
- 0x07, // 0b00000111, 7
- 0x7f, // 0b01111111, 8
- 0x6f, // 0b01101111, 9
- 0x48, // 0b01001000, : (=)
- 0x48, // 0b01001000, ; (=)
- 0x58, // 0b01011000, <
- 0x48, // 0b01001000, =
- 0x4c, // 0b01001100, >
- 0x53, // 0b01010011, ?
- 0x7b, // 0b01111011, @
- 0x77, // 0b01110111, A
- 0x7f, // 0b01111111, B
- 0x39, // 0b00111001, C
- 0x5e, // 0b01011110, D
- 0x79, // 0b01111001, E
- 0x71, // 0b01110001, F
- 0x3d, // 0b00111101, G
- 0x76, // 0b01110110, H
- 0x30, // 0b00110000, I
- 0x1e, // 0b00011110, J
- 0x76, // 0b01110110, K
- 0x38, // 0b00111000, L
- 0x37, // 0b00110111, M
- 0x37, // 0b00110111, N
- 0x3f, // 0b00111111, O
- 0x73, // 0b01110011, P
- 0x6b, // 0b01101011, Q
- 0x33, // 0b00110011, R
- 0x6d, // 0b01101101, S
- 0x78, // 0b01111000, T
- 0x3e, // 0b00111110, U
- 0x3e, // 0b00111110, V (U)
- 0x3e, // 0b00111110, W (U)
- 0x76, // 0b01110110, X (H)
- 0x6e, // 0b01101110, Y
- 0x5b, // 0b01011011, Z
- 0x39, // 0b00111001, [
- 0x64, // 0b01100100, '\'
- 0x0f, // 0b00001111, /
- 0x23, // 0b00100011, ^
- 0x08, // 0b00001000, _
- 0x02, // 0b00000010, `
- 0x5f, // 0b01011111, a
- 0x7c, // 0b01111100, b
- 0x58, // 0b01011000, c
- 0x5e, // 0b01011110, d
- 0x7b, // 0b01111011, e
- 0x71, // 0b01110001, f
- 0x6f, // 0b01101111, g
- 0x74, // 0b01110100, h
- 0x10, // 0b00010000, i
- 0x0c, // 0b00001100, j
- 0x76, // 0b01110110, k
- 0x30, // 0b00110000, l
- 0x54, // 0b01010100, m
- 0x54, // 0b01010100, n
- 0x5c, // 0b01011100, o
- 0x73, // 0b01110011, p
- 0x67, // 0b01100111, q
- 0x50, // 0b01010000, r
- 0x6d, // 0b01101101, s
- 0x78, // 0b01111000, t
- 0x1c, // 0b00011100, u
- 0x1c, // 0b00011100, v (u)
- 0x1c, // 0b00011100, w (u)
- 0x76, // 0b01110110, x
- 0x6e, // 0b01101110, y
- 0x5b, // 0b01011011, z
- 0x39, // 0b00111001, { ([)
- 0x30, // 0b00110000, |
- 0x0f, // 0b00001111, } ([)
- 0x40, // 0b01000000, ~
-};
-
-/** font for the 5x7 dot matrix block
- * @details first value is left-most line, LSB is top dot, MSB is not used
- * @note from http://sunge.awardspace.com/glcd-sd/node4.html
- */
-static const uint8_t font5x7[][5] = {
- {0x00, 0x00, 0x00, 0x00, 0x00}, // (space)
- {0x00, 0x00, 0x5F, 0x00, 0x00}, // !
- {0x00, 0x07, 0x00, 0x07, 0x00}, // "
- {0x14, 0x7F, 0x14, 0x7F, 0x14}, // #
- {0x24, 0x2A, 0x7F, 0x2A, 0x12}, // $
- {0x23, 0x13, 0x08, 0x64, 0x62}, // %
- {0x36, 0x49, 0x55, 0x22, 0x50}, // &
- {0x00, 0x05, 0x03, 0x00, 0x00}, // '
- {0x00, 0x1C, 0x22, 0x41, 0x00}, // (
- {0x00, 0x41, 0x22, 0x1C, 0x00}, // )
- {0x08, 0x2A, 0x1C, 0x2A, 0x08}, // *
- {0x08, 0x08, 0x3E, 0x08, 0x08}, // +
- {0x00, 0x50, 0x30, 0x00, 0x00}, // ,
- {0x08, 0x08, 0x08, 0x08, 0x08}, // -
- {0x00, 0x60, 0x60, 0x00, 0x00}, // .
- {0x20, 0x10, 0x08, 0x04, 0x02}, // /
- {0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0
- {0x00, 0x42, 0x7F, 0x40, 0x00}, // 1
- {0x42, 0x61, 0x51, 0x49, 0x46}, // 2
- {0x21, 0x41, 0x45, 0x4B, 0x31}, // 3
- {0x18, 0x14, 0x12, 0x7F, 0x10}, // 4
- {0x27, 0x45, 0x45, 0x45, 0x39}, // 5
- {0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6
- {0x01, 0x71, 0x09, 0x05, 0x03}, // 7
- {0x36, 0x49, 0x49, 0x49, 0x36}, // 8
- {0x06, 0x49, 0x49, 0x29, 0x1E}, // 9
- {0x00, 0x36, 0x36, 0x00, 0x00}, // :
- {0x00, 0x56, 0x36, 0x00, 0x00}, // ;
- {0x00, 0x08, 0x14, 0x22, 0x41}, // <
- {0x14, 0x14, 0x14, 0x14, 0x14}, // =
- {0x41, 0x22, 0x14, 0x08, 0x00}, // >
- {0x02, 0x01, 0x51, 0x09, 0x06}, // ?
- {0x32, 0x49, 0x79, 0x41, 0x3E}, // @
- {0x7E, 0x11, 0x11, 0x11, 0x7E}, // A
- {0x7F, 0x49, 0x49, 0x49, 0x36}, // B
- {0x3E, 0x41, 0x41, 0x41, 0x22}, // C
- {0x7F, 0x41, 0x41, 0x22, 0x1C}, // D
- {0x7F, 0x49, 0x49, 0x49, 0x41}, // E
- {0x7F, 0x09, 0x09, 0x01, 0x01}, // F
- {0x3E, 0x41, 0x41, 0x51, 0x32}, // G
- {0x7F, 0x08, 0x08, 0x08, 0x7F}, // H
- {0x00, 0x41, 0x7F, 0x41, 0x00}, // I
- {0x20, 0x40, 0x41, 0x3F, 0x01}, // J
- {0x7F, 0x08, 0x14, 0x22, 0x41}, // K
- {0x7F, 0x40, 0x40, 0x40, 0x40}, // L
- {0x7F, 0x02, 0x04, 0x02, 0x7F}, // M
- {0x7F, 0x04, 0x08, 0x10, 0x7F}, // N
- {0x3E, 0x41, 0x41, 0x41, 0x3E}, // O
- {0x7F, 0x09, 0x09, 0x09, 0x06}, // P
- {0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q
- {0x7F, 0x09, 0x19, 0x29, 0x46}, // R
- {0x46, 0x49, 0x49, 0x49, 0x31}, // S
- {0x01, 0x01, 0x7F, 0x01, 0x01}, // T
- {0x3F, 0x40, 0x40, 0x40, 0x3F}, // U
- {0x1F, 0x20, 0x40, 0x20, 0x1F}, // V
- {0x7F, 0x20, 0x18, 0x20, 0x7F}, // W
- {0x63, 0x14, 0x08, 0x14, 0x63}, // X
- {0x03, 0x04, 0x78, 0x04, 0x03}, // Y
- {0x61, 0x51, 0x49, 0x45, 0x43}, // Z
- {0x00, 0x00, 0x7F, 0x41, 0x41}, // [
- {0x02, 0x04, 0x08, 0x10, 0x20}, // '\'
- {0x41, 0x41, 0x7F, 0x00, 0x00}, // ]
- {0x04, 0x02, 0x01, 0x02, 0x04}, // ^
- {0x40, 0x40, 0x40, 0x40, 0x40}, // _
- {0x00, 0x01, 0x02, 0x04, 0x00}, // `
- {0x20, 0x54, 0x54, 0x54, 0x78}, // a
- {0x7F, 0x48, 0x44, 0x44, 0x38}, // b
- {0x38, 0x44, 0x44, 0x44, 0x20}, // c
- {0x38, 0x44, 0x44, 0x48, 0x7F}, // d
- {0x38, 0x54, 0x54, 0x54, 0x18}, // e
- {0x08, 0x7E, 0x09, 0x01, 0x02}, // f
- {0x08, 0x14, 0x54, 0x54, 0x3C}, // g
- {0x7F, 0x08, 0x04, 0x04, 0x78}, // h
- {0x00, 0x44, 0x7D, 0x40, 0x00}, // i
- {0x20, 0x40, 0x44, 0x3D, 0x00}, // j
- {0x00, 0x7F, 0x10, 0x28, 0x44}, // k
- {0x00, 0x41, 0x7F, 0x40, 0x00}, // l
- {0x7C, 0x04, 0x18, 0x04, 0x78}, // m
- {0x7C, 0x08, 0x04, 0x04, 0x78}, // n
- {0x38, 0x44, 0x44, 0x44, 0x38}, // o
- {0x7C, 0x14, 0x14, 0x14, 0x08}, // p
- {0x08, 0x14, 0x14, 0x18, 0x7C}, // q
- {0x7C, 0x08, 0x04, 0x04, 0x08}, // r
- {0x48, 0x54, 0x54, 0x54, 0x20}, // s
- {0x04, 0x3F, 0x44, 0x40, 0x20}, // t
- {0x3C, 0x40, 0x40, 0x20, 0x7C}, // u
- {0x1C, 0x20, 0x40, 0x20, 0x1C}, // v
- {0x3C, 0x40, 0x30, 0x40, 0x3C}, // w
- {0x44, 0x28, 0x10, 0x28, 0x44}, // x
- {0x0C, 0x50, 0x50, 0x50, 0x3C}, // y
- {0x44, 0x64, 0x54, 0x4C, 0x44}, // z
- {0x00, 0x08, 0x36, 0x41, 0x00}, // {
- {0x00, 0x00, 0x7F, 0x00, 0x00}, // |
- {0x00, 0x41, 0x36, 0x08, 0x00}, // }
- {0x08, 0x04, 0x0c, 0x08, 0x04}, // ~ {0b00001000, 0b00000100, 0b00001100, 0b00001000, 0b00000100}
-};
-
-/** pictures for the 5x7 dot matrix block
- * @details first value is left-most line, LSB is top dot, MSB is not used
- */
-static const uint8_t pict5x7[][5] = {
- {0x08, 0x08, 0x2A, 0x1C, 0x08}, // ->
- {0x08, 0x1C, 0x2A, 0x08, 0x08}, // <-
- {0x70, 0x70, 0x7a, 0x7c, 0x58}, // bunny side 1 {0b01110000, 0b01110000, 0b01111010, 0b01111100, 0b01011000}
- {0x20, 0x70, 0x72, 0x7c, 0x58}, // bunny side 2 {0b00100000, 0b01110000, 0b01110010, 0b01111100, 0b01011000}
- {0x3e, 0x49, 0x56, 0x49, 0x3e}, // bunny face 1 {0b00111110, 0b01001001, 0b01010110, 0b01001001, 0b00111110}
- {0x3e, 0x51, 0x66, 0x51, 0x3e}, // bunny face 2 {0b00111110, 0b01010001, 0b01100110, 0b01010001, 0b00111110}
- {0x38, 0x57, 0x64, 0x57, 0x38}, // bunny face 3 {0b00111000, 0b01010111, 0b01100100, 0b01010111, 0b00111000}
- {0x38, 0x4f, 0x54, 0x4f, 0x38}, // bunny face 4 {0b00111000, 0b01001111, 0b01010100, 0b01001111, 0b00111000}
- {0x38, 0x5e, 0x68, 0x5e, 0x38}, // bunny face 5 {0b00111000, 0b01011110, 0b01101000, 0b01011110, 0b00111000}
- {0x41, 0x36, 0x08, 0x36, 0x41}, // cross 1 {0b01000001, 0b00110110, 0b00001000, 0b00110110, 0b01000001}
- {~0x41, ~0x36, ~0x08, ~0x36, ~0x41}, // cross 1 negated {~0b01000001, ~0b00110110, ~0b00001000, ~0b00110110, ~0b01000001}
- {0x22, 0x14, 0x08, 0x14, 0x22}, // cross 2 {0b00100010, 0b00010100, 0b00001000, 0b00010100, 0b00100010}
- {~0x22, ~0x14, ~0x08, ~0x14, ~0x22}, // cross 2 negated {~0b00100010, ~0b00010100, ~0b00001000, ~0b00010100, ~0b00100010}
- {0x00, 0x00, 0x00, 0x00, 0x00}, // nothing
-};
-
-/** the 32 bits values to be shifted out to the VFD driver
- * @note split into 16 bit for SPI transfer
- * @note since the bits for digits and matrix are independent, they can be combined
- * @note we have more matrix (12) than digits (10)
- */
-static uint16_t driver_data[VFD_MATRIX][VFD_DRIVERS * 2] = {0};
-/** which driver data is being transmitted */
-static volatile uint8_t spi_i = 0;
-/** which grid/part to activate
- * @note digits and matrix can be combined
- */
-static volatile uint8_t vfd_grid = 0;
-/** the bits used for selecting then digit and 7 segment anodes
- * @note for the second driver
- */
-static const uint32_t digit_mask = 0x00fffff0;
-
-void vfd_digit(uint8_t nb, char c)
-{
- if (!(nb < VFD_DIGITS)) { // check the digit exists
- return;
- }
-
- uint32_t digit_data = 0; // the data to be shifted out for the driver (for the second driver)
-
- digit_data = 1 << (4 + (9 - nb)); // select digit
- /* encode segment
- * here the bit order (classic 7 segment + underline and dot)
- * 3_
- * 8|9_|4
- * 7|6_|5.1
- * 0_2,
- * */
- if (false) { // add the underline (not encoded)
- digit_data |= (1 << 14);
- }
- if (c&0x80) { // add the dot (encoded in the 8th bit)
- digit_data |= (1 << 15);
- }
- if (false) { // add the comma (not encoded)
- digit_data |= (1 << 16);
- }
-
- c &= 0x7f; // only take the ASCII part
- if (c >= ' ') { // only take printable characters
- uint8_t i = c - ' '; // get index for character
- if (i < LENGTH(ascii_7segments)) {
- digit_data |= (ascii_7segments[i] << 17); // add encoded segments to memory
- }
- }
-
- digit_data &= digit_mask; // be sure only the bits for the digit are used
- digit_data |= (driver_data[nb][2] + (driver_data[nb][3] << 16)) & ~digit_mask; // get the existing data and add the bits for the digit
- driver_data[nb][2] = digit_data; // write back data (least significant half)
- driver_data[nb][3] = (digit_data >> 16); // write back data (most significant half)
-}
-
-void vfd_matrix(uint8_t nb, char c)
-{
- // check the matrix exists
- if (!(nb < VFD_MATRIX)) {
- return;
- }
-
- uint32_t matrix_data[VFD_DRIVERS] = {0}; // the data to be shifted out for the driver
-
- // select matrix
- if (nb < 4) {
- matrix_data[1] = 1 << (3 - nb);
- } else {
- matrix_data[0] = 1 << (35 - nb);
- }
-
- if ((c < 0x80) && (c >= ' ')) { // only take printable characters
- uint8_t i = c - ' '; // get index for character
- if (i < LENGTH(font5x7)) {
- matrix_data[1] |= font5x7[i][0] << 24;
- matrix_data[2] |= font5x7[i][1] << 0;
- matrix_data[2] |= font5x7[i][2] << 8;
- matrix_data[2] |= font5x7[i][3] << 16;
- matrix_data[2] |= font5x7[i][4] << 24;
- }
- } else if (c > 0x7f) { // the non ASCII character are used for pictures
- uint8_t i = c - 0x80; // get index for character
- if (i < LENGTH(pict5x7)) {
- matrix_data[1] |= pict5x7[i][0] << 24;
- matrix_data[2] |= pict5x7[i][1] << 0;
- matrix_data[2] |= pict5x7[i][2] << 8;
- matrix_data[2] |= pict5x7[i][3] << 16;
- matrix_data[2] |= pict5x7[i][4] << 24;
- }
- }
-
- matrix_data[1] &= ~digit_mask; // be sure only the bits for the matrix are used
- matrix_data[1] |= (driver_data[nb][2] + (driver_data[nb][3] << 16)) & digit_mask; // get the existing data for the digit
- // prepare the data for SPI to shift it out
- for (uint8_t i = 0; i < LENGTH(matrix_data); i++) {
- driver_data[nb][i * 2] = matrix_data[i];
- driver_data[nb][i * 2 + 1] = matrix_data[i] >> 16;
- }
-}
-
-void vfd_clear(void)
-{
- for (uint8_t i = 0; i < LENGTH(driver_data); i++) {
- for (uint8_t j = 0; j < LENGTH(driver_data[0]); j++) {
- driver_data[i][j] = 0;
- }
- }
-}
-
-void vfd_test(void)
-{
- for (uint8_t i = 0; i < LENGTH(driver_data); i++) {
- for (uint8_t j = 0; j < LENGTH(driver_data[0]); j++) {
- driver_data[i][j] = ~0;
- }
- }
-}
-
-void vfd_on(void)
-{
- gpio_clear(GPIO_PORT(VFD_STR_PIN), GPIO_PIN(VFD_STR_PIN)); // enable HV output
- timer_enable_counter(TIM(VFD_TIMER)); // start timer to periodically output that to the parts
-}
-
-void vfd_off(void)
-{
- gpio_set(GPIO_PORT(VFD_STR_PIN), GPIO_PIN(VFD_STR_PIN)); // disable HV output
- timer_disable_counter(TIM(VFD_TIMER)); // stop timer to periodically output that to the parts
-}
-
-void vfd_setup(void)
-{
- /* setup GPIO to control the VFD */
- rcc_periph_clock_enable(GPIO_RCC(VFD_STR_PIN)); // enable clock for VFD GPIO
- gpio_set(GPIO_PORT(VFD_STR_PIN), GPIO_PIN(VFD_STR_PIN)); // disable HV output
- gpio_set_mode(GPIO_PORT(VFD_STR_PIN), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(VFD_STR_PIN)); // set VFD pin to output push-pull
- rcc_periph_clock_enable(GPIO_RCC(VFD_NLE_PIN)); // enable clock for VFD GPIO
- gpio_clear(GPIO_PORT(VFD_NLE_PIN), GPIO_PIN(VFD_NLE_PIN)); // do not output latched data
- gpio_set_mode(GPIO_PORT(VFD_NLE_PIN), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(VFD_NLE_PIN)); // set VFD pin to output push-pull
-
- /* setup SPI to transmit data */
- rcc_periph_clock_enable(RCC_SPI(VFD_SPI)); // enable SPI clock
- rcc_periph_clock_enable(RCC_SPI_SCK_PORT(VFD_SPI)); // enable clock for VFD SPI GPIO
- rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(VFD_SPI)); // enable clock for VFD SPI GPIO
- gpio_set_mode(SPI_SCK_PORT(VFD_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(VFD_SPI)); // set VFD pin to alternative function push-pull
- gpio_set_mode(SPI_MOSI_PORT(VFD_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(VFD_SPI)); // set VFD pin to alternative function push-pull
-
- spi_reset(SPI(VFD_SPI)); // clear SPI values
- /* set SPI:
- * - use VFD_SPI port
- * - divide clock by 8 for generating the baudrate (F_PCLK1 is 36MHz, max HV518 is 6MHz)
- * - clock idle high polarity
- * - data is valid on rising edge (second clock phase)
- * - send 16 bits at a time
- * - send least significant bit first (that's how I coded the data)
- */
- spi_init_master(SPI(VFD_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_1_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_16BIT, SPI_CR1_LSBFIRST);
- //spi_set_bidirectional_transmit_only_mode(VFD_SPI); // only use MOSI to transmit
- spi_set_unidirectional_mode(SPI(VFD_SPI)); // MISO is unused
- /* set NSS high to enable transmission
- * the NSS in STM32 can not be used as hardware slave select
- * RM0008 reference manual 25.3.1 is misleading
- * when hardware NSS is used and output is enabled NSS never goes up after transmission, even if SPI is disabled
- * when software NSS is used, NSS can not be set high again, even when writing to the register
- * the slave select must be done manually using GPIO */
- spi_enable_software_slave_management(SPI(VFD_SPI));
- spi_set_nss_high(SPI(VFD_SPI)); // set NSS high
-
- nvic_enable_irq(SPI_IRQ(VFD_SPI)); // enable SPI interrupt
- spi_enable(SPI(VFD_SPI)); // enable SPI (the tx empty interrupt will trigger)
-
- /* setup timer to refresh display */
- rcc_periph_clock_enable(RCC_TIM(VFD_TIMER)); // enable clock for timer block
- rcc_periph_reset_pulse(RST_TIM(VFD_TIMER)); // reset timer state
- timer_set_mode(TIM(VFD_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(VFD_TIMER), (rcc_ahb_frequency / (1 << 16)) - 1); // set the prescaler so this 16 bits timer overflows at 1Hz
- timer_set_period(TIM(VFD_TIMER), 0xffff / LENGTH(driver_data) / 100); // set the refresh frequency
- timer_enable_irq(TIM(VFD_TIMER), TIM_DIER_UIE); // enable interrupt for timer
- nvic_enable_irq(NVIC_TIM_IRQ(VFD_TIMER)); // allow interrupt for timer
-
- vfd_clear(); // initialize values
-}
-
-/** SPI interrupt service routine called when data has been transmitted */
-void SPI_ISR(VFD_SPI)(void)
-{
- if (SPI_SR(SPI(VFD_SPI)) & SPI_SR_TXE) { // transmission buffer empty
- if (spi_i < LENGTH(driver_data[0])) { // check if data is available
- gpio_clear(GPIO_PORT(VFD_NLE_PIN), GPIO_PIN(VFD_NLE_PIN)); // slave select to latch data
- spi_send(SPI(VFD_SPI), driver_data[vfd_grid][spi_i++]); // send next data
- } else { // all data transmitted
- spi_disable_tx_buffer_empty_interrupt(SPI(VFD_SPI)); // no need to wait for new data
- while (SPI_SR(SPI(VFD_SPI)) & SPI_SR_BSY); // wait for data to be shifted out
- spi_disable_tx_buffer_empty_interrupt(SPI(VFD_SPI)); // no need to wait for new data
- gpio_set(GPIO_PORT(VFD_NLE_PIN), GPIO_PIN(VFD_NLE_PIN)); // output latched data
- }
- }
-}
-
-/** timer interrupt service routine called time passed */
-void TIM_ISR(VFD_TIMER)(void)
-{
- if (timer_get_flag(TIM(VFD_TIMER), TIM_SR_UIF)) { // overflow even happened
- timer_clear_flag(TIM(VFD_TIMER), TIM_SR_UIF); // clear flag
- spi_i = 0; // set the register to shift out
- spi_enable_tx_buffer_empty_interrupt(SPI(VFD_SPI)); // enable TX empty interrupt
- vfd_grid = (vfd_grid + 1) % LENGTH(driver_data); // got to next segment
- }
-}
diff --git a/lib/vfd_hv518.h b/lib/vfd_hv518.h
deleted file mode 100644
index bac93db..0000000
--- a/lib/vfd_hv518.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/** library to drive vacuum fluorescent display using supertex HV518 shift register VFD drivers
- * @details the current configuration is for a VFD extracted from a Samsung SER-6500 cash register
- * @file
- * @author King Kévin <kingkevin@cuvoodoo.info>
- * @copyright SPDX-License-Identifier: GPL-3.0-or-later
- * @date 2016-2020
- * @note peripherals used: SPI @ref vfd_hv518_spi , GPIO @ref vfd_hv518_gpio , timer @ref vfd_hv518_timer
- */
-#pragma once
-#error not converted for STM32F4
-
-/** number HV518 VFD drivers */
-#define VFD_DRIVERS 3
-/** number of digits blocks on SER-6500 VFD */
-#define VFD_DIGITS 10
-/** number of dot matrix blocks on SER-6500 VFD */
-#define VFD_MATRIX 12
-
-/** set character to digit block
- * @param[in] nb digit block to set
- * @param[in] c ASCII character to set
- * @note use the MSB of @p nb to enable the dot
- */
-void vfd_digit(uint8_t nb, char c);
-/** set character to matrix block
- * @param[in] nb matrix block to set
- * @param[in] c ASCII character to set
- * @note on ASCII characters are used for pictures
- */
-void vfd_matrix(uint8_t nb, char c);
-/** clear VFD display */
-void vfd_clear(void);
-/** test VFD display (light up all segments) */
-void vfd_test(void);
-/** switch VFD on */
-void vfd_on(void);
-/** switch VFD display off */
-void vfd_off(void);
-/** setup VFD */
-void vfd_setup(void);