Compare commits

..

1 Commits
master ... dh10

Author SHA1 Message Date
King Kévin 648ff9c8af DH10 dehumidifier sensor module firmawre and documentation 2020-10-19 13:44:49 +02:00
12 changed files with 616 additions and 1523 deletions

View File

@ -1,21 +1,15 @@
CC := sdcc
CFLAGS := -mstm8 --std-c99 --opt-code-size --Werror
LDFLAGS = -mstm8 --out-fmt-ihx -lstm8
FIRMWARE := main
SRC_FILES := $(wildcard *.c)
OBJ_FILES := $(patsubst %.c,%.rel,$(SRC_FILES))
all: $(FIRMWARE).ihx
$(FIRMWARE).ihx: $(OBJ_FILES)
$(CC) $(LDFLAGS) $^ -o $@
%.ihx: %.c stm8s.h
$(CC) $(CFLAGS) --out-fmt-ihx $<
size $@
%.rel: %.c %.h
$(CC) $(CFLAGS) --compile-only $<
flash: $(FIRMWARE).ihx
stm8flash -c stlinkv2 -p stm8s103f3 -w $<
clean:
rm -f $(FIRMWARE).asm $(FIRMWARE).ihx $(FIRMWARE).cdb $(FIRMWARE).lst $(FIRMWARE).map $(FIRMWARE).lk $(FIRMWARE).rel $(FIRMWARE).rst $(FIRMWARE).sym $(OBJ_FILES)
rm -f $(FIRMWARE).asm $(FIRMWARE).ihx $(FIRMWARE).cdb $(FIRMWARE).lst $(FIRMWARE).map $(FIRMWARE).lk $(FIRMWARE).rel $(FIRMWARE).rst $(FIRMWARE).sym

3
README Normal file
View File

@ -0,0 +1,3 @@
this is the firmware for the dehumidifier sensor module.
a STM8S003 micro-controller reads the temperature and relative humidity measurements from an AHT20 humidity sensor using I²C, and sends it to the Aplatec DH 10 dehumidifier using a proprietary unidirectional IR-like pulse-width modulated protocol.

View File

@ -1,2 +0,0 @@
firmware template for ST STM8S micro-controller.
includes register definitions using macros and structures.

View File

@ -1,69 +0,0 @@
/** library to program EEPROM using block programming
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
* @date 2021
* @warning functions need to be put in and run from RAM (because block programming is used)
*/
// RAM code-putting from https://lujji.github.io/blog/executing-code-from-ram-on-stm8/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdbool.h> // boolean types
#include "stm8s.h" // STM8S definitions
#include "eeprom_blockprog.h" // own definitions
// start address of EEPROM
#define EEPROM_ADDR 0x4000
// block size from low-density devices (including STM8S103)
#define DATA_BLOCK_SIZE 64U
#pragma codeseg RAM_SEG
bool eeprom_blockprog(const uint8_t* data, uint16_t length)
{
if (0 == length) {
return true; // nothing to do
}
if (!data) {
return false; // data missing
}
if (0 != (length % DATA_BLOCK_SIZE)) {
return false; // we can only program whole blocks
}
// disable DATA (e.g. EEPROM) write protection
// don't check if it is locked this it does not save that much time and uses memory)
FLASH_DUKR = FLASH_DUKR_KEY1;
FLASH_DUKR = FLASH_DUKR_KEY2;
// don't verify if unlock succeeded to save memory
// if (!(FLASH_IAPSR & FLASH_IAPSR_DUL)) { // un-protecting failed
// return false;
// }
// program data
uint8_t* eeprom = (uint8_t*)(EEPROM_ADDR);
while (length) {
// enable standard block programming
FLASH_CR2 |= FLASH_CR2_PRG;
FLASH_NCR2 &= ~FLASH_NCR2_NPRG;
// program block
for (uint8_t i = 0; i < DATA_BLOCK_SIZE; i++) {
*(eeprom++) = *(data++);
}
length -= DATA_BLOCK_SIZE;
// wait until program completed
while (FLASH_CR2 & FLASH_CR2_PRG);
// check if programming failed
// we don't check for WR_PG_DIS (while checking EOP) because EEPROM isn't (and can't be) write protected
if (!(FLASH_IAPSR & FLASH_IAPSR_EOP)) {
FLASH_IAPSR &= ~FLASH_IAPSR_DUL; // re-enable write protection
return false;
}
}
FLASH_IAPSR &= ~FLASH_IAPSR_DUL; // re-enable write protection
return true;
}

View File

@ -1,14 +0,0 @@
/** library to program EEPROM using block programming
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
* @date 2021
* @warning functions need to be put in and run from RAM (because block programming is used)
*/
/** program EEPROM using block programming
* @param[in] data data to be programmed
* @param[in] length length of data to be programmed (must be a multiple of the block length)
* @return if program succeeded
*/
bool eeprom_blockprog(const uint8_t* data, uint16_t length);

View File

@ -1,469 +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-2021
* @note the I²C peripheral is not well specified and does not cover all cases. The following complexity is the best I could do to cope with it
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdbool.h> // boolean types
#include <stdlib.h> // general utilities
/* own libraries */
#include "stm8s.h" // STM8S definitions
#include "i2c_master.h" // I²C header and definitions
bool i2c_master_setup(uint16_t freq_khz)
{
// configure I²C peripheral
I2C_CR1 &= ~I2C_CR1_PE; // disable I²C peripheral to configure it
/*
if (!i2c_master_check_signals()) { // check the signal lines
return false;
}
*/
I2C_FREQR = 16; // the peripheral frequency (must match CPU frequency)
if (freq_khz > 100) {
uint16_t ccr = (I2C_FREQR * 1000) / (3 * freq_khz);
if (ccr > 0x0fff) {
ccr = 0x0fff;
}
I2C_CCRL = (ccr & 0xff); // set SCL at 320 kHz (for less error)
I2C_CCRH = ((ccr >> 8) & 0x0f) | (I2C_CCRH_FS); // set fast speed mode
I2C_TRISER = ((I2C_FREQR * 3 / 10) + 1); // set rise time
} else {
uint16_t ccr = (I2C_FREQR * 1000) / (2 * freq_khz);
if (ccr > 0x0fff) {
ccr = 0x0fff;
}
I2C_CCRL = (ccr & 0xff); // set SCL at 320 kHz (for less error)
I2C_CCRH = ((ccr >> 8) & 0x0f); // set fast speed mode
I2C_TRISER = (I2C_FREQR + 1); // set rise time
}
I2C_CR1 |= I2C_CR1_PE; // enable I²C peripheral
return true;
}
void i2c_master_release(void)
{
I2C_CR1 &= ~I2C_CR1_PE; // disable I²C peripheral
}
bool i2c_master_check_signals(void)
{
i2c_master_release(); // ensure PB4/PB5 are not used as alternate function
GPIO_PB->CR1.reg &= ~(PB4 | PB5); // operate in open-drain mode
GPIO_PB->DDR.reg |= (PB4 | PB5); // set SCL/SDA as output to test pull-up
GPIO_PB->ODR.reg |= PB4; // ensure SCL is high
GPIO_PB->ODR.reg &= ~PB5; // set SDA low (start condition)
for (volatile uint8_t t = 0; t < 10; t++); // wait a bit to be sure signal is low
GPIO_PB->ODR.reg |= PB5; // set SDA high (stop condition)
GPIO_PB->DDR.reg &= ~(PB4 | PB5); // set SCL/SDA as input before it is used as alternate function by the peripheral
for (volatile uint8_t t = 0; t < 50; t++); // wait 10 us for pull-up to take effect
return ((GPIO_PB->IDR.reg & PB4) && (GPIO_PB->IDR.reg & PB5)); // test if both lines are up
}
void i2c_master_reset(void)
{
I2C_CR2 |= I2C_CR2_STOP; // release lines
// don't check if BUSY is cleared since its state might be erroneous
// rewriting I2C_CR2 before I2C_CR2_STOP is cleared might cause a second STOP, but at this point we don't care
I2C_CR2 |= I2C_CR2_SWRST; // reset peripheral, in case we got stuck and the dog bit
// be sure a watchdog is present as this can take forever
while ((0 == (GPIO_PB->IDR.reg & PB4) && (0 == (GPIO_PB->IDR.reg & PB5)))); // wait for SDA/SCL line to be released
I2C_CR2 &= ~I2C_CR2_SWRST; // release reset
I2C_CR1 &= ~I2C_CR1_PE; // disable I²C peripheral to clear some bits
}
enum i2c_master_rc i2c_master_start(void)
{
// send (re-)start condition
if (I2C_CR2 & (I2C_CR2_START | I2C_CR2_STOP)) { // ensure start or stop operations are not in progress
return I2C_MASTER_RC_START_STOP_IN_PROGESS;
}
// don't check BUSY flag as this might be for a re-start
I2C_CR2 |= I2C_CR2_START; // sent start condition
I2C_SR2 = 0; // clear error flags
rim(); // enable interrupts
while ((I2C_CR2 & I2C_CR2_START) || !(I2C_SR1 & I2C_SR1_SB) || !(I2C_SR3 & I2C_SR3_MSL)) { // wait until start condition has been accepted, send, and we are in aster mode
if (I2C_SR2) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_CR2 & I2C_CR2_STOP) {
return I2C_MASTER_RC_TIMEOUT;
}
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable I²C interrupts
wfi(); // got to sleep to prevent EMI causing glitches
}
return I2C_MASTER_RC_NONE;
}
/** wait until stop is sent and bus is released
* @return I²C return code
*/
static enum i2c_master_rc i2c_master_wait_stop(void)
{
I2C_SR2 = 0; // clear error flags
while (I2C_CR2 & I2C_CR2_STOP) { // wait until stop condition is accepted and cleared
if (I2C_SR2) {
return I2C_MASTER_RC_BUS_ERROR;
}
// there is no interrupt flag we can use here
}
// this time we can't use I2C_CR2_STOP to check for timeout
if (I2C_SR3 & I2C_SR3_MSL) { // ensure we are not in master mode anymore
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_SR3 & I2C_SR3_BUSY) { // ensure bus is released
return I2C_MASTER_RC_BUS_ERROR;
}
/*
if (!i2c_master_check_signals()) { // ensure lines are released
return I2C_MASTER_RC_BUS_ERROR;
}
*/
return I2C_MASTER_RC_NONE;
}
enum i2c_master_rc i2c_master_stop(void)
{
// sanity check
if (!(I2C_SR3 & I2C_SR3_BUSY)) { // ensure bus is not already released
return I2C_MASTER_RC_NONE; // bus has probably already been released
}
if (I2C_CR2 & (I2C_CR2_START | I2C_CR2_STOP)) { // ensure start or stop operations are not in progress
return I2C_MASTER_RC_START_STOP_IN_PROGESS;
}
I2C_CR2 |= I2C_CR2_STOP; // 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)
{
if (!(I2C_SR1 & I2C_SR1_SB)) { // start condition has not been sent yet
enum i2c_master_rc rc = i2c_master_start(); // send start condition
if (I2C_MASTER_RC_NONE != rc) {
return rc;
}
}
if (!(I2C_SR3 & I2C_SR3_MSL)) { // I²C device is not in master mode
return I2C_MASTER_RC_NOT_MASTER;
}
// select slave
I2C_SR2 &= ~(I2C_SR2_AF); // clear acknowledgement failure
if (!address_10bit) { // 7-bit address
I2C_DR = (slave << 1) | (write ? 0 : 1); // select slave, with read/write flag
I2C_SR2 = 0; // clear error flags
rim(); // enable interrupts
while (!(I2C_SR1 & I2C_SR1_ADDR)) { // wait until address is transmitted (or error)
if (I2C_CR2 & I2C_CR2_STOP) {
return I2C_MASTER_RC_TIMEOUT;
}
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
return I2C_MASTER_RC_NAK;
} else if (I2C_SR2) {
return I2C_MASTER_RC_BUS_ERROR;
}
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable relevant I²C interrupts
wfi(); // got to sleep to prevent EMI causing glitches
}
} else { // 10-bit address
// send first part of address
I2C_DR = 11110000 | (((slave >> 8 ) & 0x3) << 1); // send first header (11110xx0, where xx are 2 MSb of slave address)
I2C_SR2 = 0; // clear error flags
rim(); // enable interrupts
while (!(I2C_SR1 & I2C_SR1_ADD10)) { // wait until address is transmitted (or error)
if (I2C_CR2 & I2C_CR2_STOP) {
return I2C_MASTER_RC_TIMEOUT;
}
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
return I2C_MASTER_RC_NAK;
} else if (I2C_SR2) {
return I2C_MASTER_RC_BUS_ERROR;
}
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable relevant I²C interrupts
wfi(); // got to sleep to prevent EMI causing glitches
}
// send second part of address
I2C_SR2 &= ~(I2C_SR2_AF); // clear acknowledgement failure
I2C_DR = (slave & 0xff); // send remaining of address
I2C_SR2 = 0; // clear error flags
rim(); // enable interrupts
while (!(I2C_SR1 & I2C_SR1_ADDR)) { // wait until address is transmitted (or error)
if (I2C_CR2 & I2C_CR2_STOP) {
return I2C_MASTER_RC_TIMEOUT;
}
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
return I2C_MASTER_RC_NAK;
} else if (I2C_SR2) {
return I2C_MASTER_RC_BUS_ERROR;
}
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable relevant I²C interrupts
wfi(); // got to sleep to prevent EMI causing glitches
}
// go into receive mode if necessary
if (!write) {
enum i2c_master_rc rc = i2c_master_start(); // send start condition
if (I2C_MASTER_RC_NONE != rc) {
return rc;
}
// send first part of address with receive flag
I2C_SR2 &= ~(I2C_SR2_AF); // clear acknowledgement failure
I2C_DR = 11110001 | (((slave >> 8) & 0x3) << 1); // send header (11110xx1, where xx are 2 MSb of slave address)
I2C_SR2 = 0; // clear error flags
while (!(I2C_SR1 & I2C_SR1_ADDR)) { // wait until address is transmitted (or error)
if (I2C_CR2 & I2C_CR2_STOP) {
return I2C_MASTER_RC_TIMEOUT;
}
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
return I2C_MASTER_RC_NAK;
} else if (I2C_SR2) {
return I2C_MASTER_RC_BUS_ERROR;
}
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable relevant I²C interrupts
wfi(); // got to sleep to prevent EMI causing glitches
}
}
}
// I2C_SR3_TRA should be set after I2C_SR1_ADDR is cleared (end of address transmission), but this is not the case and the TRM/errata does not provide more info
// verify if we are in the right mode
// final check
if (write && !(I2C_SR3 & I2C_SR3_TRA)) {
return I2C_MASTER_RC_NOT_TRANSMIT;
} else if (!write && (I2C_SR3 & I2C_SR3_TRA)) {
return I2C_MASTER_RC_NOT_RECEIVE;
}
return I2C_MASTER_RC_NONE;
}
enum i2c_master_rc i2c_master_read(uint8_t* data, uint16_t data_size)
{
if (NULL == data || 0 == data_size) { // no data to read
return I2C_MASTER_RC_OTHER; // we indicate an error because we don't send a stop
}
if (!(I2C_SR3 & I2C_SR3_MSL)) { // I²C device is not in master mode
return I2C_MASTER_RC_NOT_MASTER;
}
// we can't check if the address phase it over since ADDR has been cleared when checking for mode
if (I2C_SR3 & I2C_SR3_TRA) { // ensure we are in receive mode
return I2C_MASTER_RC_NOT_RECEIVE;
}
// read data
I2C_CR2 |= I2C_CR2_ACK; // enable ACK by default
I2C_SR2 = 0; // clear error flags
rim(); // enable interrupts
for (uint16_t i = 0; i < data_size; i++) { // read bytes
IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog
// set (N)ACK (EV6_3, EV6_1)
if (1 == (data_size - i)) { // prepare to sent NACK for last byte
I2C_CR2 &= ~(I2C_CR2_ACK); // disable ACK
I2C_CR2 |= I2C_CR2_STOP; // prepare to send the stop
}
rim(); // enable interrupts
while (!(I2C_SR1 & I2C_SR1_RXNE)) { // wait until data is received (or error)
if (I2C_SR2) { // an error occurred
return I2C_MASTER_RC_BUS_ERROR;
}
I2C_ITR = (I2C_ITR_ITBUFEN | I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable all I²C interrupts
wfi(); // got to sleep to prevent EMI causing glitches
}
data[i] = I2C_DR; // read the received byte
}
return i2c_master_wait_stop();
}
enum i2c_master_rc i2c_master_write(const uint8_t* data, uint16_t data_size)
{
if (NULL == data || 0 == data_size) { // no data to read
return I2C_MASTER_RC_NONE; // we don't indicate an error because the stop is done separately
}
if (!(I2C_SR3 & I2C_SR3_MSL)) { // I²C device is not in master mode
return I2C_MASTER_RC_NOT_MASTER;
}
// we can't check if the address phase it over since ADDR has been cleared when checking for mode
if (!(I2C_SR3 & I2C_SR3_TRA)) { // ensure we are in transmit mode
return I2C_MASTER_RC_NOT_TRANSMIT;
}
// write data
for (uint16_t i = 0; i < data_size; i++) { // write bytes
I2C_SR2 &= ~(I2C_SR2_AF); // clear acknowledgement failure
(void)(I2C_SR1 & I2C_SR1_BTF); // clear BTF (when followed by write) in case the clock is stretched because there was no data to send on the next transmission slot
I2C_DR = data[i]; // send byte
I2C_SR2 = 0; // clear error flags
rim(); // enable interrupts
while (!(I2C_SR1 & I2C_SR1_TXE)) { // wait until byte has been transmitted
IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog
if (I2C_CR2 & I2C_CR2_STOP) {
return I2C_MASTER_RC_TIMEOUT;
}
if (I2C_SR2 & I2C_SR2_AF) { // data has not been acknowledged
return I2C_MASTER_RC_NAK;
} else if (I2C_SR2) {
return I2C_MASTER_RC_BUS_ERROR;
}
I2C_ITR = (I2C_ITR_ITBUFEN | I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable all I²C interrupts
wfi(); // got to sleep to prevent EMI causing glitches
}
}
return I2C_MASTER_RC_NONE;
}
enum i2c_master_rc i2c_master_slave_read(uint16_t slave, bool address_10bit, uint8_t* data, uint16_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, uint16_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, uint16_t address_size, uint8_t* data, uint16_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, uint16_t address_size, const uint8_t* data, uint16_t data_size)
{
if (UINT16_MAX - address_size < data_size) { // prevent integer overflow
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;
}
enum i2c_master_rc rc; // 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 (address_size && address) {
rc = i2c_master_write(address, address_size); // send memory address
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
}
if (data_size && data) {
rc = i2c_master_write(data, data_size); // send memory data
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
}
rc = i2c_master_stop(); // sent stop condition
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
rc = I2C_MASTER_RC_NONE; // all went fine
error:
return rc;
}
void i2c_master_isr(void) __interrupt(IRQ_I2C) // I²C event or error happened
{
I2C_ITR = 0; // disable all interrupt sources to stop looping in ISR and let current loop check the right status flags
}

View File

@ -1,117 +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-2021
* @warning the I²C peripheral is very glitchy (sending random clock pulses), thus prefer the software implementation alternative, which is simpler, more flexible, smaller, and very stable (it just draws more energy)
*/
#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] freq_khz desired clock frequency, in kHz
* @return if I²C bus is ready to be used (same as i2c_master_check_signals)
*/
bool i2c_master_setup(uint16_t freq_khz);
/** release I²C peripheral */
void i2c_master_release(void);
/** reset I²C peripheral, fixing any locked state
* @warning the I²C 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 high
* @return if SDA and SCL signals are pulled high
*/
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, uint16_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, uint16_t data_size);
/** sent stop condition
* @param[in] i2c I²C base address
* @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, uint16_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, uint16_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, uint16_t address_size, uint8_t* data, uint16_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, uint16_t address_size, const uint8_t* data, uint16_t data_size);
/** interrupt service routine used to wake up
* @note not sure why the declaration need to be in main for it to work
*/
void i2c_master_isr(void) __interrupt(IRQ_I2C);

311
main.c
View File

@ -1,21 +1,205 @@
/* firmware template for STM8S microcontroller
* Copyright (C) 2019-2020 King Kévin <kingkevin@cuvoodoo.info>
/* firmware for the ALPATEC DH-10 0101E dehumidifier humidity sensor board
* Copyright (C) 2020 King Kévin <kingkevin@cuvoodoo.info>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
/* firmware to read out temperature and relative humidity from AHT20 sensor and send it to Aplatec DH 10 dehumidifier */
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "stm8s.h"
#include "main.h"
// get length of array
#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
// pin to send the humidity value to the humidifier
// WHTM-03 board
//#define DEHUMIDIFIER_PORT GPIO_PD
//#define DEHUMIDIFIER_PIN PD5
// DH10 board
#define DEHUMIDIFIER_PORT GPIO_PD
#define DEHUMIDIFIER_PIN PD2
// blocking wait (in 10 us steps, up to UINT32_MAX / 10)
static void wait_10us(uint32_t us10)
// the I²C address of the AHT20
#define SENSOR_ADDR 0x38
#define AHT20_CMD_RESET 0xBA
#define AHT20_CMD_INIT 0xBE
#define AHT20_CMD_TRIGGER 0xAC
// flag set when value should be sent
volatile bool periodic_flag = false;
// blocking wait, in us
static void wait_us(uint16_t time)
{
us10 = ((us10 / (1 << CLK->CKDIVR.fields.HSIDIV)) * 1000) / 206; // calibrated for 1 ms
while (us10--); // burn energy
TIM1->ARRH.reg = (time >> 8) & 0xff; // set timeout
TIM1->ARRL.reg = (time >> 0) & 0xff; // set timeout
TIM1->CR1.fields.CEN = 1; // enable timer
while (TIM1->CR1.fields.CEN); // wait until time passed
}
// send bit to dehumidifier
static void send_bit(bool bit)
{
// pulse low
DEHUMIDIFIER_PORT->ODR.reg &= ~DEHUMIDIFIER_PIN; // set low
wait_us(500 - 5); // time with function call delay
// pulse high
DEHUMIDIFIER_PORT->ODR.reg |= DEHUMIDIFIER_PIN; // set high
if (bit) {
wait_us(1500 - 7); // long high pulse
} else {
wait_us(500 - 5); // short high pulse
}
}
// send byte to dehumidifier (LSb first)
static void send_byte(uint8_t byte)
{
for (int8_t i = 7; i >= 0; i--) {
send_bit((byte >> i) & 0x01);
}
}
// send break condition to dehumidifier (after sending the 4 data bytes)
static void send_break(void)
{
// pulse low
DEHUMIDIFIER_PORT->ODR.reg &= ~DEHUMIDIFIER_PIN; // set low
wait_us(12250 - 759); // long low pulse
DEHUMIDIFIER_PORT->ODR.reg |= DEHUMIDIFIER_PIN; // set high
}
static uint8_t i2c_transmit(uint8_t addr, const uint8_t* data, uint8_t len)
{
if (0 == len || 0 == data) {
return 0;
}
I2C_SR2 = 0; // clear errors
I2C_CR2 |= I2C_CR2_START; // send start condition
while (!(I2C_SR1 & I2C_SR1_SB)) { // wait until start bit is sent
if (I2C_SR2 & (I2C_SR2_ARLO | I2C_SR2_BERR)) { // bus error occurred
return 1;
}
}
if (!(I2C_SR3 & I2C_SR3_MSL)) { // ensure we are in master mode
return 2;
}
I2C_SR2 = 0; // clear errors
I2C_DR = (addr << 1) | 0; // select device in transmit
while (!(I2C_SR1 & I2C_SR1_ADDR)) { // wait until address has been transmitted
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 3;
}
}
if (I2C_SR2 & I2C_SR2_AF) { // no ACK received
return 4;
}
if (!(I2C_SR3 & I2C_SR3_TRA)) { // ensure we are in transmit mode
return 5;
}
for (uint8_t i = 0; i < len; i++) {
while (!(I2C_SR1 & I2C_SR1_TXE)) { // wait until transmit register is empty
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 6;
}
}
if (I2C_SR2 & I2C_SR2_AF) { // no ACK received
return 7;
}
I2C_DR = data[i]; // send data byte
}
while (!(I2C_SR1 & I2C_SR1_TXE)) { // wait until transmit register is empty
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 8;
}
}
while (!(I2C_SR1 & I2C_SR1_BTF)) { // wait until transmission completed
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 9;
}
}
I2C_CR2 |= I2C_CR2_STOP; // send stop
while (I2C_SR3 & I2C_SR3_BUSY) { // wait until transmission ended
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 10;
}
}
if (I2C_SR3 & I2C_SR3_MSL) { // ensure we are back in slave mode
return 11;
}
return 0;
}
static uint8_t i2c_receive(uint8_t addr, uint8_t* data, uint8_t len)
{
if (0 == len || 0 == data) {
return 0;
}
I2C_SR2 = 0; // clear errors
I2C_CR2 |= I2C_CR2_START; // send start condition
while (!(I2C_SR1 & I2C_SR1_SB)) { // wait until start bit is sent
if (I2C_SR2 & (I2C_SR2_ARLO | I2C_SR2_BERR)) { // bus error occurred
return 1;
}
}
if (!(I2C_SR3 & I2C_SR3_MSL)) { // ensure we are in master mode
return 2;
}
I2C_SR2 = 0; // clear errors
I2C_DR = (addr << 1) | 1; // select device in receive
while (!(I2C_SR1 & I2C_SR1_ADDR)) { // wait until address has been transmitted
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 3;
}
}
if (I2C_SR2 & I2C_SR2_AF) { // no ACK received
return 4;
}
if (I2C_SR3 & I2C_SR3_TRA) { // ensure we are in receive mode
return 5;
}
data[0] = I2C_DR; // just to clear the flag
if (1 == len) {
I2C_CR2 &= ~I2C_CR2_ACK; // already send NACK
I2C_CR2 |= I2C_CR2_STOP; // already program stop
while (!(I2C_SR1 & I2C_SR1_RXNE)) { // wait to receive data
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 6;
}
}
data[0] = I2C_DR; // save receive data
} else if (2 == len) {
I2C_CR2 &= ~I2C_CR2_ACK; // already send NACK
while (!(I2C_SR1 & I2C_SR1_BTF)) { // wait until 2 bytes received
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 7;
}
}
I2C_CR2 |= I2C_CR2_STOP; // send stop
} else {
I2C_CR2 |= I2C_CR2_ACK; // send ACK
for (uint8_t i = 0; i < len; i++) {
while (!(I2C_SR1 & I2C_SR1_RXNE)) { // wait to receive data
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 8;
}
}
data[i] = I2C_DR; // save receive data
if (i + 1 == len) {
I2C_CR2 &= ~I2C_CR2_ACK; // send NACK
I2C_CR2 |= I2C_CR2_STOP; // send stop
}
}
}
while (I2C_SR3 & I2C_SR3_BUSY) { // wait until transmission ended
if (I2C_SR2 & I2C_SR2_BERR) { // bus error occurred
return 10;
}
}
if (I2C_SR3 & I2C_SR3_MSL) { // ensure we are back in slave mode
return 11;
}
return 0;
}
void main(void)
@ -26,12 +210,45 @@ void main(void)
CLK->CKDIVR.fields.CPUDIV = CLK_CKDIVR_CPUDIV_DIV0; // don't divide CPU frequency to 16 MHz
while (!CLK->ICKR.fields.HSIRDY); // wait for internal oscillator to be ready
// configure auto-wakeup (AWU) to be able to refresh the watchdog
// 128 kHz LSI used by default in option bytes CKAWUSEL
// we skip measuring the LS clock frequency since there is no need to be precise
AWU->TBR.fields.AWUTB = 10; // interval range: 128-256 ms
AWU->APR.fields.APR = 0x3e; // set time to 256 ms
AWU_CSR |= AWU_CSR_AWUEN; // enable AWU (start only when entering wait or active halt mode)
// configure dehumidifier output pin
DEHUMIDIFIER_PORT->DDR.reg |= DEHUMIDIFIER_PIN; // switch pin to output
DEHUMIDIFIER_PORT->CR1.reg &= ~DEHUMIDIFIER_PIN; // switch output to open-drain
//DEHUMIDIFIER_PORT->CR1.reg |= DEHUMIDIFIER_PIN; // switch output to push/pull
DEHUMIDIFIER_PORT->ODR.reg |= DEHUMIDIFIER_PIN; // set idle high
// configure I²C to communicate with ATH20 humidity sensor
CLK_PCKENR1 |= CLK_PCKENR1_I2C; // enable I²C peripheral (should be on per default)
GPIO_PB->CR1.reg |= (PB4 | PB5); // enable internal pull-up on SCL/SDA (there should also be external pull-up resistors)
GPIO_PB->DDR.reg &= ~(PB4 | PB5); // set SCL/SDA as input before it is used as alternate function by the peripheral
I2C_CR1 |= I2C_CR1_PE; // enable I²C peripheral (must be done before any other register is written)
I2C_CR2 |= I2C_CR2_STOP; // release lines
I2C_CR2 |= I2C_CR2_SWRST; // reset peripheral, in case we got stuck and the dog bit
while (!(GPIO_PB->IDR.reg & PB4)); // wait for SCL line to be released
while (!(GPIO_PB->IDR.reg & PB5)); // wait for SDA line to be released
I2C_CR2 &= ~I2C_CR2_SWRST; // release reset
I2C_CR1 &= ~I2C_CR1_PE; // disable I²C peripheral to configure it
I2C_FREQR = 16; // the peripheral frequency is 16 MHz (must match CPU frequency)
I2C_CCRH = (uint8_t)(8000 >> 8); // set control clock to 100 kHz (16 MHz / 2 * 8000), standard mode
I2C_CCRL = (uint8_t)(8000 >> 0); // set control clock to 100 kHz (16 MHz / 2 * 8000)
I2C_TRISER = 0x09; // set maximum rise time for SCL (100 ns in standard mode)
I2C_CR1 |= I2C_CR1_PE; // re-enable I²C peripheral
// configure timer 2 for periodic 250 ms value sending
TIM2->CR1.fields.URS = 1; // only interrupt on overflow
TIM2->PSCR.fields.PSC = 6; // best prescaler for most precise timer for up to 0.262 second (1.0/(16E6/(2**6)) * 2**16)
TIM2->ARRH.reg = 62500 >> 8; // set the timeout to 250 ms
TIM2->ARRL.reg = 62500 & 0xff; // set the timeout to 250 ms
TIM2->IER.fields.UIE = 1; // enable update/overflow interrupt
TIM2->CR1.fields.CEN = 1; // enable timer for periodic value output
// configure timer 1 for pulse sending (500 us)
TIM1->CR1.fields.OPM = 1; // only run once
TIM1->CR1.fields.URS = 1; // only interrupt on overflow
TIM1->PSCRH.reg = ((16 - 1) >> 8); // set prescaler to have us
TIM1->PSCRL.reg = ((16 - 1) >> 0); // set prescaler to have us
TIM1->CNTRH.reg = 0; // reset counter value (should be per default)
TIM1->CNTRL.reg = 0; // reset counter value (should be per default)
wait_us(2); // test it once
// configure independent watchdog (very loose, just it case the firmware hangs)
IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog
@ -42,18 +259,74 @@ void main(void)
rim(); // re-enable interrupts
bool action = false; // if an action has been performed
wait_us(40000); // wait 40 ms for device to start up
const uint8_t aht20_reset[] = {AHT20_CMD_RESET};
uint8_t rc = i2c_transmit(SENSOR_ADDR, aht20_reset, ARRAY_LENGTH(aht20_reset)); // send software reset
if (rc) {
while(true); // let the dog bite
}
wait_us(20000); // wait 20 ms for reset to complete
uint8_t rx_buffer[7]; // to receive the measurements
rc = i2c_receive(SENSOR_ADDR, rx_buffer, 1); // read the status
if (rc) {
while(true); // let the dog bite
}
if (!(rx_buffer[0] & 0x08)) { // ensure it is calibrated
const uint8_t aht20_init[] = {AHT20_CMD_INIT};
rc = i2c_transmit(SENSOR_ADDR, aht20_init, ARRAY_LENGTH(aht20_init)); // initialise device (not sure what it does)
if (rc) {
while(true); // let the dog bite
}
wait_us(10000); // wait 10 ms for calibration to complete
}
// trigger measurement
const uint8_t aht20_trigger[] = {AHT20_CMD_TRIGGER, 0x33, 0x00};
rc = i2c_transmit(SENSOR_ADDR, aht20_trigger, ARRAY_LENGTH(aht20_trigger));
if (rc) {
while(true); // let the dog bite
}
wait_us(80000); // wait 80 ms for measurement to complete
uint8_t humidity = 99;
uint8_t temp = 0;
while (true) {
IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog
if (periodic_flag) { // time to get and send measurements
periodic_flag = false; // clear flag
rc = i2c_receive(SENSOR_ADDR, rx_buffer, ARRAY_LENGTH(rx_buffer)); // read measurement
if (rc) {
while(true); // let the dog bite
}
if (!(rx_buffer[0] & 0x80)) { // not busy doing the measurement
humidity = (rx_buffer[1] * (uint16_t)100) / 256; // save new humidity value, only use the 8 MSb out of 20
temp = (((uint8_t)(rx_buffer[3] << 4) + (uint8_t)(rx_buffer[4] >> 4)) * (uint16_t)200) / 256 - 50; // save new temperature, only use the 8 MSB (out of 20)
// trigger next measurement
rc = i2c_transmit(SENSOR_ADDR, aht20_trigger, ARRAY_LENGTH(aht20_trigger));
if (rc) {
while(true); // let the dog bite
}
}
send_byte(temp);
send_byte(humidity);
send_byte(temp ^ 0xff);
send_byte(humidity ^ 0xff);
send_break();
}
if (action) { // something has been performed, check if other flags have been set meanwhile
action = false; // clear flag
} else { // nothing down
wfi(); // go to sleep (wait for any interrupt, including periodic AWU)
wfi(); // go to sleep (wait for periodic ping)
}
}
}
void awu(void) __interrupt(IRQ_AWU) // auto wakeup
void tim2_isr(void) __interrupt(IRQ_TIM2_UO) // timer 2 update interrupt service routine
{
volatile uint8_t awuf = AWU_CSR; // clear interrupt flag by reading it (reading is required, and volatile prevents compiler optimization)
// let the main loop kick the dog
if (TIM2->SR1.fields.UIF) { // 250 ms passed, time to send data
TIM2->SR1.fields.UIF = 0; // clear flag
periodic_flag = true; // notify main loop
}
}

