Merge branch 'master' of ssh://git.cuvoodoo.info/stm32f1
This commit is contained in:
commit
d7cd572f9a
|
@ -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
|
||||
|
|
4
global.c
4
global.c
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
23
global.h
23
global.h
|
@ -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) */
|
||||
|
|
|
@ -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)
|
||||
|
|
452
lib/i2c_master.c
452
lib/i2c_master.c
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, // ~
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
41
lib/menu.c
41
lib/menu.c
|
@ -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
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
142
lib/print.c
142
lib/print.c
|
@ -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;
|
||||
}
|
||||
|
|
11
lib/print.h
11
lib/print.h
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue