cherry-pick from busvoodoo branch, part 4

This commit is contained in:
King Kévin 2018-02-18 15:21:18 +01:00
parent 8ba50b2d65
commit 62bfaf3973
10 changed files with 410 additions and 179 deletions

View File

@ -161,12 +161,12 @@ end
desc "export binary"
rule '.bin' => '.elf' do |t|
sh "#{OBJCOPY} --strip-all --strip-debug --output-target binary #{t.source} #{t.name}"
sh "#{OBJCOPY} --output-target binary #{t.source} #{t.name}"
end
desc "export intel hex file"
rule '.hex' => '.elf' do |t|
sh "#{OBJCOPY} --strip-all --strip-debug --output-target ihex #{t.source} #{t.name}"
sh "#{OBJCOPY} --output-target ihex #{t.source} #{t.name}"
end
desc "export list"
@ -227,9 +227,9 @@ task :debug => APPLICATION+".elf" do |t|
case SWD_ADAPTER
when "STLINKV2"
# for GDB to work with openOCD the firmware needs to be reloaded
sh "#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' --eval-command='monitor reset halt' --eval-command='load' --eval-command='monitor reset init' #{t.source}"
excec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' --eval-command='monitor reset halt' --eval-command='load' --eval-command='monitor reset init' #{t.source}")
when "BMP"
sh "#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='monitor version' --eval-command='monitor swdp_scan' --eval-command='attach 1' #{t.source}"
exec("#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='monitor version' --eval-command='monitor swdp_scan' --eval-command='attach 1' #{t.source}")
end
end

View File

@ -1,16 +1,20 @@
/* linker script for application running on STM32F103x8 micro-controller
* the STM32F103x8 has 64kB of flash starting at 0x0800 0000, and 20kB of RAM starting at 0x2000 0000
* the USB DFU bootloader will take the first 8 kB of flash, followed by the application
* the STM32F103xC has 256 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
* the USB DFU bootloader will take the first 8 KB of flash, followed by the application
*/
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000 + 8K, LENGTH = 56K
rom (rx) : ORIGIN = 0x08000000 + 8K, LENGTH = 248K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
PROVIDE(__application_beginning = ORIGIN(rom));
/* only provide application end if you want to force a flash size
i.e. STM32F103x8 most often have if fact 128 KB instead of the specified and advertised 64 KB
PROVIDE(__application_end = ORIGIN(rom) + LENGTH(rom));
PROVIDE(__flash_end = ORIGIN(rom) + LENGTH(rom));
*/
/* include rest of the definitions for the STM32F1 family */
INCLUDE libopencm3_stm32f1.ld

View File

@ -1,6 +1,6 @@
/* linker script for application running on STM32F103x8 micro-controller
* the STM32F103x8 has 64kB of flash starting at 0x0800 0000, and 20kB of RAM starting at 0x2000 0000
* the USB DFU bootloader will take the first 8 kB of flash, followed by the application
* the STM32F103xC has 256 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
* the USB DFU bootloader will take the first 8 KB of flash, followed by the application
*/
/* Define memory regions. */
@ -10,7 +10,11 @@ MEMORY
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
PROVIDE(__application_beginning = ORIGIN(rom) + LENGTH(rom));
PROVIDE(__application_end = __application_beginning + 56K);
/* only provide application end if you want to force a flash size
i.e. STM32F103x8 most often have if fact 128 KB instead of the specified and advertised 64 KB
PROVIDE(__application_end = __application_beginning + 248K);
PROVIDE(__flash_end = __application_beginning + 248K);
*/
/* include rest of the definitions for the STM32F1 family */
INCLUDE libopencm3_stm32f1.ld

View File