2
main.h
View File

@ -1,2 +0,0 @@
// get length of array
#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))

View File

@ -1,412 +0,0 @@
/** library to communicate using I²C as master, implemented in software
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
* @date 2021
* @note I implemented I²C in software because the hardware peripheral is hard to use, and buggy (I was not able to get rid of clock glitches corrupting the communication, undetected)
* @note some methods copied from Wikipedia https://en.wikipedia.org/wiki/I%C2%B2C
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdbool.h> // boolean types
#include <stdlib.h> // general utilities
/* own libraries */
#include "stm8s.h" // STM8S definitions
#include "softi2c_master.h" // software I²C header and definitions
// half period to wait for I²C clock
static uint16_t period = 0;
// port for data line
#define SDA_PORT GPIO_PB
// pin for data line
#define SDA_PIN PB5
// port for clock line
#define SCL_PORT GPIO_PB
// pin for clock line
#define SCL_PIN PB4
// operation timeout (in half period)
#define TIMEOUT 10U
// delay for half a period
static void I2C_delay(void)
{
for (volatile uint16_t i = 0; i < period; i++);
}
// Return current level of SCL line, 0 or 1
static inline bool read_SCL(void)
{
return (SCL_PORT->IDR.reg & SCL_PIN);
}
// Return current level of SDA line, 0 or 1
static inline bool read_SDA(void)
{
return (SDA_PORT->IDR.reg & SDA_PIN);
}
// Do not drive SCL (set pin high-impedance)
static inline void set_SCL(void)
{
SCL_PORT->ODR.reg |= SCL_PIN;
}
// Actively drive SCL signal low
static inline void clear_SCL(void)
{
SCL_PORT->ODR.reg &= ~SCL_PIN;
}
// Do not drive SDA (set pin high-impedance)
static inline void set_SDA(void)
{
SDA_PORT->ODR.reg |= SDA_PIN;
}
// Actively drive SDA signal low
static inline void clear_SDA(void)
{
SDA_PORT->ODR.reg &= ~SDA_PIN;
}
bool softi2c_master_setup(uint16_t freq_khz)
{
// enforce minimal frequency
if (0 == freq_khz) {
freq_khz = 1;
}
// calculated period from frequency (hand tuned value using 16 MHz clock)
period = 589 / (1 << CLK->CKDIVR.fields.HSIDIV) / (1 << CLK->CKDIVR.fields.CPUDIV) / freq_khz;
// switch pins to open drain
SCL_PORT->ODR.reg |= SCL_PIN; // ensure clock is high
SCL_PORT->DDR.reg |= SCL_PIN; // switch pin to output
SCL_PORT->CR1.reg &= ~SCL_PIN; // use in open-drain mode
SDA_PORT->ODR.reg |= SDA_PIN; // ensure data is high
SDA_PORT->DDR.reg |= SDA_PIN; // switch pin to output
SDA_PORT->CR1.reg &= ~SDA_PIN; // use in open-drain mode
I2C_delay(); // give time to get high
return (read_SCL() && read_SDA()); // line is ready when the two lines are high
}
void softi2c_master_release(void)
{
SCL_PORT->DDR.reg &= ~SCL_PIN; // switch pin to input
SDA_PORT->DDR.reg &= ~SDA_PIN; // switch pin to input
}
// if transaction has already started
static bool started = false;
bool softi2c_master_start(void)
{
if (started) {
// if started, do a restart condition
// set SDA to 1
set_SDA();
I2C_delay();
set_SCL();
uint8_t timeout = TIMEOUT;
while (read_SCL() == 0 && timeout) { // Clock stretching
I2C_delay();
timeout--;
}
if (0 == timeout) {
return false;
}
// Repeated start setup time, minimum 4.7us
I2C_delay();
}
if (read_SDA() == 0) {
return false;
}
// SCL is high, set SDA from 1 to 0.
clear_SDA();
I2C_delay();
clear_SCL();
started = true;
return true;
}
bool softi2c_master_stop(void)
{
// set SDA to 0
clear_SDA();
I2C_delay();
set_SCL();
uint8_t timeout = TIMEOUT;
while (read_SCL() == 0 && timeout) { // Clock stretching
I2C_delay();
timeout--;
}
if (0 == timeout) {
return false;
}
I2C_delay(); // Stop bit setup time, minimum 4us
// SCL is high, set SDA from 0 to 1
set_SDA();
I2C_delay();
if (read_SDA() == 0) {
return false;
}
started = false;
return true;
}
// Write a bit to I²C bus
static bool softi2c_master_write_bit(bool bit) {
// set data bit
if (bit) {
set_SDA();
} else {
clear_SDA();
}
I2C_delay(); // SDA change propagation delay
set_SCL(); // Set SCL high to indicate a new valid SDA value is available
I2C_delay(); // Wait for SDA value to be read by slave, minimum of 4us for standard mode
uint8_t timeout = TIMEOUT;
while (read_SCL() == 0 && timeout) { // Clock stretching
I2C_delay();
timeout--;
}
if (0 == timeout) {
return false;
}
// SCL is high, now data is valid
if (bit && (read_SDA() == 0)) { // If SDA is high, check that nobody else is driving SDA
return false;
}
clear_SCL(); // Clear the SCL to low in preparation for next change
return true;
}
// Read a bit from I²C bus
static bool softi2c_master_read_bit(void) {
set_SDA(); // Let the slave drive data
I2C_delay(); // Wait for SDA value to be written by slave, minimum of 4us for standard mode
set_SCL(); // Set SCL high to indicate a new valid SDA value is available
uint8_t timeout = TIMEOUT;
while (read_SCL() == 0 && timeout) { // Clock stretching
I2C_delay();
timeout--;
}
if (0 == timeout) {
return false;
}
I2C_delay(); // Wait for SDA value to be written by slave, minimum of 4us for standard mode
const bool bit = read_SDA(); // SCL is high, read out bit
clear_SCL(); // Set SCL low in preparation for next operation
return bit;
}
// Write a byte to I2C bus. Return true if ACK by the slave.
static bool softi2c_master_write_byte(uint8_t byte)
{
for (uint8_t bit = 0; bit < 8; ++bit) {
softi2c_master_write_bit((byte & 0x80) != 0);
byte <<= 1;
}
const bool nack = softi2c_master_read_bit();
return !nack;
}
// Read a byte from I²C bus
static uint8_t softi2c_master_read_byte(bool nack)
{
uint8_t byte = 0;
for (uint8_t bit = 0; bit < 8; ++bit) {
byte = (byte << 1) | softi2c_master_read_bit();
}
softi2c_master_write_bit(nack);
return byte;
}
bool softi2c_master_select_slave(uint8_t slave, bool write)
{
if (!softi2c_master_start()) { // send (re-)start condition
return false;
}
const uint8_t byte = (slave << 1) | (write ? 0 : 1); // select slave, with read/write flag
return softi2c_master_write_byte(byte); // select slave
}
bool softi2c_master_read(uint8_t* data, uint16_t data_size)
{
if (NULL == data || 0 == data_size) { // no data to read
return false;
}
for (uint16_t i = 0; i < data_size; i++) { // read bytes
IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog
if (1 == (data_size - i)) { // last byte
data[i] = softi2c_master_read_byte(true); // NACK after reading byte
} else {
data[i] = softi2c_master_read_byte(false); // ACK after reading byte
}
}
return softi2c_master_stop();
}
bool softi2c_master_write(const uint8_t* data, uint16_t data_size)
{
if (NULL == data || 0 == data_size) { // no data to read
return true; // we don't indicate an error because the stop is done separately
}
// write data
for (uint16_t i = 0; i < data_size; i++) { // write bytes
if (!softi2c_master_write_byte(data[i])) { // write byte
return false;
}
}
return true;
}
bool softi2c_master_slave_read(uint8_t slave, uint8_t* data, uint16_t data_size)
{
if (NULL == data && data_size > 0) { // no data to read
return false;
}
if (!softi2c_master_select_slave(slave, false)) { // select slave to read
softi2c_master_stop();
return false;
}
if (NULL != data && data_size > 0) { // only read data if needed
if (!softi2c_master_read(data, data_size)) { // read data (includes stop)
return false;
}
}
return true;
}
bool softi2c_master_slave_write(uint8_t slave, const uint8_t* data, uint16_t data_size)
{
if (NULL == data && data_size > 0) { // no data to read
return false;
}
bool rc = false;
if (!softi2c_master_select_slave(slave, true)) { // select slave to write
goto error;
}
if (NULL != data && data_size > 0) { // write data only is some is available
if (!softi2c_master_write(data, data_size)) { // write data
goto error;
}
}
rc = true; // all went well
error:
rc = softi2c_master_stop() && rc; // sent stop condition
return rc;
}
bool softi2c_master_address_read(uint8_t slave, const uint8_t* address, uint16_t address_size, uint8_t* data, uint16_t data_size)
{
if (address_size > 0 && NULL == address) {
return false;
}
if (data_size > 0 && NULL == data) {
return false;
}
bool rc = false;
rc = softi2c_master_select_slave(slave, true); // select slave to write
if (!rc) {
goto error;
}
// write address
if (NULL != address && address_size > 0) {
rc = softi2c_master_write(address, address_size); // send memory address
if (!rc) {
goto error;
}
}
// read data
if (NULL != data && data_size > 0) {
rc = softi2c_master_select_slave(slave, false); // re-select slave to read
if (!rc) {
goto error;
}
rc = softi2c_master_read(data, data_size); // read memory (includes stop)
if (!rc) {
goto error;
}
} else {
softi2c_master_stop(); // sent stop condition
}
rc = true;
error:
if (!rc) { // only send stop on error
softi2c_master_stop(); // sent stop condition
}
return rc;
}
bool softi2c_master_address_write(uint8_t slave, const uint8_t* address, uint16_t address_size, const uint8_t* data, uint16_t data_size)
{
if (address_size > 0 && NULL == address) {
return false;
}
if (data_size > 0 && NULL == data) {
return false;
}
bool rc = false;
rc = softi2c_master_select_slave(slave, true); // select slave to write
if (!rc) {
goto error;
}
if (address_size && address) {
rc = softi2c_master_write(address, address_size); // send memory address
if (!rc) {
goto error;
}
}
if (data_size && data) {
rc = softi2c_master_write(data, data_size); // send memory data
if (!rc) {
goto error;
}
}
rc = softi2c_master_stop(); // sent stop condition
if (!rc) {
return false;
}
rc = true; // all went fine
error:
if (!rc) {
softi2c_master_stop(); // send stop on error
}
return rc;
}

