Merge branch 'master' of ssh://git.cuvoodoo.info/stm32f1

This commit is contained in:
King Kévin 2019-04-01 15:17:24 +02:00
commit d7cd572f9a
28 changed files with 556 additions and 452 deletions

View File

@ -73,7 +73,7 @@ size_t putc(char c)
usb_cdcacm_putchar(c); // send byte over USB
length++; // remember we printed 1 character
last_c = c; // remember last character
return length; // return number of characters printed
return length; // return number of characters printed
}
/** display available commands

View File

@ -110,7 +110,7 @@ void sleep_us(uint32_t duration)
sleep_duration = duration; // save sleep duration for count down
systick_counter_enable(); // start counting
while (sleep_duration>0) { // wait for count down to complete
__WFI(); // go to sleep
__WFI(); // go to sleep
}
}
@ -125,7 +125,7 @@ void sleep_ms(uint32_t duration)
sleep_duration = duration; // save sleep duration for count down
systick_counter_enable(); // start counting
while (sleep_duration>0) { // wait for count down to complete
__WFI(); // go to sleep
__WFI(); // go to sleep
}
}

View File

@ -15,7 +15,7 @@
/** global definitions and methods (API)
* @file global.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016-2017
* @date 2016-2019
*/
#pragma once
@ -30,6 +30,18 @@
#define CAT3(x,y,z) x##y##z
/** concatenate 4 arguments */
#define CAT4(w,x,y,z) w##x##y##z
/** integer underflow/overflow safe uint8_t addition (result to min/max on underflow/overflow) */
#define ADDU8_SAFE(a,b) {__typeof__ (a) _a = (a); __typeof__ (b) _b = (b); a = (_b > 0 ? ((_a > UINT8_MAX - _b) ? UINT8_MAX : (_a + _b)) : ((_a < _b) ? 0 : (_a - _b)));}
/** integer underflow/overflow safe uint16_t addition (result to min/max on underflow/overflow) */
#define ADDU16_SAFE(a,b) {__typeof__ (a) _a = (a); __typeof__ (b) _b = (b); a = (_b > 0 ? ((_a > UINT16_MAX - _b) ? UINT16_MAX : (_a + _b)) : ((_a < _b) ? 0 : (_a - _b)));}
/** integer underflow/overflow safe uint32_t addition (result to min/max on underflow/overflow) */
#define ADDU32_SAFE(a,b) {__typeof__ (a) _a = (a); __typeof__ (b) _b = (b); a = (_b > 0 ? ((_a > UINT32_MAX - _b) ? UINT32_MAX : (_a + _b)) : ((_a < _b) ? 0 : (_a - _b)));}
/** integer underflow/overflow safe int8_t addition (result to min/max on underflow/overflow) */
#define ADDS8_SAFE(a,b) {__typeof__ (a) _a = (a); __typeof__ (b) _b = (b); a = (_b > 0 ? ((_a > INT8_MAX - _b) ? INT8_MAX : (_a + _b)) : ((_a < INT8_MAX + _b) ? INT8_MAX : (_a - _b)));}
/** integer underflow/overflow safe int16_t addition (result to min/max on underflow/overflow) */
#define ADDS16_SAFE(a,b) {__typeof__ (a) _a = (a); __typeof__ (b) _b = (b); a = (_b > 0 ? ((_a > INT16_MAX - _b) ? INT16_MAX : (_a + _b)) : ((_a < INT16_MIN + _b) ? INT16_MIN : (_a - _b)));}
/** integer underflow/overflow safe int32_t addition (result to min/max on underflow/overflow) */
#define ADDS32_SAFE(a,b) {__typeof__ (a) _a = (a); __typeof__ (b) _b = (b); a = (_b > 0 ? ((_a > UINT32_MAX - _b) ? UINT32_MAX : (_a + _b)) : ((_a < INT32_MIN + _b) ? INT32_MIN : (_a - _b)));}
/** build year as number */
#define COMPUTE_BUILD_YEAR \
@ -416,10 +428,17 @@
#define DFU_FORCE_PIN BUTTON_PIN /**< button pin */
#define DFU_FORCE_VALUE 0 /**< button floating unpressed, connected to ground pressed to force DFU mode */
#elif defined(BUSVOODOO)
/* on BusVoodoo DFU input is on PC4 */
#if BUSVOODOO_HARDWARE_VERSION==0
/* on BusVoodoo v0 DFU input is on PC7 */
#define DFU_FORCE_PORT C /**< GPIO port (port C) */
#define DFU_FORCE_PIN 7 /**< GPIO pin (pin PC7) */
#define DFU_FORCE_VALUE 1 /**< pin is pulled low, and goes high when shorted with VUSB */
#else
/* on BusVoodoo vA DFU input is on PC4 */
#define DFU_FORCE_PORT C /**< GPIO port (port C) */
#define DFU_FORCE_PIN 4 /**< GPIO pin (pin PC4) */
#define DFU_FORCE_VALUE 1 /**< pin floating, set high when shorted with nearby VCC */
#endif
#else
/* use the JNTRST pin as GPIO (SWJ will still be working, minus NTRST) */
#define DFU_FORCE_PORT B /**< JNTRST port (needs to be remapped to become PB4) */

View File

@ -249,7 +249,7 @@ static uint8_t flash_sdcard_write_block(uint8_t* data, size_t size)
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)
@ -511,7 +511,7 @@ bool flash_sdcard_setup(void)
}
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)

View File