@ -31,6 +31,70 @@
/** concatenate 4 arguments */
#define CAT4(w,x,y,z) w##x##y##z
/** build year as number */
#define COMPUTE_BUILD_YEAR \
( \
(__DATE__[ 7] - '0') * 1000 + \
(__DATE__[ 8] - '0') * 100 + \
(__DATE__[ 9] - '0') * 10 + \
(__DATE__[10] - '0') \
)
/** build day as number */
#define COMPUTE_BUILD_DAY \
( \
((__DATE__[4] >= '0') ? (__DATE__[4] - '0') * 10 : 0) + \
(__DATE__[5] - '0') \
)
/** check if build month is January */
#define BUILD_MONTH_IS_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
/** check if build month is February */
#define BUILD_MONTH_IS_FEB (__DATE__[0] == 'F')
/** check if build month is March */
#define BUILD_MONTH_IS_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
/** check if build month is April */
#define BUILD_MONTH_IS_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p')
/** check if build month is May */
#define BUILD_MONTH_IS_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
/** check if build month is June */
#define BUILD_MONTH_IS_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
/** check if build month is July */
#define BUILD_MONTH_IS_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
/** check if build month is August */
#define BUILD_MONTH_IS_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u')
/** check if build month is September */
#define BUILD_MONTH_IS_SEP (__DATE__[0] == 'S')
/** check if build month is October */
#define BUILD_MONTH_IS_OCT (__DATE__[0] == 'O')
/** check if build month is November */
#define BUILD_MONTH_IS_NOV (__DATE__[0] == 'N')
/** check if build month is December */
#define BUILD_MONTH_IS_DEC (__DATE__[0] == 'D')
/** build month as number */
#define COMPUTE_BUILD_MONTH \
( \
(BUILD_MONTH_IS_JAN) ? 1 : \
(BUILD_MONTH_IS_FEB) ? 2 : \
(BUILD_MONTH_IS_MAR) ? 3 : \
(BUILD_MONTH_IS_APR) ? 4 : \
(BUILD_MONTH_IS_MAY) ? 5 : \
(BUILD_MONTH_IS_JUN) ? 6 : \
(BUILD_MONTH_IS_JUL) ? 7 : \
(BUILD_MONTH_IS_AUG) ? 8 : \
(BUILD_MONTH_IS_SEP) ? 9 : \
(BUILD_MONTH_IS_OCT) ? 10 : \
(BUILD_MONTH_IS_NOV) ? 11 : \
(BUILD_MONTH_IS_DEC) ? 12 : \
/* error default */ 99 \
)
/** check if build date is unknown */
#define BUILD_DATE_IS_BAD (__DATE__[0] == '?')
/** build year as number if known, or 0 if unknown */
#define BUILD_YEAR ((BUILD_DATE_IS_BAD) ? 0 : COMPUTE_BUILD_YEAR)
/** build month as number if known, or 0 if unknown */
#define BUILD_MONTH ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_MONTH)
/** build day as number if known, or 0 if unknown */
#define BUILD_DAY ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_DAY)
/** @defgroup reg_macro macros to define values based on other defines values
* @note used when the value is calculated or isn't a value
* @{
@ -298,8 +362,6 @@
#define DMA_CHANNEL_ISR_SPI1_RX dma1_channel4_isr /**< SPI1 RX is on DMA 1 channel 4 */
#define DMA_CHANNEL_ISR_SPI2_RX dma1_channel2_isr /**< SPI2 RX is on DMA 1 channel 2 */
#define DMA_CHANNEL_ISR_SPI3_RX dma2_channel1_isr /**< SPI3 RX is on DMA 2 channel 1 */
/** get DMA channel based on SPI identifier */
/** @} */
/** @defgroup board_led board LED GPIO

View File

@ -23,19 +23,27 @@
#include <stdlib.h> // general utilities
/* STM32 (including CM3) libraries */
#include <libopencm3/stm32/desig.h> // device signature utilities
#include <libopencm3/stm32/flash.h> // flash utilities
#include <libopencm3/stm32/desig.h> // device signature definitions
#include <libopencm3/stm32/dbgmcu.h> // debug definitions
#include "flash_internal.h" // flash storage library API
#include "global.h" // global definitions
/** the flash page size (medium-density devices have 1KiB page size) */
#define PAGE_SIZE 1024
bool flash_internal_read(uint32_t address, uint8_t *buffer, size_t size)
{
// verify it's in the flash area and do other sanity checks
if (address<FLASH_BASE || address>(UINT32_MAX-size) || (address+size)>(FLASH_BASE+DESIG_FLASH_SIZE*1024) || buffer==NULL || size==0) {
// sanity checks
if (address<FLASH_BASE || address>(UINT32_MAX-size) || buffer==NULL || size==0) {
return false;
}
// verify if it's in the flash area
#if defined(__flash_end)
if (address<FLASH_BASE || (address+size)>(uint32_t)&__flash_end)
#else
if (address<FLASH_BASE || (address+size)>(FLASH_BASE+DESIG_FLASH_SIZE*1024))
#endif
{
return false;
}
@ -49,36 +57,60 @@ bool flash_internal_read(uint32_t address, uint8_t *buffer, size_t size)
bool flash_internal_write(uint32_t address, uint8_t *buffer, size_t size)
{
// verify it's in the flash area and do other sanity checks
if (address<FLASH_BASE || address>(UINT32_MAX-size) || (address+size)>(FLASH_BASE+DESIG_FLASH_SIZE*1024) || buffer==NULL || size==0 || size%2) {
// sanity checks
if (address<FLASH_BASE || address>(UINT32_MAX-size) || buffer==NULL || size==0 || size%2) {
return false;
}
// verify if it's in the flash area
#if defined(__flash_end)
if (address<FLASH_BASE || (address+size)>(uint32_t)&__flash_end)
#else
if (address<FLASH_BASE || (address+size)>(FLASH_BASE+DESIG_FLASH_SIZE*1024))
#endif
{
return false;
}
// get page size
uint16_t page_size = 0;
if ((0x412==(DBGMCU_IDCODE&DBGMCU_IDCODE_DEV_ID_MASK)) || (0x412==(DBGMCU_IDCODE&DBGMCU_IDCODE_DEV_ID_MASK))) { // low-density (16-32 KB flash) and medium-density (64-128 KB flash) devices have 1 KB flash pages
page_size = 1024;
} else if ((0x414==(DBGMCU_IDCODE&DBGMCU_IDCODE_DEV_ID_MASK)) || (0x430==(DBGMCU_IDCODE&DBGMCU_IDCODE_DEV_ID_MASK)) || (0x418==(DBGMCU_IDCODE&DBGMCU_IDCODE_DEV_ID_MASK))) { // high-density (256-512 KB flash), XL-density (768-1024 KB flash) devices and connectivity line have 2 KB flash pages
page_size = 2048;
} else { // unknown device type (or unreadable type, see errata), deduce page size from flash size
if (DESIG_FLASH_SIZE<256) {
page_size = 1024;
} else {
page_size = 2048;
}
}
flash_unlock(); // unlock flash to be able to write it
while (size) { // write page by page until all data has been written
uint32_t page_start = address-(address%PAGE_SIZE); // get start of the current page
uint32_t page_start = address-(address%page_size); // get start of the current page
bool erase = false; // verify if the flash to write is erased of if we need to erase the page
for (uint32_t flash=address; flash<(address+size) && flash<(page_start+PAGE_SIZE); flash += 2) { // go through page
for (uint32_t flash=address; flash<(address+size) && flash<(page_start+page_size); flash += 2) { // go through page
if (*(uint16_t*)(flash)!=0xffff) { // is flash not erased
erase = true; // the erase flash
}
}
if (erase) { // make copy of the page to erase and erase it
uint8_t page_data[PAGE_SIZE]; // a copy of the complete page before the erase it
uint8_t page_data[page_size]; // a copy of the complete page before the erase it
uint16_t page_i = 0; // index for page data
// copy page before address
for (uint32_t flash=page_start; flash<address && flash<(page_start+PAGE_SIZE) && page_i<sizeof(page_data); flash++) {
for (uint32_t flash=page_start; flash<address && flash<(page_start+page_size) && page_i<page_size; flash++) {
page_data[page_i++] = *(uint8_t*)(flash);
}
// copy data starting at address
while (size>0 && page_i<sizeof(page_data)) {
while (size>0 && page_i<page_size) {
page_data[page_i++] = *buffer;
buffer++;
address++;
size--;
}
// copy data after buffer until end of page
while (page_i<sizeof(page_data)) {
while (page_i<page_size) {
page_data[page_i] = *(uint8_t*)(page_start+page_i);
page_i++;
}
@ -87,7 +119,7 @@ bool flash_internal_write(uint32_t address, uint8_t *buffer, size_t size)
flash_lock(); // lock back flash to protect it
return false;
}
for (uint16_t i=0; i<PAGE_SIZE/2; i++) { // write whole page
for (uint16_t i=0; i<page_size/2; i++) { // write whole page
flash_program_half_word(page_start+i*2, *((uint16_t*)(page_data+i*2)));
if (flash_get_status_flags()!=FLASH_SR_EOP) { // operation went wrong
flash_lock(); // lock back flash to protect it
@ -99,7 +131,7 @@ bool flash_internal_write(uint32_t address, uint8_t *buffer, size_t size)
}
}
} else { // simply data until end of page
while (size>0 && address<(page_start+PAGE_SIZE)) {
while (size>0 && address<(page_start+page_size)) {
flash_program_half_word(address, *((uint16_t*)(buffer)));
if (flash_get_status_flags()!=FLASH_SR_EOP) { // operation went wrong
flash_lock(); // lock back flash to protect it

View File

@ -15,13 +15,13 @@
/** library to communicate using I2C as master (code)
* @file i2c_master.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017
* @date 2017-2018
* @note peripherals used: I2C @ref i2c_master_i2c, timer @ref i2c_master_timer
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdio.h> // standard I/O facilities
//#include <stdio.h> // standard I/O facilities
#include <stdlib.h> // general utilities
/* STM32 (including CM3) libraries */
@ -30,13 +30,14 @@
#include <libopencm3/stm32/i2c.h> // I2C library
#include <libopencm3/stm32/timer.h> // timer utilities
/* own libraries */
#include "global.h" // global utilities
#include "i2c_master.h" // I2C header and definitions
/** @defgroup i2c_master_i2c I2C peripheral used to communicate
* @{
*/
#define I2C_MASTER_I2C 2 /**< I2C peripheral */
#define I2C_MASTER_I2C 1 /**< I2C peripheral */
/** @} */
/** @defgroup i2c_master_timer timer peripheral used for timeouts
@ -46,7 +47,6 @@
#define I2C_MASTER_TIMEOUT 4 /**< timeout factor (compared to expected time) */
/** @} */
void i2c_master_setup(bool fast)
{
// configure I2C peripheral
@ -94,89 +94,72 @@ void i2c_master_setup(bool fast)
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
}
bool i2c_master_read(uint8_t slave, const uint8_t* address, size_t address_size, uint8_t* data, size_t data_size)
bool i2c_master_start(void)
{
// sanity check
if (address==NULL || address_size==0 || data==NULL || data_size==0) { // input data is erroneous
return false;
}
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY) { // I2C device is busy
return false;
}
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) { // I2C device is already in master mode
return false;
}
bool to_return = false; // return if read succeeded
// send start condition
// send (re-)start condition
i2c_send_start(I2C(I2C_MASTER_I2C)); // send start condition to start transaction
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
timer_set_counter(TIM(I2C_MASTER_TIMER), 0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_SB) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until start condition is transmitted
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
return false;
}
if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL)) { // verify if in master mode
goto error;
return false;
}
return true;
}
bool i2c_master_select_slave(uint8_t slave, bool write)
{
if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY)) { // I2C device is not busy (start condition has not been sent)
if (!i2c_master_start()) { // send start condition
return false; // could not send start condition
}
}
if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL)) { // I2C device is already not master mode
return false;
}
// select slave
i2c_send_7bit_address(I2C(I2C_MASTER_I2C), slave, I2C_WRITE); // select slave
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
i2c_send_7bit_address(I2C(I2C_MASTER_I2C), slave, write ? I2C_WRITE : I2C_READ); // select slave, with read/write flag
timer_set_counter(TIM(I2C_MASTER_TIMER), 0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_ADDR) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until address is transmitted
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred (no ACK received)
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
return false;
}
if (!((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_TRA))) { // verify we are in transmit mode (and read SR2 to clear ADDR)
goto error;
}
// send address
for (size_t i=0; i<address_size; i++) {
i2c_send_data(I2C(I2C_MASTER_I2C), address[i]); // send memory address we want to read
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_TxE) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until byte has been transmitted
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
if (write) {
if (!((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_TRA))) { // verify we are in transmit mode (and read SR2 to clear ADDR)
return false;
}
} else {
if ((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_TRA)) { // verify we are in read mode (and read SR2 to clear ADDR)
return false;
}
}
// switch to read mode
i2c_send_start(I2C(I2C_MASTER_I2C)); // send restart condition to switch from write to read mode
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_SB) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until start condition is transmitted
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
}
return true;
}
i2c_send_7bit_address(I2C(I2C_MASTER_I2C), slave, I2C_READ); // select slave
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_ADDR) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until address is transmitted
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
}
if ((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_TRA)) { // verify we are in read mode (and read SR2 to clear ADDR)
goto error;
bool i2c_master_read(uint8_t* data, size_t data_size)
{
// sanity check
if (data==NULL || data_size==0) { // no data to read
return true;
}
if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY)) { // I2C device is not busy (start condition has not been sent)
return false; // address has probably also not been sent
}
if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL)) { // I2C device not master mode
return false;
}
// read data
@ -187,96 +170,34 @@ bool i2c_master_read(uint8_t slave, const uint8_t* address, size_t address_size,
} else {
i2c_enable_ack(I2C(I2C_MASTER_I2C)); // ACK received byte to continue slave transmission
}
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
timer_set_counter(TIM(I2C_MASTER_TIMER), 0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_RxNE) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until byte has been received
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
return false;
}
data[i] = i2c_get_data(I2C(I2C_MASTER_I2C)); // read received byte
}
to_return = true;
error:
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY) { // release bus if busy
// i2c_send_stop(I2C(I2C_MASTER_I2C)); // send stop to release bus
}
i2c_send_stop(I2C(I2C_MASTER_I2C)); // send stop to release bus
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while ((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until bus released (non master mode)
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
}
return to_return;
return true;
}
bool i2c_master_write(uint8_t slave, const uint8_t* address, size_t address_size, const uint8_t* data, size_t data_size)
bool i2c_master_write(const uint8_t* data, size_t data_size)
{
// sanity check
if (address==NULL || address_size==0 || data==NULL || data_size==0) { // input data is erroneous
return false;
if (data==NULL || data_size==0) { // no data to write
return true;
}
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY) { // I2C device is busy
return false;
if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY)) { // I2C device is not busy (start condition has not been sent)
return false; // address has probably also not been sent
}
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) { // I2C device is already in master mode
if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL)) { // I2C device is not master mode
return false;
}
bool to_return = false; // return if read succeeded
// send start condition
i2c_send_start(I2C(I2C_MASTER_I2C)); // send start condition to start transaction
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_SB) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until start condition is transmitted
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
}
if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL)) { // verify if in master mode
goto error;
}
// select slave
i2c_send_7bit_address(I2C(I2C_MASTER_I2C), slave, I2C_WRITE); // select slave
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_ADDR) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until address is transmitted
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
}
if (!((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_TRA))) { // verify we are in transmit mode (and read SR2 to clear ADDR)
goto error;
}
// send address
for (size_t i=0; i<address_size; i++) {
i2c_send_data(I2C(I2C_MASTER_I2C), address[i]); // send memory address we want to read
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_TxE) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until byte has been transmitted
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
}
}
// write data
for (size_t i=0; i<data_size; i++) { // write bytes
i2c_send_data(I2C(I2C_MASTER_I2C), data[i]); // send byte to be written in memory
@ -285,24 +206,186 @@ bool i2c_master_write(uint8_t slave, const uint8_t* address, size_t address_size
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while (!(I2C_SR1(I2C(I2C_MASTER_I2C)) & I2C_SR1_TxE) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until byte has been transmitted
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred (no ACK received)
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
goto error;
return false;
}
}
to_return = true;
error:
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY) { // release bus if busy
i2c_send_stop(I2C(I2C_MASTER_I2C)); // send stop to release bus
return true;
}
void i2c_master_stop(void)
{
// sanity check
if (!(I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY)) { // release is not busy
return; // bus has probably already been released
}
timer_set_counter(TIM(I2C_MASTER_TIMER),0); // restart timer
// send stop condition
i2c_send_stop(I2C(I2C_MASTER_I2C)); // send stop to release bus
timer_set_counter(TIM(I2C_MASTER_TIMER), 0); // restart timer
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
timer_enable_counter(TIM(I2C_MASTER_TIMER)); // enable timer for timeouts
while ((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until bus released (non master mode)
while ((I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) && !timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)); // wait until bus released (non master mode)
timer_disable_counter(TIM(I2C_MASTER_TIMER)); // disable timer for timeouts
if (timer_get_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF)) { // timeout occurred
timer_clear_flag(TIM(I2C_MASTER_TIMER), TIM_SR_UIF); // clear flag
}
return to_return;
}
bool i2c_master_slave_read(uint8_t slave, uint8_t* data, size_t data_size)
{
// sanity check
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY) { // I2C device is busy
return false;
}
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) { // I2C device is already in master mode
return false;
}
bool success = false; // return if read succeeded
// send start condition
if (!i2c_master_start()) {
goto error;
}
// select slave to write
if (!i2c_master_select_slave(slave, true)) {
goto error;
}
// read data
if (NULL!=data && data_size>0) {
// read data
if (!i2c_master_read(data, data_size)) {
goto error;
}
}
success = true;
error:
i2c_master_stop(); // sent stop condition
return success;
}
bool i2c_master_slave_write(uint8_t slave, const uint8_t* data, size_t data_size)
{
// sanity check
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY) { // I2C device is busy
return false;
}
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) { // I2C device is already in master mode
return false;
}
bool success = false; // return if read succeeded
// send start condition
if (!i2c_master_start()) {
goto error;
}
// select slave to write
if (!i2c_master_select_slave(slave, true)) {
goto error;
}
// write data
if (NULL!=data && data_size>0) {
if (!i2c_master_write(data, data_size)) {
goto error;
}
}
success = true;
error:
i2c_master_stop(); // sent stop condition
return success;
}
bool i2c_master_address_read(uint8_t slave, const uint8_t* address, size_t address_size, uint8_t* data, size_t data_size)
{
// sanity check
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY) { // I2C device is busy
return false;
}
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) { // I2C device is already in master mode
return false;
}
bool success = false; // return if read succeeded
// write address
if (NULL!=address && address_size>0) {
// send start condition
if (!i2c_master_start()) {
goto error;
}
// select slave to write
if (!i2c_master_select_slave(slave, true)) {
goto error;
}
// send address
if (!i2c_master_write(address, address_size)) {
goto error;
}
}
// read data
if (NULL!=data && data_size>0) {
// send re-start condition
if (!i2c_master_start()) {
goto error;
}
// select slave to read
if (!i2c_master_select_slave(slave, false)) {
goto error;
}
// read data
if (!i2c_master_read(data, data_size)) {
goto error;
}
}
success = true;
error:
i2c_master_stop(); // sent stop condition
return success;
}
bool i2c_master_address_write(uint8_t slave, const uint8_t* address, size_t address_size, const uint8_t* data, size_t data_size)
{
// sanity check
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_BUSY) { // I2C device is busy
return false;
}
if (I2C_SR2(I2C(I2C_MASTER_I2C)) & I2C_SR2_MSL) { // I2C device is already in master mode
return false;
}
bool success = false; // return if read succeeded
// send start condition
if (!i2c_master_start()) {
goto error;
}
// select slave to write
if (!i2c_master_select_slave(slave, true)) {
goto error;
}
// write address
if (NULL!=address && address_size>0) {
// send address
if (!i2c_master_write(address, address_size)) {
goto error;
}
}
// write data
if (NULL!=data && data_size>0) {
if (!i2c_master_write(data, data_size)) {
goto error;
}
}
success = true;
error:
i2c_master_stop(); // sent stop condition
return success;
}