View File

@ -1,83 +0,0 @@
/** library to communicate using I²C as master, implemented in software
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
* @date 2021
*/
#pragma once
/** setup I²C peripheral
* @param[in] freq_khz desired clock frequency, in kHz
* @return if I²C bus is ready
*/
bool softi2c_master_setup(uint16_t freq_khz);
/** release I²C peripheral */
void softi2c_master_release(void);
/** send start condition
* @return if start sent (else arbitration lost)
*/
bool softi2c_master_start(void);
/** sent stop condition
* @param[in] i2c I²C base address
* @return if stop sent (else arbitration lost)
*/
bool softi2c_master_stop(void);
/** select I²C slave device
* @param[in] slave I²C address of slave device to select
* @param[in] write this transaction will be followed by a read (false) or write (true) operation
* @return if slave ACKed
* @note includes (re-)start condition
*/
bool softi2c_master_select_slave(uint8_t slave, 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 if read succeeded (else arbitration lost)
* @warning the slave device must be selected before this operation
* @note includes sending stop (after having NACKed last received byte)
*/
bool softi2c_master_read(uint8_t* data, uint16_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 if write succeeded (else data has been NACKed)
* @warning the slave device must be selected before this operation
* @note no stop condition is sent at the end, allowing multiple writes
*/
bool softi2c_master_write(const uint8_t* data, uint16_t data_size);
/** read data from slave device
* @param[in] slave I²C address of slave device to select
* @param[out] data array to store bytes read
* @param[in] data_size number of bytes to read
* @return if read succeeded (else arbitration has been lost)
* @note start and stop conditions are included
*/
bool softi2c_master_slave_read(uint8_t slave, uint8_t* data, uint16_t data_size);
/** write data to slave device
* @param[in] slave I²C 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 if write succeeded
* @note start and stop conditions are included
*/
bool softi2c_master_slave_write(uint8_t slave, const uint8_t* data, uint16_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 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 if read succeeded
* @note start and stop conditions are included
*/
bool softi2c_master_address_read(uint8_t slave, const uint8_t* address, uint16_t address_size, uint8_t* data, uint16_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 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 if write succeeded
* @note start and stop conditions are included
*/
bool softi2c_master_address_write(uint8_t slave, const uint8_t* address, uint16_t address_size, const uint8_t* data, uint16_t data_size);

645
stm8s.h
View File

@ -94,14 +94,14 @@ typedef struct {
#define PA_DDR (*(volatile uint8_t *)(PA_BASE + 0x02))
#define PA_CR1 (*(volatile uint8_t *)(PA_BASE + 0x03))
#define PA_CR2 (*(volatile uint8_t *)(PA_BASE + 0x04))
#define PA0 (1U << 0)
#define PA1 (1U << 1)
#define PA2 (1U << 2)
#define PA3 (1U << 3)
#define PA4 (1U << 4)
#define PA5 (1U << 5)
#define PA6 (1U << 6)
#define PA7 ((uint8_t)(1U << 7))
#define PA0 (1 << 0)
#define PA1 (1 << 1)
#define PA2 (1 << 2)
#define PA3 (1 << 3)
#define PA4 (1 << 4)
#define PA5 (1 << 5)
#define PA6 (1 << 6)
#define PA7 ((uint8_t)(1 << 7))
// Block: Port B
#define PB_BASE 0x5005
#define GPIO_PB ((GPIO_type*)PB_BASE)
@ -110,14 +110,14 @@ typedef struct {
#define PB_DDR (*(volatile uint8_t *)(PB_BASE + 0x02))
#define PB_CR1 (*(volatile uint8_t *)(PB_BASE + 0x03))
#define PB_CR2 (*(volatile uint8_t *)(PB_BASE + 0x04))
#define PB0 (1U << 0)
#define PB1 (1U << 1)
#define PB2 (1U << 2)
#define PB3 (1U << 3)
#define PB4 (1U << 4)
#define PB5 (1U << 5)
#define PB6 (1U << 6)
#define PB7 ((uint8_t)(1U << 7))
#define PB0 (1 << 0)
#define PB1 (1 << 1)
#define PB2 (1 << 2)
#define PB3 (1 << 3)
#define PB4 (1 << 4)
#define PB5 (1 << 5)
#define PB6 (1 << 6)
#define PB7 ((uint8_t)(1 << 7))
// Block: Port C
#define PC_BASE 0x500A
#define GPIO_PC ((GPIO_type*)PC_BASE)
@ -126,14 +126,14 @@ typedef struct {
#define PC_DDR (*(volatile uint8_t *)(PC_BASE + 0x02))
#define PC_CR1 (*(volatile uint8_t *)(PC_BASE + 0x03))
#define PC_CR2 (*(volatile uint8_t *)(PC_BASE + 0x04))
#define PC0 (1U << 0)
#define PC1 (1U << 1)
#define PC2 (1U << 2)
#define PC3 (1U << 3)
#define PC4 (1U << 4)
#define PC5 (1U << 5)
#define PC6 (1U << 6)
#define PC7 ((uint8_t)(1U << 7))
#define PC0 (1 << 0)
#define PC1 (1 << 1)
#define PC2 (1 << 2)
#define PC3 (1 << 3)
#define PC4 (1 << 4)
#define PC5 (1 << 5)
#define PC6 (1 << 6)
#define PC7 ((uint8_t)(1 << 7))
// Block: Port D
#define PD_BASE 0x500F
#define GPIO_PD ((GPIO_type*)PD_BASE)
@ -142,14 +142,14 @@ typedef struct {
#define PD_DDR (*(volatile uint8_t *)(PD_BASE + 0x02))
#define PD_CR1 (*(volatile uint8_t *)(PD_BASE + 0x03))
#define PD_CR2 (*(volatile uint8_t *)(PD_BASE + 0x04))
#define PD0 (1U << 0)
#define PD1 (1U << 1)
#define PD2 (1U << 2)
#define PD3 (1U << 3)
#define PD4 (1U << 4)
#define PD5 (1U << 5)
#define PD6 (1U << 6)
#define PD7 ((uint8_t)(1U << 7))
#define PD0 (1 << 0)
#define PD1 (1 << 1)
#define PD2 (1 << 2)
#define PD3 (1 << 3)
#define PD4 (1 << 4)
#define PD5 (1 << 5)
#define PD6 (1 << 6)
#define PD7 ((uint8_t)(1 << 7))
// Block: Port E
#define PE_BASE 0x5014
#define GPIO_PE ((GPIO_type*)PE_BASE)
@ -158,14 +158,14 @@ typedef struct {
#define PE_DDR (*(volatile uint8_t *)(PE_BASE + 0x02))
#define PE_CR1 (*(volatile uint8_t *)(PE_BASE + 0x03))
#define PE_CR2 (*(volatile uint8_t *)(PE_BASE + 0x04))
#define PE0 (1U << 0)
#define PE1 (1U << 1)
#define PE2 (1U << 2)
#define PE3 (1U << 3)
#define PE4 (1U << 4)
#define PE5 (1U << 5)
#define PE6 (1U << 6)
#define PE7 ((uint8_t)(1U << 7))
#define PE0 (1 << 0)
#define PE1 (1 << 1)
#define PE2 (1 << 2)
#define PE3 (1 << 3)
#define PE4 (1 << 4)
#define PE5 (1 << 5)
#define PE6 (1 << 6)
#define PE7 ((uint8_t)(1 << 7))
// Block: Port F
#define PF_BASE 0x5019
#define GPIO_PF ((GPIO_type*)PF_BASE)
@ -174,14 +174,14 @@ typedef struct {
#define PF_DDR (*(volatile uint8_t *)(PF_BASE + 0x02))
#define PF_CR1 (*(volatile uint8_t *)(PF_BASE + 0x03))
#define PF_CR2 (*(volatile uint8_t *)(PF_BASE + 0x04))
#define PF0 (1U << 0)
#define PF1 (1U << 1)
#define PF2 (1U << 2)
#define PF3 (1U << 3)
#define PF4 (1U << 4)
#define PF5 (1U << 5)
#define PF6 (1U << 6)
#define PF7 ((uint8_t)(1U << 7))
#define PF0 (1 << 0)
#define PF1 (1 << 1)
#define PF2 (1 << 2)
#define PF3 (1 << 3)
#define PF4 (1 << 4)
#define PF5 (1 << 5)
#define PF6 (1 << 6)
#define PF7 ((uint8_t)(1 << 7))
// General hardware register map
// Block: Flash
@ -285,48 +285,48 @@ typedef struct {
#define FLASH_BASE 0x505A
#define FLASH ((FLASH_type*)FLASH_BASE)
#define FLASH_CR1 (*(volatile uint8_t *)(FLASH_BASE + 0x00))
#define FLASH_CR1_FIX (1U << 0)
#define FLASH_CR1_IE (1U << 1)
#define FLASH_CR1_AHALT (1U << 2)
#define FLASH_CR1_HALT (1U << 3)
#define FLASH_CR1_FIX (1 << 0)
#define FLASH_CR1_IE (1 << 1)
#define FLASH_CR1_AHALT (1 << 2)
#define FLASH_CR1_HALT (1 << 3)
#define FLASH_CR2 (*(volatile uint8_t *)(FLASH_BASE + 0x01))
#define FLASH_CR2_PRG (1U << 0)
#define FLASH_CR2_FPRG (1U << 4)
#define FLASH_CR2_ERASE (1U << 5)
#define FLASH_CR2_WPRG (1U << 6)
#define FLASH_CR2_OPT (1U << 7)
#define FLASH_CR2_PRG (1 << 0)
#define FLASH_CR2_FPRG (1 << 4)
#define FLASH_CR2_ERASE (1 << 5)
#define FLASH_CR2_WPRG (1 << 6)
#define FLASH_CR2_OPT (1 << 7)
#define FLASH_NCR2 (*(volatile uint8_t *)(FLASH_BASE + 0x02))
#define FLASH_NCR2_NPRG (1U << 0)
#define FLASH_NCR2_NFPRG (1U << 4)
#define FLASH_NCR2_NERASE (1U << 5)
#define FLASH_NCR2_NWPRG (1U << 6)
#define FLASH_NCR2_NOPT (1U << 7)
#define FLASH_NCR2_NPRG (1 << 0)
#define FLASH_NCR2_NFPRG (1 << 4)
#define FLASH_NCR2_NERASE (1 << 5)
#define FLASH_NCR2_NWPRG (1 << 6)
#define FLASH_NCR2_NOPT (1 << 7)
#define FLASH_FPR (*(volatile uint8_t *)(FLASH_BASE + 0x03))
#define FLASH_FPR_WPB0 (1U << 0)
#define FLASH_FPR_WPB1 (1U << 1)
#define FLASH_FPR_WPB2 (1U << 2)
#define FLASH_FPR_WPB3 (1U << 3)
#define FLASH_FPR_WPB4 (1U << 4)
#define FLASH_FPR_WPB5 (1U << 5)
#define FLASH_FPR_WPB0 (1 << 0)
#define FLASH_FPR_WPB1 (1 << 1)
#define FLASH_FPR_WPB2 (1 << 2)
#define FLASH_FPR_WPB3 (1 << 3)
#define FLASH_FPR_WPB4 (1 << 4)
#define FLASH_FPR_WPB5 (1 << 5)
#define FLASH_NFPR (*(volatile uint8_t *)(FLASH_BASE + 0x04))
#define FLASH_NFPR_NWPB0 (1U << 0)
#define FLASH_NFPR_NWPB1 (1U << 1)
#define FLASH_NFPR_NWPB2 (1U << 2)
#define FLASH_NFPR_NWPB3 (1U << 3)
#define FLASH_NFPR_NWPB4 (1U << 4)
#define FLASH_NFPR_NWPB5 (1U << 5)
#define FLASH_NFPR_NWPB0 (1 << 0)
#define FLASH_NFPR_NWPB1 (1 << 1)
#define FLASH_NFPR_NWPB2 (1 << 2)
#define FLASH_NFPR_NWPB3 (1 << 3)
#define FLASH_NFPR_NWPB4 (1 << 4)
#define FLASH_NFPR_NWPB5 (1 << 5)
#define FLASH_IAPSR (*(volatile uint8_t *)(FLASH_BASE + 0x05))
#define FLASH_IAPSR_WR_PG_DIS (1U << 0)
#define FLASH_IAPSR_PUL (1U << 1)
#define FLASH_IAPSR_EOP (1U << 2)
#define FLASH_IAPSR_DUL (1U << 3)
#define FLASH_IAPSR_HVOFF (1U << 6)
#define FLASH_IAPSR_WR_PG_DIS (1 << 0)
#define FLASH_IAPSR_PUL (1 << 1)
#define FLASH_IAPSR_EOP (1 << 2)
#define FLASH_IAPSR_DUL (1 << 3)
#define FLASH_IAPSR_HVOFF (1 << 6)
#define FLASH_PUKR (*(volatile uint8_t *)(FLASH_BASE + 0x08))
#define FLASH_PUKR_KEY1 0x56
#define FLASH_PUKR_KEY2 0xAE
#define FLASH_DUKR (*(volatile uint8_t *)(FLASH_BASE + 0x0A))
#define FLASH_DUKR_KEY1 0xAE
#define FLASH_DUKR_KEY2 0x56
#define FLASH_DUKR_KEY1 0x56
#define FLASH_DUKR_KEY2 0xAE
// Block: ITC
@ -367,7 +367,7 @@ typedef struct {
#define EXTI_CR2 (*(volatile uint8_t *)(EXTI_BASE + 0x01))
#define EXTI_CR2_PEIS_OFFSET 0
#define EXTI_CR2_PEIS_MASK 0x3
#define EXTI_CR2_TLIS (1U << 2)
#define EXTI_CR2_TLIS (1 << 2)
#define EXTI_FALLING_EDGE_LOW_LEVEL 0
#define EXTI_RISING_EDGE 1
#define EXTI_FALLING_EDGE 2
@ -392,11 +392,11 @@ typedef struct {
#define RST_BASE 0x50B3
#define RST ((RST_type*)RST_BASE)
#define RST_SR (*(volatile uint8_t *)(RST_BASE + 0x00))
#define RST_SR_WWDGF (1U << 0)
#define RST_SR_IWDGF (1U << 1)
#define RST_SR_ILLOPF (1U << 2)
#define RST_SR_SWIMF (1U << 3)
#define RST_SR_EMCF (1U << 4)
#define RST_SR_WWDGF (1 << 0)
#define RST_SR_IWDGF (1 << 1)
#define RST_SR_ILLOPF (1 << 2)
#define RST_SR_SWIMF (1 << 3)
#define RST_SR_EMCF (1 << 4)
// Block: CLK
typedef union {
@ -533,15 +533,15 @@ typedef struct {
#define CLK_BASE 0x50C0
#define CLK ((CLK_type*)CLK_BASE)
#define CLK_ICKR (*(volatile uint8_t *)(CLK_BASE + 0x00))
#define CLK_ICKR_HSIEN (1U << 0)
#define CLK_ICKR_HSIRDY (1U << 1)
#define CLK_ICKR_FHW (1U << 2)
#define CLK_ICKR_LSIEN (1U << 3)
#define CLK_ICKR_LSIRDY (1U << 4)
#define CLK_ICKR_REGAH (1U << 5)
#define CLK_ICKR_HSIEN (1 << 0)
#define CLK_ICKR_HSIRDY (1 << 1)
#define CLK_ICKR_FHW (1 << 2)
#define CLK_ICKR_LSIEN (1 << 3)
#define CLK_ICKR_LSIRDY (1 << 4)
#define CLK_ICKR_REGAH (1 << 5)
#define CLK_ECKR (*(volatile uint8_t *)(CLK_BASE + 0x01))
#define CLK_ECKR_HSEEN (1U << 0)
#define CLK_ECKR_HSERDY (1U << 1)
#define CLK_ECKR_HSEEN (1 << 0)
#define CLK_ECKR_HSERDY (1 << 1)
#define CLK_CMSR (*(volatile uint8_t *)(CLK_BASE + 0x03))
#define CLK_CMSR_CKM_OFFSET 0
#define CLK_CMSR_CKM_MASK 0xff
@ -552,10 +552,10 @@ typedef struct {
#define CLK_SWR_SWI_OFFSET 0
#define CLK_SWR_SWI_MASK 0xff
#define CLK_SWCR (*(volatile uint8_t *)(CLK_BASE + 0x05))
#define CLK_SWCR_SWBSY (1U << 0)
#define CLK_SWCR_SWEN (1U << 1)
#define CLK_SWCR_SWIEN (1U << 2)
#define CLK_SWCR_SWIF (1U << 3)
#define CLK_SWCR_SWBSY (1 << 0)
#define CLK_SWCR_SWEN (1 << 1)
#define CLK_SWCR_SWIEN (1 << 2)
#define CLK_SWCR_SWIF (1 << 3)
#define CLK_CKDIVR (*(volatile uint8_t *)(CLK_BASE + 0x06))
#define CLK_CKDIVR_CPUDIV_OFFSET 0
#define CLK_CKDIVR_CPUDIV_MASK 0x7
@ -574,20 +574,20 @@ typedef struct {
#define CLK_CKDIVR_HSIDIV_DIV4 2
#define CLK_CKDIVR_HSIDIV_DIV8 3
#define CLK_PCKENR1 (*(volatile uint8_t *)(CLK_BASE + 0x07))
#define CLK_PCKENR1_I2C (1U << 0)
#define CLK_PCKENR1_SPI (1U << 1)
#define CLK_PCKENR1_UART1234 (3U << 2)
#define CLK_PCKENR1_TIM46 (1U << 4)
#define CLK_PCKENR1_TIM25 (1U << 5)
#define CLK_PCKENR1_TIM3 (1U << 6)
#define CLK_PCKENR1_TIM1 (1U << 7)
#define CLK_PCKENR1_I2C (1 << 0)
#define CLK_PCKENR1_SPI (1 << 1)
#define CLK_PCKENR1_UART1234 (3 << 2)
#define CLK_PCKENR1_TIM46 (1 << 4)
#define CLK_PCKENR1_TIM25 (1 << 5)
#define CLK_PCKENR1_TIM3 (1 << 6)
#define CLK_PCKENR1_TIM1 (1 << 7)
#define CLK_CSSR (*(volatile uint8_t *)(CLK_BASE + 0x08))
#define CLK_CSSR_CSSEN (1U << 0)
#define CLK_CSSR_AUX (1U << 1)
#define CLK_CSSR_CSSDIE (1U << 2)
#define CLK_CSSR_CSSD (1U << 3)
#define CLK_CSSR_CSSEN (1 << 0)
#define CLK_CSSR_AUX (1 << 1)
#define CLK_CSSR_CSSDIE (1 << 2)
#define CLK_CSSR_CSSD (1 << 3)
#define CLK_CCOR (*(volatile uint8_t *)(CLK_BASE + 0x09))
#define CLK_CCOR_CCOEN (1U << 0)
#define CLK_CCOR_CCOEN (1 << 0)
#define CLK_CCOR_CCOSEL_OFFSET 1
#define CLK_CCOR_CCOSEL_MASK 0xf
#define CLK_CCOR_CCOSEL_HSIDIV 0
@ -602,17 +602,17 @@ typedef struct {
#define CLK_CCOR_CCOSEL_CPU_DIV64 10
#define CLK_CCOR_CCOSEL_HSI 11
#define CLK_CCOR_CCOSEL_MASTER 12
#define CLK_CCOR_CCORDY (1U << 5)
#define CLK_CCOR_CCOBSY (1U << 6)
#define CLK_CCOR_CCORDY (1 << 5)
#define CLK_CCOR_CCOBSY (1 << 6)
#define CLK_PCKENR2 (*(volatile uint8_t *)(CLK_BASE + 0x0A))
#define CLK_PCKENR2_AWU (1U << 2)
#define CLK_PCKENR2_ADC (1U << 3)
#define CLK_PCKENR2_CAN (1U << 7)
#define CLK_PCKENR2_AWU (1 << 2)
#define CLK_PCKENR2_ADC (1 << 3)
#define CLK_PCKENR2_CAN (1 << 7)
#define CLK_HSITRIMR (*(volatile uint8_t *)(CLK_BASE + 0x0C))
#define CLK_HSITRIMR_OFFSET 0
#define CLK_HSITRIMR_MASK 0xf
#define CLK_SWIMCCR (*(volatile uint8_t *)(CLK_BASE + 0x0D))
#define CLK_SWIMCCR_SWIMCLK (1U << 0)
#define CLK_SWIMCCR_SWIMCLK (1 << 0)
// Block: WWDG
typedef union {
@ -652,14 +652,14 @@ typedef struct {
#define WWDG_CR (*(volatile uint8_t *)(WWDG_BASE + 0x00))
#define WWDG_CR_T_OFFSET 0
#define WWDG_CR_T_MASK 0x7f
#define WWDG_CR_T0 (1U << 0)
#define WWDG_CR_T1 (1U << 1)
#define WWDG_CR_T2 (1U << 2)
#define WWDG_CR_T3 (1U << 3)
#define WWDG_CR_T4 (1U << 4)
#define WWDG_CR_T5 (1U << 5)
#define WWDG_CR_T6 (1U << 6)
#define WWDG_CR_WDGA (1U << 7)
#define WWDG_CR_T0 (1 << 0)
#define WWDG_CR_T1 (1 << 1)
#define WWDG_CR_T2 (1 << 2)
#define WWDG_CR_T3 (1 << 3)
#define WWDG_CR_T4 (1 << 4)
#define WWDG_CR_T5 (1 << 5)
#define WWDG_CR_T6 (1 << 6)
#define WWDG_CR_WDGA (1 << 7)
#define WWDG_WR (*(volatile uint8_t *)(WWDG_BASE + 0x01))
#define WWDG_WR_W_OFFSET 0
#define WWDG_WR_W_MASK 0x7f
@ -742,9 +742,9 @@ typedef struct {
#define AWU_BASE 0x50F0
#define AWU ((AWU_type*)AWU_BASE)
#define AWU_CSR (*(volatile uint8_t *)(AWU_BASE + 0x00))
#define AWU_CSR_MSR (1U << 0)
#define AWU_CSR_AWUEN (1U << 4)
#define AWU_CSR_AWUF (1U << 5)
#define AWU_CSR_MSR (1 << 0)
#define AWU_CSR_AWUEN (1 << 4)
#define AWU_CSR_AWUF (1 << 5)
#define AWU_APR (*(volatile uint8_t *)(AWU_BASE + 0x01))
#define AWU_TBR (*(volatile uint8_t *)(AWU_BASE + 0x02))
@ -1016,50 +1016,48 @@ typedef struct {
#define I2C_BASE 0x5210
#define I2C ((I2C_type*)I2C_BASE)
#define I2C_CR1 (*(volatile uint8_t *)(I2C_BASE + 0x00))
#define I2C_CR1_PE (1U << 0)
#define I2C_CR1_ENGC (1U << 6)
#define I2C_CR1_NOSTRETCH (1U << 7)
#define I2C_CR1_PE (1 << 0)
#define I2C_CR1_ENGC (1 << 6)
#define I2C_CR1_NOSTRETCH (1 << 7)
#define I2C_CR2 (*(volatile uint8_t *)(I2C_BASE + 0x01))
#define I2C_CR2_START (1U << 0)
#define I2C_CR2_STOP (1U << 1)
#define I2C_CR2_ACK (1U << 2)
#define I2C_CR2_POS (1U << 3)
#define I2C_CR2_SWRST (1U << 7)
#define I2C_CR2_START (1 << 0)
#define I2C_CR2_STOP (1 << 1)
#define I2C_CR2_ACK (1 << 2)
#define I2C_CR2_POS (1 << 3)
#define I2C_CR2_SWRST (1 << 7)
#define I2C_FREQR (*(volatile uint8_t *)(I2C_BASE + 0x02))
#define I2C_OARL (*(volatile uint8_t *)(I2C_BASE + 0x03))
#define I2C_OARL_ARR0 (1U << 0)
#define I2C_OARL_ARR0 (1 << 0)
#define I2C_OARH (*(volatile uint8_t *)(I2C_BASE + 0x04))
#define I2C_OARH_ADDCONF (1U << 6)
#define I2C_OARH_ADDMODE (1U << 7)
#define I2C_OARH_ADDCONF (1 << 6)
#define I2C_OARH_ADDMODE (1 << 7)
#define I2C_DR (*(volatile uint8_t *)(I2C_BASE + 0x06))
#define I2C_SR1 (*(volatile uint8_t *)(I2C_BASE + 0x07))
#define I2C_SR1_SB (1U << 0)
#define I2C_SR1_ADDR (1U << 1)
#define I2C_SR1_BTF (1U << 2)
#define I2C_SR1_ADD10 (1U << 3)
#define I2C_SR1_STOPF (1U << 4)
#define I2C_SR1_RXNE (1U << 6)
#define I2C_SR1_TXE (1U << 7)
#define I2C_SR1_SB (1 << 0)
#define I2C_SR1_ADDR (1 << 1)
#define I2C_SR1_BTF (1 << 2)
#define I2C_SR1_ADD10 (1 << 3)
#define I2C_SR1_STOPF (1 << 4)
#define I2C_SR1_RXNE (1 << 6)
#define I2C_SR1_TXE (1 << 7)
#define I2C_SR2 (*(volatile uint8_t *)(I2C_BASE + 0x08))
#define I2C_SR2_BERR (1U << 0)
#define I2C_SR2_ARLO (1U << 1)
#define I2C_SR2_AF (1U << 2)
#define I2C_SR2_OVR (1U << 3)
#define I2C_SR2_WUFH (1U << 5)
#define I2C_SR2_BERR (1 << 0)
#define I2C_SR2_ARLO (1 << 1)
#define I2C_SR2_AF (1 << 2)
#define I2C_SR2_OVR (1 << 3)
#define I2C_SR2_WUFH (1 << 5)
#define I2C_SR3 (*(volatile uint8_t *)(I2C_BASE + 0x09))
#define I2C_SR3_MSL (1U << 0)
#define I2C_SR3_BUSY (1U << 1)
#define I2C_SR3_TRA (1U << 2)
#define I2C_SR3_GENCALL (1U << 4)
#define I2C_SR3_DUALF (1U << 7)
#define I2C_SR3_MSL (1 << 0)
#define I2C_SR3_BUSY (1 << 1)
#define I2C_SR3_TRA (1 << 2)
#define I2C_SR3_GENCALL (1 << 4)
#define I2C_SR3_DUALF (1 << 7)
#define I2C_ITR (*(volatile uint8_t *)(I2C_BASE + 0x0A))
#define I2C_ITR_ITERREN (1U << 0)
#define I2C_ITR_ITEVTEN (1U << 1)
#define I2C_ITR_ITBUFEN (1U << 2)
#define I2C_ITR_ITERREN (1 << 0)
#define I2C_ITR_ITEVTEN (1 << 1)
#define I2C_ITR_ITBUFEN (1 << 2)
#define I2C_CCRL (*(volatile uint8_t *)(I2C_BASE + 0x0B))
#define I2C_CCRH (*(volatile uint8_t *)(I2C_BASE + 0x0C))
#define I2C_CCRH_DUTY (1U << 6)
#define I2C_CCRH_FS (1U << 7)
#define I2C_TRISER (*(volatile uint8_t *)(I2C_BASE + 0x0D))
#define I2C_PECR (*(volatile uint8_t *)(I2C_BASE + 0x0E))
@ -1895,7 +1893,7 @@ typedef union {
uint8_t OC1PE:1; /*!< bit 3: Output compare 1 preload enable */
uint8_t OC1M:3; /*!< bit 4..6: Output compare 1 mode */
uint8_t OC1CE:1; /*!< bit 7: Output compare 1 clear enable */
} output_fields; /*!< structure used for bit access */
} outpur_fields; /*!< structure used for bit access */
struct {
uint8_t CC1S:2; /*!< bit 0..1: Capture/compare 1 selection */
uint8_t IC1PSC:2; /*!< bit 2..3: Input capture 1 prescaler */
@ -1910,7 +1908,7 @@ typedef union {
uint8_t :1; /*!< bit 2: Reserved */
uint8_t OC1PE:1; /*!< bit 3: Output compare 1 preload enable */
uint8_t OC1M:3; /*!< bit 4..6: Output compare 1 mode */
} output_fields; /*!< structure used for bit access */
} outpur_fields; /*!< structure used for bit access */
struct {
uint8_t CC1S:2; /*!< bit 0..1: Capture/compare 1 selection */
uint8_t IC1PSC:2; /*!< bit 2..3: Input capture 1 prescaler */
@ -2386,36 +2384,36 @@ typedef struct {
// Block: TIM2
#define TIM2_CR1 (*(volatile uint8_t *)(TIM2_BASE + 0x00))
#define TIM2_CR1_CEN (1U << 0)
#define TIM2_CR1_UDIS (1U << 1)
#define TIM2_CR1_URS (1U << 2)
#define TIM2_CR1_OPM (1U << 3)
#define TIM2_CR1_APRE (1U << 7)
#define TIM2_CR1_CEN (1 << 0)
#define TIM2_CR1_UDIS (1 << 1)
#define TIM2_CR1_URS (1 << 2)
#define TIM2_CR1_OPM (1 << 3)
#define TIM2_CR1_APRE (1 << 7)
#define TIM2_IER (*(volatile uint8_t *)(TIM2_BASE + 0x03))
#define TIM2_IER_UIE (1U << 0)
#define TIM2_IER_CC1IE (1U << 1)
#define TIM2_IER_CC2IE (1U << 2)
#define TIM2_IER_CC3IE (1U << 3)
#define TIM2_IER_TIE (1U << 6)
#define TIM2_IER_UIE (1 << 0)
#define TIM2_IER_CC1IE (1 << 1)
#define TIM2_IER_CC2IE (1 << 2)
#define TIM2_IER_CC3IE (1 << 3)
#define TIM2_IER_TIE (1 << 6)
#define TIM2_SR1 (*(volatile uint8_t *)(TIM2_BASE + 0x04))
#define TIM2_SR1_UIF (1U << 0)
#define TIM2_SR1_CC1IF (1U << 1)
#define TIM2_SR1_CC2IF (1U << 2)
#define TIM2_SR1_CC3IF (1U << 3)
#define TIM2_SR1_TIF (1U << 6)
#define TIM2_SR1_UIF (1 << 0)
#define TIM2_SR1_CC1IF (1 << 1)
#define TIM2_SR1_CC2IF (1 << 2)
#define TIM2_SR1_CC3IF (1 << 3)
#define TIM2_SR1_TIF (1 << 6)
#define TIM2_SR2 (*(volatile uint8_t *)(TIM2_BASE + 0x05))
#define TIM2_SR2_CC1OF (1U << 1)
#define TIM2_SR2_CC2OF (1U << 2)
#define TIM2_SR2_CC3OF (1U << 3)
#define TIM2_SR2_CC1OF (1 << 1)
#define TIM2_SR2_CC2OF (1 << 2)
#define TIM2_SR2_CC3OF (1 << 3)
#define TIM2_EGR (*(volatile uint8_t *)(TIM2_BASE + 0x06))
#define TIM2_EGR_CC1G (1U << 1)
#define TIM2_EGR_CC2G (1U << 2)
#define TIM2_EGR_CC3G (1U << 3)
#define TIM2_EGR_TG (1U << 6)
#define TIM2_EGR_CC1G (1 << 1)
#define TIM2_EGR_CC2G (1 << 2)
#define TIM2_EGR_CC3G (1 << 3)
#define TIM2_EGR_TG (1 << 6)
#define TIM2_CCMR1 (*(volatile uint8_t *)(TIM2_BASE + 0x07))
#define TIM2_CCMR1_CC1S_OFFSET 0
#define TIM2_CCMR1_CC1S_MASK 0x3
#define TIM2_CCMR1_CC1PE (1U << 3)
#define TIM2_CCMR1_CC1PE (1 << 3)
#define TIM2_CCMR1_OC1M_OFFSET 4
#define TIM2_CCMR1_OC1M_MASK 0x7
#define TIM2_CCMR1_CC1S_OFFSET 0
@ -2427,7 +2425,7 @@ typedef struct {
#define TIM2_CCMR2 (*(volatile uint8_t *)(TIM2_BASE + 0x08))
#define TIM2_CCMR2_CC2S_OFFSET 0
#define TIM2_CCMR2_CC2S_MASK 0x3
#define TIM2_CCMR2_CC2PE (1U << 3)
#define TIM2_CCMR2_CC2PE (1 << 3)
#define TIM2_CCMR2_OC2M_OFFSET 4
#define TIM2_CCMR2_OC2M_MASK 0x7
#define TIM2_CCMR2_CC2S_OFFSET 0
@ -2439,7 +2437,7 @@ typedef struct {
#define TIM2_CCMR3 (*(volatile uint8_t *)(TIM2_BASE + 0x09))
#define TIM2_CCMR3_CC3S_OFFSET 0
#define TIM2_CCMR3_CC3S_MASK 0x3
#define TIM2_CCMR3_CC3PE (1U << 3)
#define TIM2_CCMR3_CC3PE (1 << 3)
#define TIM2_CCMR3_OC3M_OFFSET 4
#define TIM2_CCMR3_OC3M_MASK 0x7
#define TIM2_CCMR3_CC3S_OFFSET 0
@ -2449,13 +2447,13 @@ typedef struct {
#define TIM2_CCMR3_IC3F_OFFSET 4
#define TIM2_CCMR3_IC3F_MASK 0xf
#define TIM2_CCER1 (*(volatile uint8_t *)(TIM2_BASE + 0x0A))
#define TIM2_CCER1_CC1E (1U << 0)
#define TIM2_CCER1_CC1P (1U << 1)
#define TIM2_CCER1_CC2E (1U << 4)
#define TIM2_CCER1_CC2P (1U << 5)
#define TIM2_CCER1_CC1E (1 << 0)
#define TIM2_CCER1_CC1P (1 << 1)
#define TIM2_CCER1_CC2E (1 << 4)
#define TIM2_CCER1_CC2P (1 << 5)
#define TIM2_CCER2 (*(volatile uint8_t *)(TIM2_BASE + 0x0B))
#define TIM2_CCER2_CC3E (1U << 0)
#define TIM2_CCER2_CC3P (1U << 1)
#define TIM2_CCER2_CC3E (1 << 0)
#define TIM2_CCER2_CC3P (1 << 1)
#define TIM2_CNTRH (*(volatile uint8_t *)(TIM2_BASE + 0x0C))
#define TIM2_CNTRL (*(volatile uint8_t *)(TIM2_BASE + 0x0D))
#define TIM2_PSCR (*(volatile uint8_t *)(TIM2_BASE + 0x0E))
@ -2472,36 +2470,36 @@ typedef struct {
// Block: TIM3
#define TIM3_CR1 (*(volatile uint8_t *)(TIM3_BASE + 0x00))
#define TIM3_CR1_CEN (1U << 0)
#define TIM3_CR1_UDIS (1U << 1)
#define TIM3_CR1_URS (1U << 2)
#define TIM3_CR1_OPM (1U << 3)
#define TIM3_CR1_APRE (1U << 7)
#define TIM3_CR1_CEN (1 << 0)
#define TIM3_CR1_UDIS (1 << 1)
#define TIM3_CR1_URS (1 << 2)
#define TIM3_CR1_OPM (1 << 3)
#define TIM3_CR1_APRE (1 << 7)
#define TIM3_IER (*(volatile uint8_t *)(TIM3_BASE + 0x01))
#define TIM3_IER_UIE (1U << 0)
#define TIM3_IER_CC1IE (1U << 1)
#define TIM3_IER_CC2IE (1U << 2)
#define TIM3_IER_CC3IE (1U << 3)
#define TIM3_IER_TIE (1U << 6)
#define TIM3_IER_UIE (1 << 0)
#define TIM3_IER_CC1IE (1 << 1)
#define TIM3_IER_CC2IE (1 << 2)
#define TIM3_IER_CC3IE (1 << 3)
#define TIM3_IER_TIE (1 << 6)
#define TIM3_SR1 (*(volatile uint8_t *)(TIM3_BASE + 0x02))
#define TIM3_SR1_UIF (1U << 0)
#define TIM3_SR1_CC1IF (1U << 1)
#define TIM3_SR1_CC2IF (1U << 2)
#define TIM3_SR1_CC3IF (1U << 3)
#define TIM3_SR1_TIF (1U << 6)
#define TIM3_SR1_UIF (1 << 0)
#define TIM3_SR1_CC1IF (1 << 1)
#define TIM3_SR1_CC2IF (1 << 2)
#define TIM3_SR1_CC3IF (1 << 3)
#define TIM3_SR1_TIF (1 << 6)
#define TIM3_SR2 (*(volatile uint8_t *)(TIM3_BASE + 0x03))
#define TIM3_SR2_CC1OF (1U << 1)
#define TIM3_SR2_CC2OF (1U << 2)
#define TIM3_SR2_CC3OF (1U << 3)
#define TIM3_SR2_CC1OF (1 << 1)
#define TIM3_SR2_CC2OF (1 << 2)
#define TIM3_SR2_CC3OF (1 << 3)
#define TIM3_EGR (*(volatile uint8_t *)(TIM3_BASE + 0x04))
#define TIM3_EGR_CC1G (1U << 1)
#define TIM3_EGR_CC2G (1U << 2)
#define TIM3_EGR_CC3G (1U << 3)
#define TIM3_EGR_TG (1U << 6)
#define TIM3_EGR_CC1G (1 << 1)
#define TIM3_EGR_CC2G (1 << 2)
#define TIM3_EGR_CC3G (1 << 3)
#define TIM3_EGR_TG (1 << 6)
#define TIM3_CCMR1 (*(volatile uint8_t *)(TIM3_BASE + 0x05))
#define TIM3_CCMR1_CC1S_OFFSET 0
#define TIM3_CCMR1_CC1S_MASK 0x3
#define TIM3_CCMR1_CC1PE (1U << 3)
#define TIM3_CCMR1_CC1PE (1 << 3)
#define TIM3_CCMR1_OC1M_OFFSET 4
#define TIM3_CCMR1_OC1M_MASK 0x7
#define TIM3_CCMR1_CC1S_OFFSET 0
@ -2513,7 +2511,7 @@ typedef struct {
#define TIM3_CCMR2 (*(volatile uint8_t *)(TIM3_BASE + 0x06))
#define TIM3_CCMR2_CC2S_OFFSET 0
#define TIM3_CCMR2_CC2S_MASK 0x3
#define TIM3_CCMR2_CC2PE (1U << 3)
#define TIM3_CCMR2_CC2PE (1 << 3)
#define TIM3_CCMR2_OC2M_OFFSET 4
#define TIM3_CCMR2_OC2M_MASK 0x7
#define TIM3_CCMR2_CC2S_OFFSET 0
@ -2523,10 +2521,10 @@ typedef struct {
#define TIM3_CCMR2_IC2F_OFFSET 4
#define TIM3_CCMR2_IC2F_MASK 0xf
#define TIM3_CCER1 (*(volatile uint8_t *)(TIM3_BASE + 0x07))
#define TIM3_CCER1_CC1E (1U << 0)
#define TIM3_CCER1_CC1P (1U << 1)
#define TIM3_CCER1_CC2E (1U << 4)
#define TIM3_CCER1_CC2P (1U << 5)
#define TIM3_CCER1_CC1E (1 << 0)
#define TIM3_CCER1_CC1P (1 << 1)
#define TIM3_CCER1_CC2E (1 << 4)
#define TIM3_CCER1_CC2P (1 << 5)
#define TIM3_CNTRH (*(volatile uint8_t *)(TIM3_BASE + 0x08))
#define TIM3_CNTRL (*(volatile uint8_t *)(TIM3_BASE + 0x09))
#define TIM3_PSCR (*(volatile uint8_t *)(TIM3_BASE + 0x0A))
@ -2550,11 +2548,11 @@ typedef struct {
// Block: TIM5
#define TIM5_CR1 (*(volatile uint8_t *)(TIM5_BASE + 0x00))
#define TIM5_CR1_CEN (1U << 0)
#define TIM5_CR1_UDIS (1U << 1)
#define TIM5_CR1_URS (1U << 2)
#define TIM5_CR1_OPM (1U << 3)
#define TIM5_CR1_APRE (1U << 7)
#define TIM5_CR1_CEN (1 << 0)
#define TIM5_CR1_UDIS (1 << 1)
#define TIM5_CR1_URS (1 << 2)
#define TIM5_CR1_OPM (1 << 3)
#define TIM5_CR1_APRE (1 << 7)
#define TIM5_CR2 (*(volatile uint8_t *)(TIM5_BASE + 0x01))
#define TIM5_CR2_MMS_OFFSET 4
#define TIM5_CR2_MMS_MASK 0x07
@ -2563,32 +2561,32 @@ typedef struct {
#define TIM5_SMCR_SMS_MASK 0x07
#define TIM5_SMCR_TS_OFFSET 4
#define TIM5_SMCR_TS_MASK 0x07
#define TIM5_SMCR_MSM (1U << 7)
#define TIM5_SMCR_MSM (1 << 7)
#define TIM5_IER (*(volatile uint8_t *)(TIM5_BASE + 0x03))
#define TIM5_IER_UIE (1U << 0)
#define TIM5_IER_CC1IE (1U << 1)
#define TIM5_IER_CC2IE (1U << 2)
#define TIM5_IER_CC3IE (1U << 3)
#define TIM5_IER_TIE (1U << 6)
#define TIM5_IER_UIE (1 << 0)
#define TIM5_IER_CC1IE (1 << 1)
#define TIM5_IER_CC2IE (1 << 2)
#define TIM5_IER_CC3IE (1 << 3)
#define TIM5_IER_TIE (1 << 6)
#define TIM5_SR1 (*(volatile uint8_t *)(TIM5_BASE + 0x04))
#define TIM5_SR1_UIF (1U << 0)
#define TIM5_SR1_CC1IF (1U << 1)
#define TIM5_SR1_CC2IF (1U << 2)
#define TIM5_SR1_CC3IF (1U << 3)
#define TIM5_SR1_TIF (1U << 6)
#define TIM5_SR1_UIF (1 << 0)
#define TIM5_SR1_CC1IF (1 << 1)
#define TIM5_SR1_CC2IF (1 << 2)
#define TIM5_SR1_CC3IF (1 << 3)
#define TIM5_SR1_TIF (1 << 6)
#define TIM5_SR2 (*(volatile uint8_t *)(TIM5_BASE + 0x05))
#define TIM5_SR2_CC1OF (1U << 1)
#define TIM5_SR2_CC2OF (1U << 2)
#define TIM5_SR2_CC3OF (1U << 3)
#define TIM5_SR2_CC1OF (1 << 1)
#define TIM5_SR2_CC2OF (1 << 2)
#define TIM5_SR2_CC3OF (1 << 3)
#define TIM5_EGR (*(volatile uint8_t *)(TIM5_BASE + 0x06))
#define TIM5_EGR_CC1G (1U << 1)
#define TIM5_EGR_CC2G (1U << 2)
#define TIM5_EGR_CC3G (1U << 3)
#define TIM5_EGR_TG (1U << 6)
#define TIM5_EGR_CC1G (1 << 1)
#define TIM5_EGR_CC2G (1 << 2)
#define TIM5_EGR_CC3G (1 << 3)
#define TIM5_EGR_TG (1 << 6)
#define TIM5_CCMR1 (*(volatile uint8_t *)(TIM5_BASE + 0x07))
#define TIM5_CCMR1_CC1S_OFFSET 0
#define TIM5_CCMR1_CC1S_MASK 0x3
#define TIM5_CCMR1_CC1PE (1U << 3)
#define TIM5_CCMR1_CC1PE (1 << 3)
#define TIM5_CCMR1_OC1M_OFFSET 4
#define TIM5_CCMR1_OC1M_MASK 0x7
#define TIM5_CCMR1_CC1S_OFFSET 0
@ -2600,7 +2598,7 @@ typedef struct {
#define TIM5_CCMR2 (*(volatile uint8_t *)(TIM5_BASE + 0x08))
#define TIM5_CCMR2_CC2S_OFFSET 0
#define TIM5_CCMR2_CC2S_MASK 0x3
#define TIM5_CCMR2_CC2PE (1U << 3)
#define TIM5_CCMR2_CC2PE (1 << 3)
#define TIM5_CCMR2_OC2M_OFFSET 4
#define TIM5_CCMR2_OC2M_MASK 0x7
#define TIM5_CCMR2_CC2S_OFFSET 0
@ -2612,7 +2610,7 @@ typedef struct {
#define TIM5_CCMR3 (*(volatile uint8_t *)(TIM5_BASE + 0x09))
#define TIM5_CCMR3_CC3S_OFFSET 0
#define TIM5_CCMR3_CC3S_MASK 0x3
#define TIM5_CCMR3_CC3PE (1U << 3)
#define TIM5_CCMR3_CC3PE (1 << 3)
#define TIM5_CCMR3_OC3M_OFFSET 4
#define TIM5_CCMR3_OC3M_MASK 0x7
#define TIM5_CCMR3_CC3S_OFFSET 0
@ -2622,13 +2620,13 @@ typedef struct {
#define TIM5_CCMR3_IC3F_OFFSET 4
#define TIM5_CCMR3_IC3F_MASK 0xf
#define TIM5_CCER1 (*(volatile uint8_t *)(TIM5_BASE + 0x0A))
#define TIM5_CCER1_CC1E (1U << 0)
#define TIM5_CCER1_CC1P (1U << 1)
#define TIM5_CCER1_CC2E (1U << 4)
#define TIM5_CCER1_CC2P (1U << 5)
#define TIM5_CCER1_CC1E (1 << 0)
#define TIM5_CCER1_CC1P (1 << 1)
#define TIM5_CCER1_CC2E (1 << 4)
#define TIM5_CCER1_CC2P (1 << 5)
#define TIM5_CCER2 (*(volatile uint8_t *)(TIM5_BASE + 0x0B))
#define TIM5_CCER2_CC3E (1U << 0)
#define TIM5_CCER2_CC3P (1U << 1)
#define TIM5_CCER2_CC3E (1 << 0)
#define TIM5_CCER2_CC3P (1 << 1)
#define TIM5_CNTRH (*(volatile uint8_t *)(TIM5_BASE + 0x0C))
#define TIM5_CNTRL (*(volatile uint8_t *)(TIM5_BASE + 0x0D))
#define TIM5_PSCR (*(volatile uint8_t *)(TIM5_BASE + 0x0E))
@ -2918,13 +2916,13 @@ typedef struct {
#define CPU_SPH (*(volatile uint8_t *)(CPU_BASE + 0x08))
#define CPU_SPL (*(volatile uint8_t *)(CPU_BASE + 0x09))
#define CPU_CCR (*(volatile uint8_t *)(CPU_BASE + 0x0A))
#define CPU_CCR_C (1U << 0)
#define CPU_CCR_Z (1U << 1)
#define CPU_CCR_N (1U << 2)
#define CPU_CCR_I0 (1U << 3)
#define CPU_CCR_H (1U << 4)
#define CPU_CCR_I1 (1U << 5)
#define CPU_CCR_V (1U << 7)
#define CPU_CCR_C (1 << 0)
#define CPU_CCR_Z (1 << 1)
#define CPU_CCR_N (1 << 2)
#define CPU_CCR_I0 (1 << 3)
#define CPU_CCR_H (1 << 4)
#define CPU_CCR_I1 (1 << 5)
#define CPU_CCR_V (1 << 7)
typedef union {
struct {
@ -3294,31 +3292,26 @@ typedef union {
uint8_t reg; /*!< type used for register access */
} OPT_NOPT1_type; /*!< */
// NOTE: OPT2 fields depends on device's pin count
typedef union {
struct {
uint8_t AFR0:1; /*!< bit 0: Alternate function remapping option 0 */
uint8_t :1; /*!< bit 0: Reserved */
uint8_t AFR1:1; /*!< bit 1: Alternate function remapping option 1 */
uint8_t AFR2:1; /*!< bit 2: Alternate function remapping option 2 */
uint8_t AFR3:1; /*!< bit 3: Alternate function remapping option 3 */
uint8_t AFR4:1; /*!< bit 4: Alternate function remapping option 4 */
uint8_t :3; /*!< bit 2..4: Reserved */
uint8_t AFR5:1; /*!< bit 5: Alternate function remapping option 5 */
uint8_t AFR6:1; /*!< bit 6: Alternate function remapping option 6 */
uint8_t AFR7:1; /*!< bit 7: Alternate function remapping option 7 */
uint8_t :1; /*!< bit 7: Reserved */
} fields; /*!< structure used for bit access */
uint8_t reg; /*!< type used for register access */
} OPT_OPT2_type; /*!< */
typedef union {
struct {
uint8_t NAFR0:1; /*!< bit 0: Alternate function remapping option 0 */
uint8_t :1; /*!< bit 0: Reserved */
uint8_t NAFR1:1; /*!< bit 1: Alternate function remapping option 1 */
uint8_t NAFR2:1; /*!< bit 2: Alternate function remapping option 2 */
uint8_t NAFR3:1; /*!< bit 3: Alternate function remapping option 3 */
uint8_t NAFR4:1; /*!< bit 4: Alternate function remapping option 4 */
uint8_t :3; /*!< bit 2..4: Reserved */
uint8_t NAFR5:1; /*!< bit 5: Alternate function remapping option 5 */
uint8_t NAFR6:1; /*!< bit 6: Alternate function remapping option 6 */
uint8_t NAFR7:1; /*!< bit 7: Alternate function remapping option 7 */
uint8_t :1; /*!< bit 7: Reserved */
} fields; /*!< structure used for bit access */
uint8_t reg; /*!< type used for register access */
} OPT_NOPT2_type; /*!< */
@ -3393,58 +3386,58 @@ typedef struct {
#define OPT_BASE 0x4800
#define OPT ((OPT_type*)OPT_BASE)
#define OPT_OPT0 (*(volatile uint8_t *)(OPT_BASE + 0x00))
#define ROP OPT_OPT0
#define OPT_OPT1 (*(volatile uint8_t *)(OPT_BASE + 0x01))
#define UBC OPT_OPT1
#define OPT_NOPT1 (*(volatile uint8_t *)(OPT_BASE + 0x02))
#define NUBC OPT_NOPT1
#define OPT_OPT2 (*(volatile uint8_t *)(OPT_BASE + 0x03))
#define AFR OPT_OPT2
#define AFR_AFR0 (1U << 0)
#define AFR_AFR1 (1U << 1)
#define AFR_AFR2 (1U << 2)
#define AFR_AFR3 (1U << 3)
#define AFR_AFR4 (1U << 4)
#define AFR_AFR5 (1U << 5)
#define AFR_AFR6 (1U << 6)
#define AFR_AFR7 (1U << 7)
#define OPT_NOPT2 (*(volatile uint8_t *)(OPT_BASE + 0x04))
#define NAFR OPT_NOPT2
#define AFR_NAFR0 (1U << 0)
#define AFR_NAFR1 (1U << 1)
#define AFR_NAFR2 (1U << 2)
#define AFR_NAFR3 (1U << 3)
#define AFR_NAFR4 (1U << 4)
#define AFR_NAFR5 (1U << 5)
#define AFR_NAFR6 (1U << 6)
#define AFR_NAFR7 (1U << 7)
#define OPT_OPT3 (*(volatile uint8_t *)(OPT_BASE + 0x05))
#define OPT3_WWDG_HALT (1U << 0)
#define OPT3_WWDG_HW (1U << 1)
#define OPT3_IWDG_HW (1U << 2)
#define OPT3_LSI_EN (1U << 3)
#define OPT3_HSI_TRIM (1U << 4)
#define OPT_NOPT3 (*(volatile uint8_t *)(OPT_BASE + 0x06))
#define NOPT3_NWWDG_HALT (1U << 0)
#define NOPT3_NWWDG_HW (1U << 1)
#define NOPT3_NIWDG_HW (1U << 2)
#define NOPT3_NLSI_EN (1U << 3)
#define NOPT3_NHSI_TRIM (1U << 4)
#define OPT_OPT4 (*(volatile uint8_t *)(OPT_BASE + 0x07))
#define OPT4_PRS_C0 (1U << 0)
#define OPT4_PRS_C1 (1U << 1)
#define OPT4_CKAWU_SEL (1U << 2)
#define OPT4_EXT_CLK (1U << 3)
#define OPT_NOPT4 (*(volatile uint8_t *)(OPT_BASE + 0x08))
#define NOPT4_NPRS_C0 (1U << 0)
#define NOPT4_NPRS_C1 (1U << 1)
#define NOPT4_NCKAWU_SEL (1U << 2)
#define NOPT4_NEXT_CLK (1U << 3)
#define OPT_OPT5 (*(volatile uint8_t *)(OPT_BASE + 0x09))
#define HSECNT OPT_OPT5
#define OPT_NOPT5 (*(volatile uint8_t *)(OPT_BASE + 0x0A))
#define NHSECNT OPT_NOPT5
#define OPT0 (*(volatile uint8_t *)(OPT_BASE + 0x00))
#define ROP OPT0
#define OPT1 (*(volatile uint8_t *)(OPT_BASE + 0x01))
#define UBC OPT1
#define NOPT1 (*(volatile uint8_t *)(OPT_BASE + 0x02))
#define NUBC NOPT1
#define OPT2 (*(volatile uint8_t *)(OPT_BASE + 0x03))
#define AFR OPT2
#define AFR_AFR0 (1 << 0)
#define AFR_AFR1 (1 << 1)
#define AFR_AFR2 (1 << 2)
#define AFR_AFR3 (1 << 3)
#define AFR_AFR4 (1 << 4)
#define AFR_AFR5 (1 << 5)
#define AFR_AFR6 (1 << 6)
#define AFR_AFR7 (1 << 7)
#define NOPT2 (*(volatile uint8_t *)(OPT_BASE + 0x04))
#define NAFR NOPT2
#define AFR_NAFR0 (1 << 0)
#define AFR_NAFR1 (1 << 1)
#define AFR_NAFR2 (1 << 2)
#define AFR_NAFR3 (1 << 3)
#define AFR_NAFR4 (1 << 4)
#define AFR_NAFR5 (1 << 5)
#define AFR_NAFR6 (1 << 6)
#define AFR_NAFR7 (1 << 7)
#define OPT3 (*(volatile uint8_t *)(OPT_BASE + 0x05))
#define OPT3_WWDG_HALT (1 << 0)
#define OPT3_WWDG_HW (1 << 1)
#define OPT3_IWDG_HW (1 << 2)
#define OPT3_LSI_EN (1 << 3)
#define OPT3_HSI_TRIM (1 << 4)
#define NOPT3 (*(volatile uint8_t *)(OPT_BASE + 0x06))
#define NOPT3_NWWDG_HALT (1 << 0)
#define NOPT3_NWWDG_HW (1 << 1)
#define NOPT3_NIWDG_HW (1 << 2)
#define NOPT3_NLSI_EN (1 << 3)
#define NOPT3_NHSI_TRIM (1 << 4)
#define OPT4 (*(volatile uint8_t *)(OPT_BASE + 0x07))
#define OPT4_PRS_C0 (1 << 0)
#define OPT4_PRS_C1 (1 << 1)
#define OPT4_CKAWU_SEL (1 << 2)
#define OPT4_EXT_CLK (1 << 3)
#define NOPT4 (*(volatile uint8_t *)(OPT_BASE + 0x08))
#define NOPT4_NPRS_C0 (1 << 0)
#define NOPT4_NPRS_C1 (1 << 1)
#define NOPT4_NCKAWU_SEL (1 << 2)
#define NOPT4_NEXT_CLK (1 << 3)
#define OPT5 (*(volatile uint8_t *)(OPT_BASE + 0x09))
#define HSECNT OPT5
#define NOPT5 (*(volatile uint8_t *)(OPT_BASE + 0x0A))
#define NHSECNT NOPT5
// Unique ID
typedef struct {
@ -3456,11 +3449,9 @@ typedef struct {
/* some useful assembly instructions */
// wait for event (go to sleep)
#define wfe() { __asm__("wfe\n"); }
#define wfe() { __asm__("wfi\n"); }
// wait for interrupt (go to sleep)
#define wfi() { __asm__("wfi\n"); }
// go into halt mode
#define halt() { __asm__("halt\n"); }
// disable interrupts
#define sim() { __asm__("sim"); }
// enable interrupts