@ -15,7 +15,7 @@
/** library to communicate using I2C as master (code)
* @file i2c_master.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017-2018
* @date 2017-2019
* @note peripherals used: I2C
*/
@ -24,6 +24,8 @@
#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> // I2C library
@ -38,15 +40,17 @@
*/
static uint32_t RCC_I2C(uint32_t i2c)
{
cm3_assert(I2C1 == i2c || I2C2 == i2c);
switch (i2c) {
case I2C1:
return RCC_I2C1;
break;
case I2C2:
return RCC_I2C2;
break;
default:
while (true);
case I2C1:
return RCC_I2C1;
break;
case I2C2:
return RCC_I2C2;
break;
default:
return 0;
}
}
@ -56,13 +60,15 @@ static uint32_t RCC_I2C(uint32_t i2c)
*/
static uint32_t RCC_GPIO_PORT_SCL(uint32_t i2c)
{
cm3_assert(I2C1 == i2c || I2C2 == i2c);
switch (i2c) {
case I2C1:
case I2C2:
return RCC_GPIOB;
break;
default:
while (true);
case I2C1:
case I2C2:
return RCC_GPIOB;
break;
default:
return 0;
}
}
@ -72,13 +78,15 @@ static uint32_t RCC_GPIO_PORT_SCL(uint32_t i2c)
*/
static uint32_t RCC_GPIO_PORT_SDA(uint32_t i2c)
{
cm3_assert(I2C1 == i2c || I2C2 == i2c);
switch (i2c) {
case I2C1:
case I2C2:
return RCC_GPIOB;
break;
default:
while (true);
case I2C1:
case I2C2:
return RCC_GPIOB;
break;
default:
return 0;
}
}
@ -88,19 +96,21 @@ static uint32_t RCC_GPIO_PORT_SDA(uint32_t i2c)
*/
static uint32_t GPIO_PORT_SCL(uint32_t i2c)
{
cm3_assert(I2C1 == i2c || I2C2 == i2c);
switch (i2c) {
case I2C1:
if (AFIO_MAPR & AFIO_MAPR_I2C1_REMAP) {
return GPIO_BANK_I2C1_RE_SCL;
} else {
return GPIO_BANK_I2C1_SCL;
}
break;
case I2C2:
return GPIO_BANK_I2C2_SCL;
break;
default:
while (true);
case I2C1:
if (AFIO_MAPR & AFIO_MAPR_I2C1_REMAP) {
return GPIO_BANK_I2C1_RE_SCL;
} else {
return GPIO_BANK_I2C1_SCL;
}
break;
case I2C2:
return GPIO_BANK_I2C2_SCL;
break;
default:
return 0;
}
}
@ -110,19 +120,21 @@ static uint32_t GPIO_PORT_SCL(uint32_t i2c)
*/
static uint32_t GPIO_PORT_SDA(uint32_t i2c)
{
cm3_assert(I2C1 == i2c || I2C2 == i2c);
switch (i2c) {
case I2C1:
if (AFIO_MAPR & AFIO_MAPR_I2C1_REMAP) {
return GPIO_BANK_I2C1_RE_SDA;
} else {
return GPIO_BANK_I2C1_SDA;
}
break;
case I2C2:
return GPIO_BANK_I2C2_SDA;
break;
default:
while (true);
case I2C1:
if (AFIO_MAPR & AFIO_MAPR_I2C1_REMAP) {
return GPIO_BANK_I2C1_RE_SDA;
} else {
return GPIO_BANK_I2C1_SDA;
}
break;
case I2C2:
return GPIO_BANK_I2C2_SDA;
break;
default:
return 0;
}
}
@ -132,19 +144,21 @@ static uint32_t GPIO_PORT_SDA(uint32_t i2c)
*/
static uint32_t GPIO_PIN_SCL(uint32_t i2c)
{
cm3_assert(I2C1 == i2c || I2C2 == i2c);
switch (i2c) {
case I2C1:
if (AFIO_MAPR & AFIO_MAPR_I2C1_REMAP) {
return GPIO_I2C1_RE_SCL;
} else {
return GPIO_I2C1_SCL;
}
break;
case I2C2:
return GPIO_I2C2_SCL;
break;
default:
while (true);
case I2C1:
if (AFIO_MAPR & AFIO_MAPR_I2C1_REMAP) {
return GPIO_I2C1_RE_SCL;
} else {
return GPIO_I2C1_SCL;
}
break;
case I2C2:
return GPIO_I2C2_SCL;
break;
default:
return 0;
}
}
@ -154,28 +168,27 @@ static uint32_t GPIO_PIN_SCL(uint32_t i2c)
*/
static uint32_t GPIO_PIN_SDA(uint32_t i2c)
{
cm3_assert(I2C1 == i2c || I2C2 == i2c);
switch (i2c) {
case I2C1:
if (AFIO_MAPR & AFIO_MAPR_I2C1_REMAP) {
return GPIO_I2C1_RE_SDA;
} else {
return GPIO_I2C1_SDA;
}
break;
case I2C2:
return GPIO_I2C2_SDA;
break;
default:
while (true);
case I2C1:
if (AFIO_MAPR & AFIO_MAPR_I2C1_REMAP) {
return GPIO_I2C1_RE_SDA;
} else {
return GPIO_I2C1_SDA;
}
break;
case I2C2:
return GPIO_I2C2_SDA;
break;
default:
return 0;
}
}
void i2c_master_setup(uint32_t i2c, uint16_t frequency)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
// configure I2C peripheral
rcc_periph_clock_enable(RCC_GPIO_PORT_SCL(i2c)); // enable clock for I2C I/O peripheral
@ -192,28 +205,25 @@ void i2c_master_setup(uint32_t i2c, uint16_t frequency)
I2C_CR1(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
} else if (frequency > 400) { // limit frequency to 400 kHz
frequency = 400;
}
i2c_set_clock_frequency(i2c, rcc_apb1_frequency/1000000); // configure the peripheral clock to the APB1 freq (where it is connected to)
i2c_set_clock_frequency(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); // set fast mode (Fm)
i2c_set_ccr(i2c, rcc_apb1_frequency/(frequency*1000*2)); // set Thigh/Tlow to generate frequency (fast duty not used)
i2c_set_trise(i2c, (300/(1000/(rcc_apb1_frequency/1000000)))+1); // max rise time for Fm mode (< 400) kHz is 300 ns
i2c_set_ccr(i2c, rcc_apb1_frequency / (frequency * 1000 * 2)); // set Thigh/Tlow to generate frequency (fast duty not used)
i2c_set_trise(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); // set standard mode (Sm)
i2c_set_ccr(i2c, rcc_apb1_frequency/(frequency*1000*2)); // set Thigh/Tlow to generate frequency of 100 kHz
i2c_set_trise(i2c, (1000/(1000/(rcc_apb1_frequency/1000000)))+1); // max rise time for Sm mode (< 100 kHz) is 1000 ns (~1 MHz)
i2c_set_ccr(i2c, rcc_apb1_frequency / (frequency * 1000 * 2)); // set Thigh/Tlow to generate frequency of 100 kHz
i2c_set_trise(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); // enable I2C after configuration completed
}
void i2c_master_release(uint32_t i2c)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
i2c_reset(i2c); // reset I2C peripheral configuration
i2c_peripheral_disable(i2c); // disable I2C peripheral
@ -224,10 +234,7 @@ void i2c_master_release(uint32_t i2c)
bool i2c_master_check_signals(uint32_t i2c)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
// pull SDA and SDC low to check if there are pull-up resistors
uint32_t sda_crl = GPIO_CRL(GPIO_PORT_SDA(i2c)); // backup port configuration
@ -240,7 +247,7 @@ bool i2c_master_check_signals(uint32_t i2c)
gpio_set_mode(GPIO_PORT_SCL(i2c), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_PIN_SCL(i2c)); // configure signal as pull down
gpio_clear(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // pull down
gpio_clear(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // pull down
bool to_return = (0!=gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)) && 0!=gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c))); // check if the signals are still pulled high by external stronger pull-up resistors
bool to_return = (0 != gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)) && 0 != gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c))); // check if the signals are still pulled high by external stronger pull-up resistors
GPIO_CRL(GPIO_PORT_SDA(i2c)) = sda_crl; // restore port configuration
GPIO_CRH(GPIO_PORT_SDA(i2c)) = sda_crh; // restore port configuration
GPIO_BSRR(GPIO_PORT_SDA(i2c)) = sda_bsrr; // restore port configuration
@ -251,74 +258,94 @@ bool i2c_master_check_signals(uint32_t i2c)
return to_return;
}
void i2c_master_reset(uint32_t i2c)
bool i2c_master_reset(uint32_t i2c)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
bool to_return = true;
// follow procedure described in STM32F10xxC/D/E Errata sheet, Section 2.14.7
i2c_peripheral_disable(i2c); // disable i2c peripheral
gpio_set_mode(GPIO_PORT_SCL(i2c), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN_SCL(i2c)); // put I2C I/O pins to general output
gpio_set(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // set high
while (!gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c))); // ensure it is high
to_return &= !gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // ensure it is high
gpio_set_mode(GPIO_PORT_SDA(i2c), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN_SDA(i2c)); // put I2C I/O pins to general output
gpio_set(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // set high
while (!gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c))); // ensure it is high
to_return &= !gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // ensure it is high
gpio_clear(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // set low (try first transition)
while (gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c))); // ensure it is low
to_return &= gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // ensure it is low
gpio_clear(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // set low (try first transition)
while (gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c))); // ensure it is low
to_return &= gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // ensure it is low
gpio_set(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // set high (try second transition)
while (!gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c))); // ensure it is high
to_return &= !gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // ensure it is high
gpio_set(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // set high (try second transition)
while (!gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c))); // ensure it is high
to_return &= !gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // ensure it is high
gpio_set_mode(GPIO_PORT_SCL(i2c), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO_PIN_SCL(i2c)); // set I2C I/O pins back
gpio_set_mode(GPIO_PORT_SDA(i2c), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO_PIN_SDA(i2c)); // set I2C I/O pins back
I2C_CR1(i2c) |= I2C_CR1_SWRST; // reset device
I2C_CR1(i2c) &= ~I2C_CR1_SWRST; // reset device
i2c_peripheral_enable(i2c); // re-enable device
return to_return;
}
enum i2c_master_rc i2c_master_start(uint32_t i2c)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
bool retry = true; // retry after reset if first try failed
enum i2c_master_rc to_return; // return code
try:
to_return = I2C_MASTER_RC_NONE; // return code
// send (re-)start condition
if (I2C_CR1(i2c) & (I2C_CR1_START|I2C_CR1_STOP)) { // ensure start or stop operations are not in progress
if (I2C_CR1(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 I2C 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); // send start condition to start transaction
while ((I2C_CR1(i2c) & I2C_CR1_START) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until start condition has been accepted and cleared
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
bool timeout = false; // remember if the timeout has been reached
systick_counter_enable(); // start timer
while ((I2C_CR1(i2c) & I2C_CR1_START) && !(I2C_SR1(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
}
while (!(I2C_SR1(i2c) & I2C_SR1_SB) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until start condition is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
if (I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
to_return = I2C_MASTER_RC_BUS_ERROR;
}
if (!(I2C_SR2(i2c) & I2C_SR2_MSL)) { // verify if in master mode
return I2C_MASTER_RC_NOT_MASTER;
while (!(I2C_SR1(i2c) & I2C_SR1_SB) && !(I2C_SR1(i2c) & (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
}
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
to_return = I2C_MASTER_RC_BUS_ERROR;
} else if (!(I2C_SR1(i2c) & 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 (!(I2C_SR2(i2c) & 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;
}
return I2C_MASTER_RC_NONE;
if (I2C_MASTER_RC_NOT_MASTER == to_return && retry) { // error happened
retry = false; // don't retry a second time
I2C_CR1(i2c) |= I2C_CR1_SWRST; // assert peripheral reset
I2C_CR1(i2c) &= ~I2C_CR1_SWRST; // release peripheral reset
goto try;
}
systick_counter_disable(); // we don't need to timer anymore
return to_return;
}
enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool address_10bit, bool write)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I2C return codes
if (!(I2C_SR1(i2c) & I2C_SR1_SB)) { // start condition has not been sent
rc = i2c_master_start(i2c); // send start condition
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
return rc;
}
}
@ -330,8 +357,8 @@ enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool ad
if (!address_10bit) { // 7-bit address
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
i2c_send_7bit_address(i2c, slave, write ? I2C_WRITE : I2C_READ); // select slave, with read/write flag
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until address is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR | I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until address is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
@ -340,16 +367,16 @@ enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool ad
} else { // 10-bit address
// send first part of address
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
I2C_DR(i2c) = 11110000 | (((slave>>8)&0x3)<<1); // send first header (11110xx0, where xx are 2 MSb of slave address)
while (!(I2C_SR1(i2c) & (I2C_SR1_ADD10|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until first part of address is transmitted
I2C_DR(i2c) = 11110000 | (((slave >> 8 ) & 0x3) << 1); // send first header (11110xx0, where xx are 2 MSb of slave address)
while (!(I2C_SR1(i2c) & (I2C_SR1_ADD10 | I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until first part of address is transmitted
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
return I2C_MASTER_RC_NAK;
}
// send second part of address
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
I2C_DR(i2c) = (slave&0xff); // send remaining of address
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until remaining part of address is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
I2C_DR(i2c) = (slave & 0xff); // send remaining of address
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until remaining part of address is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
@ -358,14 +385,14 @@ enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool ad
// go into receive mode if necessary
if (!write) {
rc = i2c_master_start(i2c); // send start condition
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
return rc;
}
// send first part of address with receive flag
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
I2C_DR(i2c) = 11110001 | (((slave>>8)&0x3)<<1); // send header (11110xx1, where xx are 2 MSb of slave address)
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until remaining part of address is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
I2C_DR(i2c) = 11110001 | (((slave >> 8) & 0x3) << 1); // send header (11110xx1, where xx are 2 MSb of slave address)
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR | I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until remaining part of address is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
@ -373,30 +400,29 @@ enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool ad
}
}
}
if (write) {
if (!((I2C_SR2(i2c) & I2C_SR2_TRA))) { // verify we are in transmit mode (and read SR2 to clear ADDR)
return I2C_MASTER_RC_NOT_TRANSMIT;
}
} else {
if ((I2C_SR2(i2c) & I2C_SR2_TRA)) { // verify we are in read mode (and read SR2 to clear ADDR)
return I2C_MASTER_RC_NOT_RECEIVE;
}
}
// 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(uint32_t i2c, uint8_t* data, size_t data_size)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
// sanity check
if (data==NULL || data_size==0) { // no data to read
if (NULL == data || 0 == data_size) { // no data to read
return I2C_MASTER_RC_NONE;
}
}
if (1 == data_size) {
i2c_nack_current(i2c); // [N]ACK current byte
i2c_disable_ack(i2c); // NACK after first byte
} else if (2 == data_size) {
i2c_nack_next(i2c); // [N]ACK next byte
i2c_enable_ack(i2c); // NACK first byte
} else {
i2c_nack_current(i2c); // ACK current byte
i2c_enable_ack(i2c); // NAK after next byte
}
// reading SR2 will also also clear ADDR and start the transaction
if (!(I2C_SR2(i2c) & I2C_SR2_MSL)) { // I2C device is not master
return I2C_MASTER_RC_NOT_MASTER;
}
@ -408,13 +434,17 @@ enum i2c_master_rc i2c_master_read(uint32_t i2c, uint8_t* data, size_t data_size
}
// read data
for (size_t i=0; i<data_size; i++) { // read bytes
if (i==data_size-1) { // prepare to sent NACK for last byte
for (size_t i = 0; i < data_size; i++) { // read bytes
if (2 == data_size - i) { // prepare to sent NACK for second last byte
i2c_nack_next(i2c); // NACK next byte
i2c_disable_ack(i2c); // NACK received to stop slave transmission
} else if (1 == data_size - i) { // prepare to sent NACK for last byte
i2c_nack_current(i2c); // ACK current byte
i2c_disable_ack(i2c); // NACK received to stop slave transmission
} else {
i2c_enable_ack(i2c); // ACK received byte to continue slave transmission
}
while (!(I2C_SR1(i2c) & I2C_SR1_RxNE) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until byte has been received
while (!(I2C_SR1(i2c) & I2C_SR1_RxNE) && !(I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until byte has been received
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
@ -426,15 +456,12 @@ enum i2c_master_rc i2c_master_read(uint32_t i2c, uint8_t* data, size_t data_size
enum i2c_master_rc i2c_master_write(uint32_t i2c, const uint8_t* data, size_t data_size)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
// sanity check
if (data==NULL || data_size==0) { // no data to write
if (NULL == data || 0 == data_size) { // no data to write
return I2C_MASTER_RC_NONE;
}
}
if (!(I2C_SR2(i2c) & I2C_SR2_MSL)) { // I2C device is not master
return I2C_MASTER_RC_NOT_MASTER;
}
@ -446,11 +473,11 @@ enum i2c_master_rc i2c_master_write(uint32_t i2c, const uint8_t* data, size_t da
}
// write data
for (size_t i=0; i<data_size; i++) { // write bytes
for (size_t i = 0; i < data_size; i++) { // write bytes
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
i2c_send_data(i2c, data[i]); // send byte to be written in memory
while (!(I2C_SR1(i2c) & (I2C_SR1_TxE|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until byte has been transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
while (!(I2C_SR1(i2c) & (I2C_SR1_TxE | I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO))); // wait until byte has been transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR | I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_SR1(i2c) & I2C_SR1_AF) { // data has not been acknowledged
@ -463,39 +490,55 @@ enum i2c_master_rc i2c_master_write(uint32_t i2c, const uint8_t* data, size_t da
enum i2c_master_rc i2c_master_stop(uint32_t i2c)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
// sanity check
if (!(I2C_SR2(i2c) & I2C_SR2_BUSY)) { // release is not busy
return I2C_MASTER_RC_NONE; // bus has probably already been released
}
// send stop condition
if (I2C_CR1(i2c) & (I2C_CR1_START|I2C_CR1_STOP)) { // ensure start or stop operations are not in progress
if (I2C_CR1(i2c) & (I2C_CR1_START | I2C_CR1_STOP)) { // ensure start or stop operations are not in progress
return I2C_MASTER_RC_START_STOP_IN_PROGESS;
}
i2c_send_stop(i2c); // send stop to release bus
while ((I2C_CR1(i2c) & I2C_CR1_STOP) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until stop condition is accepted and cleared
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
while ((I2C_SR2(i2c) & I2C_SR2_MSL) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until bus released (non master mode)
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
if (!((I2C_SR2(i2c) & I2C_SR2_TRA))) { // if we are in receiver mode
i2c_disable_ack(i2c); // disable ACK to be able to close the communication
}
return I2C_MASTER_RC_NONE;
enum i2c_master_rc to_return = I2C_MASTER_RC_NONE;
// prepare timer in case the peripheral hangs on sending stop condition (see errata 2.14.4 Wrong behavior of I2C 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
i2c_send_stop(i2c); // send stop to release bus
systick_counter_enable(); // start timer
i2c_send_stop(i2c); // send stop to release bus
while ((I2C_CR1(i2c) & I2C_CR1_STOP) && !(I2C_SR1(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_SR1_BERR | I2C_SR1_ARLO)) {
to_return = I2C_MASTER_RC_BUS_ERROR;
}
while ((I2C_SR2(i2c) & I2C_SR2_MSL) && !(I2C_SR1(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_SR1_BERR | I2C_SR1_ARLO)) {
to_return = I2C_MASTER_RC_BUS_ERROR;
}
if (timeout) {
I2C_CR1(i2c) |= I2C_CR1_SWRST; // assert peripheral reset
I2C_CR1(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_slave_read(uint32_t i2c, uint16_t slave, bool address_10bit, uint8_t* data, size_t data_size)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I2C return codes
rc = i2c_master_start(i2c); // send (re-)start condition
@ -503,12 +546,12 @@ enum i2c_master_rc i2c_master_slave_read(uint32_t i2c, uint16_t slave, bool addr
return rc;
}
rc = i2c_master_select_slave(i2c, slave, address_10bit, false); // select slave to read
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
if (NULL!=data && data_size>0) { // only read data if needed
if (NULL != data && data_size > 0) { // only read data if needed
rc = i2c_master_read(i2c, data, data_size);
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
}
@ -521,23 +564,20 @@ error:
enum i2c_master_rc i2c_master_slave_write(uint32_t i2c, uint16_t slave, bool address_10bit, const uint8_t* data, size_t data_size)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I2C return codes
rc = i2c_master_start(i2c); // send (re-)start condition
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
return rc;
}
rc = i2c_master_select_slave(i2c, slave, address_10bit, true); // select slave to write
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
if (NULL!=data && data_size>0) { // write data only is some is available
if (NULL != data && data_size > 0) { // write data only is some is available
rc = i2c_master_write(i2c, data, data_size); // write data
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
}
@ -550,40 +590,37 @@ error:
enum i2c_master_rc i2c_master_address_read(uint32_t i2c, uint16_t slave, bool address_10bit, const uint8_t* address, size_t address_size, uint8_t* data, size_t data_size)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I2C return codes
rc = i2c_master_start(i2c); // send (re-)start condition
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
return rc;
}
rc = i2c_master_select_slave(i2c, slave, address_10bit, true); // select slave to write
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
// write address
if (NULL!=address && address_size>0) {
if (NULL != address && address_size > 0) {
rc = i2c_master_write(i2c, address, address_size); // send memory address
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
}
// read data
if (NULL!=data && data_size>0) {
if (NULL != data && data_size > 0) {
rc = i2c_master_start(i2c); // send re-start condition
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
return rc;
}
rc = i2c_master_select_slave(i2c, slave, address_10bit, false); // select slave to read
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
rc = i2c_master_read(i2c, data, data_size); // read memory
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
}
@ -596,32 +633,29 @@ error:
enum i2c_master_rc i2c_master_address_write(uint32_t i2c, uint16_t slave, bool address_10bit, const uint8_t* address, size_t address_size, const uint8_t* data, size_t data_size)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
cm3_assert(I2C1 == i2c || I2C2 == i2c);
enum i2c_master_rc rc = I2C_MASTER_RC_NONE; // to store I2C return codes
rc = i2c_master_start(i2c); // send (re-)start condition
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
return rc;
}
rc = i2c_master_select_slave(i2c, slave, address_10bit, true); // select slave to write
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
// write address
if (NULL!=address && address_size>0) {
if (NULL != address && address_size > 0) {
rc = i2c_master_write(i2c, address, address_size); // send memory address
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
}
// read data
if (NULL!=data && data_size>0) {
if (NULL != data && data_size > 0) {
rc = i2c_master_write(i2c, data, data_size); // write memory
if (I2C_MASTER_RC_NONE!=rc) {
if (I2C_MASTER_RC_NONE != rc) {
goto error;
}
}

View File

@ -15,7 +15,7 @@
/** library to communicate using I2C as master (API)
* @file i2c_master.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017-2018
* @date 2017-2019
* @note peripherals used: I2C
*/
#pragma once
@ -46,8 +46,9 @@ void i2c_master_release(uint32_t i2c);
* @warning the I2C peripheral needs to be re-setup
* @note to be used after failed start or stop, and bus error
* @param[in] i2c I2C base address
* return true if complete reset is successful, false if the lines could not be set
*/
void i2c_master_reset(uint32_t i2c);
bool i2c_master_reset(uint32_t i2c);
/** check if SDA and SCL signals are high
* @param[in] i2c I2C base address
* @return SDA and SCL signals are high
@ -72,6 +73,7 @@ enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool ad
* @param[in] i2c I2C base address
* @param[out] data array to store bytes read
* @param[in] data_size number of bytes to read
* @note the last read byte is NACKed, but the I2C peripheral will clock the read for at least 2 more bytes after the NACK
* @return I2C return code
*/
enum i2c_master_rc i2c_master_read(uint32_t i2c, uint8_t* data, size_t data_size);

View File

@ -60,99 +60,99 @@
*/
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, // } ([)
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, // ~
};

View File

@ -289,7 +289,7 @@ bool led_tm1637_number(uint16_t number)
{
uint8_t write_data[] = { 0x40 }; // command: write data, automatic address adding, normal
uint8_t data[] = { 0xc0, ascii_7segments[((number/1000)%10)+'0'-' '], ascii_7segments[((number/100)%10)+'0'-' '], ascii_7segments[((number/10)%10)+'0'-' '], ascii_7segments[((number/1)%10)+'0'-' '] }; // set address C0H and add data
if (led_tm1637_write(write_data,LENGTH(write_data)) && led_tm1637_write(data,LENGTH(data))) { // send commands
return true;
}
@ -300,7 +300,7 @@ bool led_tm1637_time(uint8_t hours, uint8_t minutes)
{
uint8_t write_data[] = { 0x40 }; // command: write data, automatic address adding, normal
uint8_t data[] = { 0xc0, ascii_7segments[((hours/10)%10)+'0'-' '], ascii_7segments[((hours/1)%10)+'0'-' ']|0x80, ascii_7segments[((minutes/10)%10)+'0'-' '], ascii_7segments[((minutes/1)%10)+'0'-' '] }; // set address C0H and add data
if (led_tm1637_write(write_data,LENGTH(write_data)) && led_tm1637_write(data,LENGTH(data))) { // send commands
return true;
}
@ -319,7 +319,7 @@ bool led_tm1637_text(char* text)
}
uint8_t write_data[] = { 0x40 }; // command: write data, automatic address adding, normal
uint8_t data[] = { 0xc0, ascii_7segments[(text[0]&0x7f)-' ']|(text[0]&0x80), ascii_7segments[(text[1]&0x7f)-' ']|(text[1]&0x80), ascii_7segments[(text[2]&0x7f)-' ']|(text[2]&0x80), ascii_7segments[(text[3]&0x7f)-' ']|(text[3]&0x80) }; // set address C0H and add data
if (led_tm1637_write(write_data,LENGTH(write_data)) && led_tm1637_write(data,LENGTH(data))) { // send commands
return true;
}

View File

@ -138,9 +138,9 @@ void led_ws2812b_setup(void)
spi_send_msb_first(SPI(LED_WS2812B_SPI)); // send least significant bit first
spi_enable_software_slave_management(SPI(LED_WS2812B_SPI)); // control the slave select in software (since there is no master)
spi_set_nss_low(SPI(LED_WS2812B_SPI)); // set NSS low so we can output
spi_enable(SPI(LED_WS2812B_SPI)); // enable SPI
spi_enable(SPI(LED_WS2812B_SPI)); // enable SPI
// do not disable SPI or set NSS high since it will put MISO high, breaking the beginning of the next transmission
// 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
@ -177,5 +177,5 @@ void DMA_ISR_SPI_TX(LED_WS2812B_SPI)(void)
timer_disable_counter(TIM(LED_WS2812B_TIMER)); // stop clock
dma_disable_channel(DMA_SPI(LED_WS2812B_SPI), DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI)); // stop using DMA
transmit_flag = false; // transmission completed
}
}
}

View File

@ -30,11 +30,11 @@
bool menu_handle_command(const char* line, const struct menu_command_t* command_list, size_t command_list_length)
{
// ensure line is not empty
if (!line || 0==strlen(line)) {
if (!line || 0 == strlen(line)) {
return false;
}
// ensure command are available
if (NULL==command_list || 0==command_list_length) {
if (NULL == command_list || 0 == command_list_length) {
return false;
}
@ -49,29 +49,35 @@ bool menu_handle_command(const char* line, const struct menu_command_t* command_
// find corresponding command
bool command_found = false; // remember if we found the corresponding command
for (size_t i=0; i<command_list_length; i++) { // go through available command list
for (size_t i = 0; i < command_list_length; i++) { // go through available command list
struct menu_command_t command = command_list[i]; // get current command
if ((1==strlen(word) && command.shortcut==word[0]) || 0==strcmp(word, command.name)) { // check if shortcut or name match
if ((1 == strlen(word) && command.shortcut == word[0]) || 0 == strcmp(word, command.name)) { // check if shortcut or name match
command_found = true; // remember we found the command
if (command.command_handler) { // ensure there is an command handler
if (MENU_ARGUMENT_NONE==command.argument) { // check if argument can be passed
if (MENU_ARGUMENT_NONE == command.argument) { // check if argument can be passed
(*command.command_handler)(NULL); // call without argument
} else { // argument can be passed
const char* original_argument = line+strlen(word)+1; // remember the start of the argument in the original line
const char* original_argument = line + strlen(word)+1; // remember the start of the argument in the original line
word = strtok(NULL, delimiter); // get next word
if (!word) { // no argument provided
(*command.command_handler)(NULL); // call without argument
} else if (MENU_ARGUMENT_SIGNED==command.argument) { // next argument should be a signed integer
int32_t argument = atoi(word); // get signed integer
} else if (MENU_ARGUMENT_SIGNED == command.argument) { // next argument should be a signed integer
int32_t argument = strtol(word, NULL, 10); // get signed integer
(*command.command_handler)(&argument); // call with argument
} else if (MENU_ARGUMENT_UNSIGNED==command.argument) { // next argument should be an unsigned integer
uint32_t argument = atoi(word); // get unsigned integer
} else if (MENU_ARGUMENT_UNSIGNED == command.argument) { // next argument should be an unsigned integer
uint32_t argument = strtoul(word, NULL, 10); // get unsigned integer
(*command.command_handler)(&argument); // call with argument
} else if (MENU_ARGUMENT_FLOAT==command.argument) { // next argument should be a floating point number
} else if (MENU_ARGUMENT_HEX == command.argument) { // next argument should be a hexadecimal
uint32_t argument = strtoul(word, NULL, 16); // get hexadecimal
(*command.command_handler)(&argument); // call with argument
} else if (MENU_ARGUMENT_BINARY == command.argument) { // next argument should be a binry
uint32_t argument = strtoul(word, NULL, 2); // get binary
(*command.command_handler)(&argument); // call with argument
} else if (MENU_ARGUMENT_FLOAT == command.argument) { // next argument should be a floating point number
double argument = atof(word); // get floating point number
(*command.command_handler)(&argument); // call with argument
} else if (MENU_ARGUMENT_STRING==command.argument) { // next argument should be a string
if (delimiter[0]==original_argument[strlen(word)]) { // if there is more than one word
} else if (MENU_ARGUMENT_STRING == command.argument) { // next argument should be a string
if (delimiter[0] == original_argument[strlen(word)]) { // if there is more than one word
word[strlen(word)] = delimiter[0]; // remove the end of string
}
(*command.command_handler)(word); // call with argument (remaining of the string)
@ -84,9 +90,9 @@ bool menu_handle_command(const char* line, const struct menu_command_t* command_
// find default command
if (!command_found) { // we didn't find the corresponding command
for (size_t i=0; i<command_list_length; i++) { // go through available command list
for (size_t i = 0; i < command_list_length; i++) { // go through available command list
struct menu_command_t command = command_list[i]; // get current command
if (0==command.shortcut && NULL==command.name) { // check if there is a default command
if (0 == command.shortcut && NULL == command.name) { // check if there is a default command
command_found = true; // remember we found the command
if (command.command_handler) { // ensure there is an command handler
(*command.command_handler)(word); // call with current word
@ -102,14 +108,14 @@ bool menu_handle_command(const char* line, const struct menu_command_t* command_
void menu_print_commands(const struct menu_command_t* command_list, size_t command_list_length)
{
for (size_t i=0; i<command_list_length; i++) {
for (size_t i = 0; i < command_list_length; i++) {
struct menu_command_t command = command_list[i];
if (command.name) {
if (command.shortcut) {
printf("%c|", command.shortcut);
}
printf("%s", command.name);
if (MENU_ARGUMENT_NONE!=command.argument && command.argument_description) {
if (MENU_ARGUMENT_NONE != command.argument && command.argument_description) {
printf(" %s", command.argument_description);
} else {
printf("\t");
@ -121,4 +127,3 @@ void menu_print_commands(const struct menu_command_t* command_list, size_t comma
}
}
}

View File

@ -22,8 +22,10 @@
/** types of argument accepted by the command */
enum menu_argument_t {
MENU_ARGUMENT_NONE, /**< no argument accepted */
MENU_ARGUMENT_SIGNED, /**< int32 argument accepted */
MENU_ARGUMENT_UNSIGNED, /**< uint32 argument accepted */
MENU_ARGUMENT_SIGNED, /**< int32 decimal argument accepted */
MENU_ARGUMENT_UNSIGNED, /**< uint32 decimal argument accepted */
MENU_ARGUMENT_HEX, /**< uint32 hexadecimal argument accepted */
MENU_ARGUMENT_BINARY, /**< uint32 binary argument accepted */
MENU_ARGUMENT_FLOAT, /**< double argument accepted */
MENU_ARGUMENT_STRING, /**< string argument accepted */
};

View File

@ -97,7 +97,6 @@ static void microwire_master_wait_clock(void)
}
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
@ -194,7 +193,7 @@ void microwire_master_read(uint32_t address, uint16_t* data, size_t length)
// there should already be a '0' dummy bit
if (0!=gpio_get(GPIO(MICROWIRE_MASTER_SDI_PORT), GPIO(MICROWIRE_MASTER_SDI_PIN))) { // the dummy bit wasn't '0'
goto clean;
goto clean;
}
// read data
@ -207,7 +206,7 @@ void microwire_master_read(uint32_t address, uint16_t* data, size_t length)
}
}
}
clean:
microwire_master_stop(); // stop communication and clean up
}
@ -251,7 +250,7 @@ void microwire_master_write(uint32_t address, uint16_t data)
microwire_master_send_bit(false); // send '0' data bit
}
}
microwire_master_stop(); // clean up
}
@ -310,6 +309,6 @@ void microwire_master_write_all(uint16_t data)
microwire_master_send_bit(false); // send '0' data bit
}
}
microwire_master_stop(); // clean up
}

View File

@ -57,7 +57,7 @@ volatile enum {
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_STATE_MASTER_READ, /**< master is reading bits */
ONEWIRE_MAX /** to count the number of possible states */
} onewire_master_state = ONEWIRE_STATE_IDLE;
@ -116,7 +116,7 @@ void TIM_ISR(ONEWIRE_MASTER_TIMER)(void)
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(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // pull signal high to end time slot
gpio_set(GPIO(ONEWIRE_MASTER_PORT),GPIO(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
@ -135,7 +135,7 @@ void TIM_ISR(ONEWIRE_MASTER_TIMER)(void)
onewire_master_state = ONEWIRE_STATE_ERROR; // indicate error
}
break;
case ONEWIRE_STATE_MASTER_READ: // master has to read a bit set by slave
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(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN))) { // check if the slave kept it low
buffer[buffer_bit/8] |= (1<<(buffer_bit%8)); // save bit "1"
@ -172,7 +172,7 @@ void onewire_master_setup(void)
rcc_periph_clock_enable(RCC_GPIO(ONEWIRE_MASTER_PORT)); // enable clock for GPIO peripheral
gpio_set(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // idle is high (using pull-up resistor)
gpio_set_mode(GPIO(ONEWIRE_MASTER_PORT), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO(ONEWIRE_MASTER_PIN)); // normal 1-Wire communication (only using external pull-up resistor)
// setup timer to generate/measure signal timing
rcc_periph_clock_enable(RCC_TIM(ONEWIRE_MASTER_TIMER)); // enable clock for timer peripheral
timer_reset(TIM(ONEWIRE_MASTER_TIMER)); // reset timer state
@ -413,13 +413,13 @@ uint64_t onewire_master_rom_read(void)
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;
}

View File

@ -72,13 +72,13 @@ bool onewire_master_rom_skip(void);
*/
bool onewire_master_rom_match(uint64_t code);
/** read data byte
* @note it is up to the user to send the reset pulse
* @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
* @note it is up to the user to send the reset pulse
* @param[in] data byte to write
* @return if operation succeeded
*/

View File

@ -94,7 +94,7 @@ 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
@ -120,7 +120,7 @@ void onewire_slave_setup(uint8_t family, uint64_t serial)
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
timer_reset(TIM(ONEWIRE_SLAVE_TIMER)); // reset timer state
@ -344,7 +344,7 @@ void TIM_ISR(ONEWIRE_SLAVE_TIMER)(void)
onewire_slave_state = ONEWIRE_STATE_IDLE; // stop comparing and go back to idle
}
}
break;
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
@ -367,7 +367,7 @@ void TIM_ISR(ONEWIRE_SLAVE_TIMER)(void)
bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare next ROM code byte
}
}
break;
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

View File

@ -15,7 +15,7 @@
/** printing utilities to replace the large printf from the standard library (code)
* @file print.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017
* @date 2017-2019
*/
/* standard libraries */
#include <stdint.h> // standard integer types
@ -25,6 +25,7 @@
#include <math.h> // mathematics utilities to handle floating points
/* own libraries */
#include "global.h" // some macro definitions
#include "print.h" // printing utilities
uint8_t print_error;
@ -55,11 +56,11 @@ static void print_printed(size_t* length, size_t printed)
static size_t print_char(char** str, size_t* size, char c)
{
size_t length = 1; // remember how many characters have been printed or should have been added on string (normally just one)
if (0==c) { // don't print string termination character
if (0 == c) { // don't print string termination character
length = 0; // remember we didn't print anything
} else if (NULL==str || NULL==*str || NULL==size) { // character should not be saved on string
} else if (NULL == str || NULL == *str || NULL == size) { // character should not be saved on string
length = putc(c); // print on user define output
} else if (*size>1) { // there is enough space in the string to store the character
} else if (*size > 1) { // there is enough space in the string to store the character
**str = c; // add provided character to string
*str += 1; // go to next character on string
*size -= 1; // remember we used one character on string
@ -97,9 +98,9 @@ static size_t print_unsigned(char** str, size_t* size, uint64_t u, uint32_t padd
uint8_t digits = 0; // to count the number of digits
size_t length = 0; // number of characters printed
do {
number[digits++] = '0'+(u%10); // store digit
number[digits++] = '0'+(u % 10); // store digit
u /= 10; // go to next digit
} while (u>0);
} while (u > 0);
if (sign) { // print sign
print_printed(&length, print_char(str, size, '+')); // we only have positive numbers
}
@ -107,7 +108,7 @@ static size_t print_unsigned(char** str, size_t* size, uint64_t u, uint32_t padd
print_printed(&length, print_char(str, size, '0')); // print 0
}
for (uint8_t digit = 0; digit < digits; digit++) { // go through all digits
print_printed(&length, print_char(str, size, number[digits-digit-1])); // print digit (in reverse order)
print_printed(&length, print_char(str, size, number[digits - digit - 1])); // print digit (in reverse order)
}
return length; // return number of characters printed
}
@ -160,15 +161,15 @@ static size_t print_float(char** str, size_t* size, double f, uint32_t padding,
double f_abs = fabs(f); // only work using the absolute value now that the sign is printed
// get the exponent
int8_t exponent = 0; // exponent min/max for double is 37
if (f_abs<1.0) {
while (f_abs<pow(10.0, exponent-1)) { // find negative exponent, base 10
if (f_abs < 1.0) {
while (f_abs < pow(10.0, exponent - 1)) { // find negative exponent, base 10
exponent -= 1; // decrement in deci
}
if (padding) { // respect padding wish
exponent -= padding;
}
} else {
while (f_abs>=pow(10.0, exponent)) { // find the positive exponent, base 10
while (f_abs >= pow(10.0, exponent)) { // find the positive exponent, base 10
exponent += 3; // increment in kilo
}
if (padding) { // respect padding wish
@ -184,7 +185,7 @@ static size_t print_float(char** str, size_t* size, double f, uint32_t padding,
if (fractional) {
print_printed(&length, print_char(str, size, '.')); // print decimal point
f_abs -= (uint64_t)f_abs; // remove integer part
for (uint32_t frac=0; frac<fractional; frac++) { // print fractional parts
for (uint32_t frac = 0; frac < fractional; frac++) { // print fractional parts
f_abs *= 10.0;
print_printed(&length, print_unsigned(str, size, f_abs, 0, false));
f_abs -= (uint64_t)f_abs;
@ -197,7 +198,7 @@ static size_t print_float(char** str, size_t* size, double f, uint32_t padding,
}
} else { // f=0
// print sign
if (f<0) {
if (f < 0) {
print_printed(&length, print_char(str, size, '-')); // print sign
} else if (sign) {
print_printed(&length, print_char(str, size, '+')); // print sign
@ -221,12 +222,12 @@ static size_t print_float(char** str, size_t* size, double f, uint32_t padding,
static size_t print_nibble(char** str, size_t* size, uint8_t nibble, bool upcase) {
size_t length = 0; // number of characters printed
nibble &= 0x0f; // ensure we only have a nibble
if (nibble<10) {
print_printed(&length, print_char(str, size, '0'+nibble));
if (nibble < 10) {
print_printed(&length, print_char(str, size, '0' + nibble));
} else if (upcase) {
print_printed(&length, print_char(str, size, 'A'+nibble-10));
print_printed(&length, print_char(str, size, 'A' + nibble - 10));
} else {
print_printed(&length, print_char(str, size, 'a'+nibble-10));
print_printed(&length, print_char(str, size, 'a' + nibble - 10));
}
return length; // return number of characters printed
}
@ -248,31 +249,31 @@ static size_t print_hex(char** str, size_t* size, uint64_t hex, uint32_t padding
}
uint8_t digits = 0; // number of digits to print
// figure out number of digits to print
if (hex>0xffffffffffffffUL) {
if (hex > 0xffffffffffffffUL) {
digits = 16;
} else if (hex>0xffffffffffffUL) {
} else if (hex > 0xffffffffffffUL) {
digits = 14;
} else if (hex>0xffffffffffUL) {
} else if (hex > 0xffffffffffUL) {
digits = 12;
} else if (hex>0xffffffffUL) {
} else if (hex > 0xffffffffUL) {
digits = 10;
} else if (hex>0xffffffUL) {
} else if (hex > 0xffffffUL) {
digits = 8;
} else if (hex>0xffffUL) {
} else if (hex > 0xffffUL) {
digits = 6;
} else if (hex>0xffUL) {
} else if (hex > 0xffUL) {
digits = 4;
} else {
digits = 2;
}
for (uint32_t zeros = digits; zeros<padding; zeros++) { // print padding 0's
for (uint32_t zeros = digits; zeros < padding; zeros++) { // print padding 0's
print_printed(&length, print_char(str, size, '0')); // print 0
}
for (uint8_t digit = 0; digit < digits; digit++) { // go through all digits
print_printed(&length, print_nibble(str, size, hex>>((digits-digit-1)*4), upcase)); // print nibble (in reverse order)
print_printed(&length, print_nibble(str, size, hex >> ((digits - digit - 1) * 4), upcase)); // print nibble (in reverse order)
}
return length; // return number of characters printed
}
}
/** print bits
* @param[out] str string to print bits on (use NULL to print on user output)
@ -287,10 +288,10 @@ static size_t print_bits(char** str, size_t* size, uint64_t u, uint32_t padding,
uint8_t digits = 0; // to count the number of digits
size_t length = 0; // number of characters printed
do {
bits[digits++] = '0'+(u&0x1); // store bit
bits[digits++] = '0' + (u & 0x1); // store bit
u >>= 1; // go to next bit
} while (u>0);
if (digits>sizeof(bits)) { // prevent buffer underflow
} while (u > 0);
if (digits > sizeof(bits)) { // prevent buffer underflow
return 0;
}
if (prefix) { // print prefix
@ -301,7 +302,7 @@ static size_t print_bits(char** str, size_t* size, uint64_t u, uint32_t padding,
print_printed(&length, print_char(str, size, '0')); // print 0
}
for (uint8_t digit = 0; digit < digits; digit++) { // go through all bits
print_printed(&length, print_char(str, size, bits[digits-digit-1])); // print bit (in reverse order)
print_printed(&length, print_char(str, size, bits[digits - digit - 1])); // print bit (in reverse order)
}
return length; // return number of characters printed
}
@ -311,7 +312,7 @@ static size_t print_bits(char** str, size_t* size, uint64_t u, uint32_t padding,
* @param[in,out] size size of string (writes at most size characters on str, including the termination null character '\0')
* @param[in] format format string to be printed
* @param[in] va arguments referenced by format string to be printed
* @return number of characters printed (a return value of size or more means that the output was truncated)
* @return number of characters printed (a return value of size or more means that the output was truncated)
**/
static size_t vsnprintf(char** str, size_t* size, const char *format, va_list va)
{
@ -322,63 +323,63 @@ static size_t vsnprintf(char** str, size_t* size, const char *format, va_list va
while (*format) { // go through format string
padding = 0; // reset padding
sign = false; // reset sign
if ('%'!=*format) { // check for format specifier prefix
if ('%' != *format) { // check for format specifier prefix
print_printed(&length, print_char(str, size, *format++)); // print character (no interpretation needed)
} else {
format++; // go to format specifier
if (0==*format) { // end of string detected
if (0 == *format) { // end of string detected
print_error |= PRINT_ERROR_MALFORMED; // set error
goto end;
}
// check if sign need to be printed
if ('+'==*format) { // sign required
if ('+' == *format) { // sign required
sign = true; // remember sign is required
format++; // go to padding number
if (0==*format) { // end of string detected
if (0 == *format) { // end of string detected
print_error |= PRINT_ERROR_MALFORMED; // set error
goto end;
}
}
}
// check padding
if ('0'==*format) { // padding required
if ('0' == *format) { // padding required
padding = 0; // reset padding
format++; // go to padding number
while (*format>='0' && *format<='9') {
if (padding>UINT32_MAX/10) { // check for overflow
while (*format >= '0' && *format <= '9') {
if (padding > UINT32_MAX / 10) { // check for overflow
print_error |= PRINT_ERROR_UNSUPPORTED; // set error
goto end;
}
padding *= 10; // go to next magnitude
if (padding>UINT32_MAX-(*format-'0')) { // check for overflow
if (padding > UINT32_MAX - (*format - '0')) { // check for overflow
print_error |= PRINT_ERROR_UNSUPPORTED; // set error
goto end;
}
padding += *format-'0'; // save digit
padding += *format - '0'; // save digit
format++; // go to next character
}
if (0==*format) { // end of string detected
if (0 == *format) { // end of string detected
print_error |= PRINT_ERROR_MALFORMED; // set error
goto end;
}
}
// check fractional
if ('.'==*format) { // fractional required
if ('.' == *format) { // fractional required
fractional = 0; // reset fractional
format++; // go to fractional number
while (*format>='0' && *format<='9') {
if (fractional>UINT32_MAX/10) { // check for overflow
while (*format >= '0' && *format <= '9') {
if (fractional > UINT32_MAX / 10) { // check for overflow
print_error |= PRINT_ERROR_UNSUPPORTED; // set error
goto end;
}
fractional *= 10; // go to next magnitude
if (fractional>UINT32_MAX-(*format-'0')) { // check for overflow
if (fractional > UINT32_MAX - (*format - '0')) { // check for overflow
print_error |= PRINT_ERROR_UNSUPPORTED; // set error
goto end;
}
fractional += *format-'0'; // save digit
fractional += *format - '0'; // save digit
format++; // go to next character
}
if (0==*format) { // end of string detected
if (0 == *format) { // end of string detected
print_error |= PRINT_ERROR_MALFORMED; // set error
goto end;
}
@ -408,13 +409,13 @@ static size_t vsnprintf(char** str, size_t* size, const char *format, va_list va
case 'f':
print_printed(&length, print_float(str, size, va_arg(va,double), padding, fractional, sign));
break;
case 'x': // for uint8_t, uint16_t, uint32_t downcase hexadecimal
case 'x': // for uint8_t, uint16_t, uint32_t downcase hexadecimal
print_printed(&length, print_hex(str, size, va_arg(va,uint32_t), padding, sign, false));
break;
case 'X': // for uint64_t downcase hexadecimal
print_printed(&length, print_hex(str, size, va_arg(va,uint64_t), padding, sign, false));
break;
case 'h': // for uint8_t, uint16_t, uint32_t upcase hexadecimal
case 'h': // for uint8_t, uint16_t, uint32_t upcase hexadecimal
print_printed(&length, print_hex(str, size, va_arg(va,uint32_t), padding, sign, true));
break;
case 'H': // for uint64_t upcase hexadecimal
@ -434,9 +435,9 @@ static size_t vsnprintf(char** str, size_t* size, const char *format, va_list va
}
}
end:
if (NULL!=str && NULL!=*str && NULL!=size) { // when working on a string
**str='\0'; // enforce null termination
if (*size>0) {
if (NULL != str && NULL != *str && NULL != size) { // when working on a string
**str = '\0'; // enforce null termination
if (*size > 0) {
*size -= 1; // remember we used memory
} else {
print_error |= PRINT_ERROR_TRUNCATED; // indicate we truncated the string
@ -464,3 +465,38 @@ size_t snprintf(char* str, size_t size, const char* format, ...)
va_end(arglist);
return length;
}
size_t print_xxd(uint32_t offset, const uint8_t* data, size_t length)
{
size_t to_return = 0; // total number of characters printed
uint32_t address = (offset / 16) * 16; // address of the data to print
if (offset > SIZE_MAX - length) { // prevent integer overflow on address
return 0;
}
while (address < offset + length) { // print data lines until the end
ADDU32_SAFE(to_return, printf("%08x: ", address)); // print address
for (uint8_t i = 0; i < 16; i++) {
if (address < offset || address >= offset + length) {
ADDU32_SAFE(to_return, printf(" "));
} else {
ADDU32_SAFE(to_return, printf("%02x ", data[address - offset]));
}
address++;
}
address -= 16;
ADDU32_SAFE(to_return, putc(' '));
for (uint8_t i = 0; i < 16; i++) {
if (address < offset || address >= offset + length) {
ADDU32_SAFE(to_return, putc(' '));
} else if (data[address - offset] < ' ' || data[address - offset] > '~') {
ADDU32_SAFE(to_return, putc('.'));
} else {
ADDU32_SAFE(to_return, putc(data[address - offset]));
}
address++;
}
ADDU32_SAFE(to_return, putc('\n'));
}
return to_return;
}

View File

@ -30,7 +30,7 @@
* - B for uint64_t bits
* @file print.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017
* @date 2017-2019
*/
#pragma once
@ -59,6 +59,13 @@ size_t printf(const char* format, ...);
* @param[in,out] size size of string (writes at most size characters on str, including the termination null character '\0')
* @param[in] format format string to be printed
* @param[in] ... arguments referenced by format string to be printed
* @return number of characters printed (a return value of size or more means that the output was truncated)
* @return number of characters printed (a return value of size or more means that the output was truncated)
**/
size_t snprintf(char* str, size_t size, const char* format, ...);
/** print data in xxd style
* @param[in] offset base address of the data to print
* @param[in] data data to print
* @param[in] length size of data to print
* @return number of characters printed (a return value of size or more means that the output was truncated)
*/
size_t print_xxd(uint32_t offset, const uint8_t* data, size_t length);

View File

@ -16,7 +16,7 @@
* @file rtc_dcf77.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016-2017
* @note peripherals used: GPIO @ref rtc_dcf77_gpio, timer @ref rtc_dcf77_timer
* @note peripherals used: GPIO @ref rtc_dcf77_gpio, timer @ref rtc_dcf77_timer
*/
/* standard libraries */

View File

@ -16,7 +16,7 @@
* @file rtc_dcf77.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016-2017
* @note peripherals used: GPIO @ref rtc_dcf77_gpio, timer @ref rtc_dcf77_timer
* @note peripherals used: GPIO @ref rtc_dcf77_gpio, timer @ref rtc_dcf77_timer
*/
#pragma once

View File

@ -179,7 +179,7 @@ bool sensor_ds18b20_precision(uint64_t code, uint8_t precision)
}
// send new configuration (and keep the alarm values)
uint8_t configuration[3] = {0}; // to store T_HIGH, T_LOW, and configuration
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)

View File

@ -16,7 +16,7 @@
* @file sensor_pzem.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
* @note peripherals used: USART @ref sensor_pzem_usart, timer @ref sensor_pzem_timer
* @note peripherals used: USART @ref sensor_pzem_usart, timer @ref sensor_pzem_timer
*/
/* standard libraries */
@ -122,7 +122,7 @@ void sensor_pzem_measurement_request(uint32_t address, enum sensor_pzem_measurem
}
sensor_pzem_measurement_received = false; // reset flag
rx_i = 0; // prepare buffer to receive next measurement
rx_i = 0; // prepare buffer to receive next measurement
}
struct sensor_pzem_measurement_t sensor_pzem_measurement_decode(void)
@ -172,7 +172,7 @@ struct sensor_pzem_measurement_t sensor_pzem_measurement_decode(void)
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)
{

View File

@ -73,7 +73,7 @@ static enum timeout_t {
/** current timeout used */
static uint16_t timeout_times[TIMEOUT_MAX] = {0};
/** SDM120 3xxxx input register start addresses for the measurement types */
/** 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)
@ -223,7 +223,7 @@ static bool sensor_sdm120_transmit_request(uint8_t meter_id, uint8_t function, u
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(SENSOR_SDM120_REDE_PORT),GPIO(SENSOR_SDM120_REDE_PIN)); // enable driver output and disable receive output
// start timeout
timeout = TIMEOUT_BEGIN; // select time before sending message
@ -298,7 +298,7 @@ float sensor_sdm120_measurement_decode(void)
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)
{

View File

@ -99,7 +99,7 @@ static void terminal_shift_line(uint16_t to_copy, uint16_t nb_copy, uint16_t to_
terminal_shift_line(to_copy+1, nb_copy>0 ? nb_copy-1 : 0, to_shift+1); // shift next character
}
if (nb_copy>0) {
terminal_buffer[terminal_end-nb_copy] = c; // place back
terminal_buffer[terminal_end-nb_copy] = c; // place back
}
}
@ -359,7 +359,7 @@ void terminal_send(volatile char c)
}
terminal_line = terminal_line_new; // set new line start
terminal_last = true; // remember we are on the last line
}
}
if (terminal_line==terminal_end) { // line is empty
// nothing to do
} else {

View File

@ -140,7 +140,7 @@ bool uart_soft_setup(uint32_t *rx_baudrates, uint32_t *tx_baudrates)
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
gpio_set(uart_soft_rx_states[rx]->port, uart_soft_rx_states[rx]->pin); // pull up to avoid noise when not connected
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_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
@ -149,13 +149,13 @@ bool uart_soft_setup(uint32_t *rx_baudrates, uint32_t *tx_baudrates)
}
// save UART transmit definition
#if defined(UART_SOFT_TX_PORT0) && defined(UART_SOFT_TX_PIN0)
#if defined(UART_SOFT_TX_PORT0) && defined(UART_SOFT_TX_PIN0)
uart_soft_tx_states[0] = calloc(1,sizeof(struct soft_uart_tx_state)); // create state definition
uart_soft_tx_states[0]->port = GPIO(UART_SOFT_TX_PORT0); // save receive port
uart_soft_tx_states[0]->pin = GPIO(UART_SOFT_TX_PIN0); // save receive pin
uart_soft_tx_states[0]->rcc = RCC_GPIO(UART_SOFT_TX_PORT0); // save receive port peripheral clock
#endif
// setup UART transmit GPIO
for (uint8_t tx=0; tx<4; tx++) {
if (!uart_soft_tx_states[tx]) { // verify is transmit UART is defined
@ -291,7 +291,7 @@ void uart_soft_putbyte_nonblocking(uint8_t uart, uint8_t byte)
{
if (uart>=4 || !uart_soft_tx_states[uart]) { // ensure transmit UART port is defined
return; // return
}
}
while (uart_soft_tx_states[uart]->buffer_used>=LENGTH(uart_soft_tx_states[uart]->buffer)) { // idle until there is place in the buffer
__WFI(); // sleep until something happened
}

View File

@ -251,7 +251,7 @@ static void usb_disconnect(void)
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO9);
gpio_set(GPIOB, GPIO9);
for (uint32_t i = 0; i < 0x2000; i++) { // wait for at least 10 ms
__asm__("nop");
__asm__("nop");
}
#else
// pull USB D+ low for a short while
@ -259,7 +259,7 @@ static void usb_disconnect(void)
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
gpio_clear(GPIOA, GPIO12);
for (uint32_t i = 0; i < 0x2000; i++) { // wait for at least 10 ms
__asm__("nop");
__asm__("nop");
}
#endif
}
@ -292,7 +292,7 @@ static enum usbd_request_return_codes usb_cdcacm_control_request(usbd_device *us
if (usb_dfu_interface.bInterfaceNumber==req->wIndex) { // check if request is for DFU
switch (req->bRequest) {
case DFU_DETACH: // USB detach requested
*complete = usb_dfu_detach; // detach after reply
*complete = usb_dfu_detach; // detach after reply
break;
case DFU_GETSTATUS: // get status
(*buf)[0] = DFU_STATUS_OK;; // set OK status
@ -355,7 +355,7 @@ static void usb_cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
char usb_data[USB_DATA_TRANSFER_SIZE] = {0}; // buffer to read data
uint16_t usb_length = 0; // length of incoming data
// receive data
usb_length = usbd_ep_read_packet(usbd_dev, usb_cdcacm_data_endpoints[0].bEndpointAddress, usb_data, sizeof(usb_data));
if (usb_length) { // copy received data
@ -398,7 +398,7 @@ static void usb_cdcacm_data_tx_cb(usbd_device *usbd_dev, uint8_t ep)
}
/** USB CDC ACM communication callback
* @note if transmission happens before the control setting is complete with a response form the communication endpoint, Linux echoes back the data
* @note if transmission happens before the control setting is complete with a response form the communication endpoint, Linux echoes back the data
* @param[in] usbd_dev USB device descriptor
* @param[in] ep endpoint where data came in
*/
@ -438,8 +438,8 @@ void usb_cdcacm_setup(void)
usb_device = usbd_init(&st_usbfs_v1_usb_driver, &usb_cdcacm_device_descriptor, &usb_cdcacm_configuration_descriptor, usb_strings, LENGTH(usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usb_device, usb_cdcacm_set_config);
nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ); // enable interrupts (to not have to poll all the time)
// reset buffer states
// reset buffer states
tx_i = 0;
tx_used = 0;
tx_lock = false; // release lock

View File

@ -27,5 +27,5 @@ void usb_cdcacm_setup(void);
/** send character over USB (non-blocking)
* @param[in] c character to send
* @note blocks if transmit buffer is full, else puts in buffer and returns
*/
*/
void usb_cdcacm_putchar(char c);

View File

@ -120,8 +120,8 @@ static const struct usb_config_descriptor usb_dfu_configuration = {
*/
static const char *usb_dfu_strings[] = {
"CuVoodoo", /**< manufacturer string */
"CuVoodoo STM32F1xx DFU bootloader", /**< product string */
"DFU bootloader (DFU mode)", /**< DFU interface string */
"CuVoodoo STM32F1xx DFU bootloader", /**< product string */
"DFU bootloader (DFU mode)", /**< DFU interface string */
};
/** disconnect USB to force re-enumerate */
@ -235,7 +235,7 @@ static enum usbd_request_return_codes usb_dfu_control_request(usbd_device *usbd_
}
if (*len % 2) { // we can only write half words
download_data[*len++] = 0xff; // leave flash untouched
}
}
usb_dfu_state = STATE_DFU_DNLOAD_SYNC; // go to sync state
*complete = usb_dfu_flash; // start flashing the downloaded data
}
@ -257,7 +257,7 @@ static enum usbd_request_return_codes usb_dfu_control_request(usbd_device *usbd_
} else if (STATE_DFU_MANIFEST_SYNC == usb_dfu_state) {
usb_dfu_state = STATE_DFU_MANIFEST; // go to manifest mode
led_off(); // indicate the end
*complete = usb_dfu_reset; // start reset without waiting for request since we advertised we would detach
*complete = usb_dfu_reset; // start reset without waiting for request since we advertised we would detach
}
break;
case DFU_CLRSTATUS: // clear status

View File

@ -293,7 +293,7 @@ static const uint8_t pict5x7[][5] = {
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
/** which grid/part to activate
* @note digits and matrix can be combined
*/
static volatile uint8_t vfd_grid = 0;
@ -309,7 +309,7 @@ void vfd_digit(uint8_t nb, char c)
}
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)
@ -327,7 +327,7 @@ void vfd_digit(uint8_t nb, char c)
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
@ -345,19 +345,19 @@ void vfd_digit(uint8_t nb, char c)
void vfd_matrix(uint8_t nb, char c)
{
// check the matrix exists
if (!(nb<VFD_MATRIX)) {
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);
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)) {
@ -423,10 +423,10 @@ void vfd_setup(void)
rcc_periph_clock_enable(VFD_PORT_RCC); // enable clock for VFD GPIO
gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, VFD_STR); // set VFD pin to output push-pull
gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, VFD_NLE); // set VFD pin to output push-pull
gpio_set(VFD_PORT, VFD_STR); // disable HV output
gpio_clear(VFD_PORT, VFD_NLE); // do not output latched data
/* setup SPI to transmit data */
rcc_periph_clock_enable(VFD_SPI_RCC); // enable SPI clock
rcc_periph_clock_enable(VFD_SPI_PORT_RCC); // enable clock for VFD SPI GPIO
@ -451,12 +451,12 @@ void vfd_setup(void)
* 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(VFD_SPI);
spi_enable_software_slave_management(VFD_SPI);
spi_set_nss_high(VFD_SPI); // set NSS high
nvic_enable_irq(VFD_SPI_IRQ); // enable SPI interrupt
nvic_enable_irq(VFD_SPI_IRQ); // enable SPI interrupt
spi_enable(VFD_SPI); // enable SPI (the tx empty interrupt will trigger)
/* setup timer to refresh display */
rcc_periph_clock_enable(VFD_TIMER_RCC); // enable clock for timer block
timer_reset(VFD_TIMER); // reset timer state
@ -465,7 +465,7 @@ void vfd_setup(void)
timer_set_period(VFD_TIMER, 0xffff/LENGTH(driver_data)/100); // set the refresh frequency
timer_enable_irq(VFD_TIMER, TIM_DIER_UIE); // enable interrupt for timer
nvic_enable_irq(VFD_TIMER_IRQ); // allow interrupt for timer
vfd_clear(); // initialize values
}