View File

@ -15,8 +15,9 @@
/** library to communicate using I2C as master (API)
* @file i2c_master.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017
* @date 2017-2018
* @note peripherals used: I2C @ref i2c_master_i2c, timer @ref i2c_master_timer
* @warning only 7-byte I2C slave addresses are supported
*/
#pragma once
@ -24,7 +25,46 @@
* @param[in] fast use standard (100 kHz) or fast (400 kHz) mode
*/
void i2c_master_setup(bool fast);
/** read from I2C slave
/** send start condition
* @return if start condition was sent successfully (true) or error occurred (false)
*/
bool i2c_master_start(void);
/** select slave device
* @warning a start condition should be sent before this operation
* @param[in] slave 7-bit I2C address of slave device to select
* @param[in] write this transaction will be followed by a read (false) or write (true) operation
* @return if slave was selected successfully (true) or error occurred (false)
*/
bool i2c_master_select_slave(uint8_t slave, bool write);
/** read data
* @warning the slave device must be selected before this operation
* @param[out] data array to store bytes read
* @param[in] data_size number of bytes to read
*/
bool i2c_master_read(uint8_t* data, size_t data_size);
/** write data
* @warning the slave device must be selected before this operation
* @param[in] data array of byte to write to slave
* @param[in] data_size number of bytes to write
*/
bool i2c_master_write(const uint8_t* data, size_t data_size);
/** sent stop condition */
void i2c_master_stop(void);
/** read from date from an I2C slave
* @param[in] slave 7-bit I2C salve device address to read from
* @param[out] data array to store bytes read
* @param[in] data_size number of bytes to read
* @return if read succeeded
*/
bool i2c_master_slave_read(uint8_t slave, uint8_t* data, size_t data_size);
/** write data to an I2C slave
* @param[in] slave 7-bit I2C salve device address to write to
* @param[in] data array of byte to write to slave
* @param[in] data_size number of bytes to write
* @return if write succeeded
*/
bool i2c_master_slave_write(uint8_t slave, const uint8_t* data, size_t data_size);
/** read data at specific address from an I2C memory slave
* @param[in] slave 7-bit I2C salve device address to read from
* @param[in] address memory address of slave to read from
* @param[in] address_size address size in bytes
@ -32,8 +72,8 @@ void i2c_master_setup(bool fast);
* @param[in] data_size number of bytes to read
* @return if read succeeded
*/
bool i2c_master_read(uint8_t slave, const uint8_t* address, size_t address_size, uint8_t* data, size_t data_size);
/** write to I2C slave
bool i2c_master_address_read(uint8_t slave, const uint8_t* address, size_t address_size, uint8_t* data, size_t data_size);
/** write data at specific address on an I2C memory slave
* @param[in] slave 7-bit I2C salve device address to write to
* @param[in] address memory address of slave to write to
* @param[in] address_size address size in bytes
@ -41,5 +81,4 @@ bool i2c_master_read(uint8_t slave, const uint8_t* address, size_t address_size,
* @param[in] data_size number of bytes to write
* @return if write succeeded
*/
bool i2c_master_write(uint8_t slave, const uint8_t* address, size_t address_size, const uint8_t* data, size_t data_size);
bool i2c_master_address_write(uint8_t slave, const uint8_t* address, size_t address_size, const uint8_t* data, size_t data_size);

View File

@ -107,6 +107,8 @@ void menu_print_commands(const struct menu_command_t* command_list, size_t comma
printf("%s", command.name);
if (MENU_ARGUMENT_NONE!=command.argument && command.argument_description) {
printf(" %s", command.argument_description);
} else {
printf("\t");
}
if (command.command_description) {
printf("\t%s", command.command_description);

View File

@ -33,7 +33,7 @@ char* terminal_prefix = NULL;
void (*terminal_process)(char* line) = NULL;
/** buffer to store user input and keep history */
static char terminal_buffer[16] = {0};
static char terminal_buffer[1024] = {0};
/** how much of the buffer is user */
static uint16_t terminal_end = 0;
/** current position in the buffer */

View File

@ -27,6 +27,7 @@
#include <libopencm3/cm3/scb.h> // reset utilities
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/desig.h> // flash size definition
#include <libopencm3/usb/usbd.h> // USB library
#include <libopencm3/usb/dfu.h> // USB DFU library
@ -223,7 +224,11 @@ static int usb_dfu_control_request(usbd_device *usbd_dev, struct usb_setup_data
// we can only write half words
usb_dfu_status = DFU_STATUS_ERR_PROG;
usb_dfu_state = STATE_DFU_ERROR;
#if defined(__application_end)
} else if (flash_pointer+*len>=(uint32_t)&__application_end) {
#else
} else if (flash_pointer+*len>=(uint32_t)(FLASH_BASE+DESIG_FLASH_SIZE*1024)) {
#endif
// application data is too large
usb_dfu_status = DFU_STATUS_ERR_ADDRESS;
usb_dfu_state = STATE_DFU_ERROR;