From 8a3fedbcb8fc58dae8b43db3cae39688ec0332ef Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Wed, 25 Jan 2017 20:51:35 +0100 Subject: o i2c test o Misc other stuff. --- apps/i2c1/CMakeLists.txt | 29 ++++ apps/i2c1/i2c1.cpp | 355 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 384 insertions(+) create mode 100644 apps/i2c1/CMakeLists.txt create mode 100644 apps/i2c1/i2c1.cpp (limited to 'apps') diff --git a/apps/i2c1/CMakeLists.txt b/apps/i2c1/CMakeLists.txt new file mode 100644 index 0000000..67139f8 --- /dev/null +++ b/apps/i2c1/CMakeLists.txt @@ -0,0 +1,29 @@ +add_executable(i2c1.elf i2c1.cpp + ${PLAYGROUND_DIR}/src/init_low.s ${PLAYGROUND_DIR}/src/init_high.cpp ${PLAYGROUND_DIR}/include/init_high.h + ${PLAYGROUND_DIR}/include/playground.h + ${PLAYGROUND_DIR}/src/debug.cpp ${PLAYGROUND_DIR}/include/debug.h + ${PLAYGROUND_DIR}/include/stm32f10x_conf.h + # http://www.sparetimelabs.com/tinyprintf/tinyprintf.php + ${TINYPRINTF_DIR}/tinyprintf.c ${TINYPRINTF_DIR}/tinyprintf.h + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/CoreSupport/core_cm3.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_rcc.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_i2c.c + ) + +target_include_directories(i2c1.elf PUBLIC + ${PLAYGROUND_DIR}/include + ${TINYPRINTF_DIR} + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/CoreSupport + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/inc) +target_compile_definitions(i2c1.elf PUBLIC ${STM32F10X_STDPERIPH_DEFINES} USE_FULL_ASSERT) + +set_target_properties(i2c1.elf PROPERTIES O_LEVEL 3) + +#set_source_files_properties(i2c1.cpp PROPERTIES O_LEVEL s) +set_property(SOURCE i2c1.cpp APPEND_STRING PROPERTY COMPILE_FLAGS "-O0") + +set_target_properties(i2c1.elf PROPERTIES LINK_FLAGS "-nostartfiles -T${CMAKE_SOURCE_DIR}/cmake/stm32.ld") +add_extra_commands(i2c1.elf) diff --git a/apps/i2c1/i2c1.cpp b/apps/i2c1/i2c1.cpp new file mode 100644 index 0000000..b6d0a27 --- /dev/null +++ b/apps/i2c1/i2c1.cpp @@ -0,0 +1,355 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "debug.h" +#include "tinyprintf.h" + +extern "C" void halt(); + +extern "C" +__attribute__((naked)) +void HardFault_Handler_C(uint32_t *hardfault_args) { + dbg_printf("r0 = 0x%08lx (%lu)\n", hardfault_args[0], hardfault_args[0]); + dbg_printf("r1 = 0x%08lx (%lu)\n", hardfault_args[1], hardfault_args[1]); + dbg_printf("r2 = 0x%08lx (%lu)\n", hardfault_args[2], hardfault_args[2]); + dbg_printf("r3 = 0x%08lx (%lu)\n", hardfault_args[3], hardfault_args[3]); + dbg_printf("r12 = 0x%08lx (%lu)\n", hardfault_args[4], hardfault_args[4]); + dbg_printf("lr = 0x%08lx (%lu)\n", hardfault_args[5], hardfault_args[5]); + dbg_printf("pc = 0x%08lx (%lu)\n", hardfault_args[6], hardfault_args[6]); + dbg_printf("psr = 0x%08lx (%lu)\n", hardfault_args[7], hardfault_args[7]); + dbg_printf("\n"); + + halt(); +} + +size_t strlen(const char *s) { + size_t size = 0; + while (*s++ != '\0') size++; + return size; +} + +bool run = true; + +volatile USART_TypeDef *usart1 = (volatile USART_TypeDef *) USART1_BASE; +volatile I2C_TypeDef *i2c1 = (volatile I2C_TypeDef *) I2C1_BASE; +volatile I2C_TypeDef *i2c2 = (volatile I2C_TypeDef *) I2C2_BASE; + +extern "C" +void assert_failed(uint8_t *file, uint32_t line) { + dbg_printf("assert_failed: %s: %" PRIu32 "\n", file, line); +} + +int start_wait_count; + +void i2c_hard_reset(I2C_TypeDef *I2Cx, I2C_InitTypeDef &i2c_init) { + dbg_printf("start_wait_count=%d\n", start_wait_count); + I2C_DeInit(I2Cx); + I2C_Cmd(I2Cx, DISABLE); + I2C_Init(I2Cx, &i2c_init); + + GPIO_InitTypeDef init; + GPIO_StructInit(&init); + init.GPIO_Pin = GPIO_Pin_10; + init.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOB, &init); + + GPIO_WriteBit(GPIOB, GPIO_Pin_10, Bit_RESET); + for (int i = 0; i < 8; i++) { + GPIO_WriteBit(GPIOB, GPIO_Pin_10, Bit_SET); + GPIO_WriteBit(GPIOB, GPIO_Pin_10, Bit_RESET); + } + + init.GPIO_Pin = GPIO_Pin_10; + init.GPIO_Mode = GPIO_Mode_AF_OD; + GPIO_Init(GPIOB, &init); + + I2C_Cmd(I2Cx, ENABLE); + + I2C_SoftwareResetCmd(I2Cx, ENABLE); + for (int i = 0; i < 100; i++) { + __NOP(); + } + I2C_SoftwareResetCmd(I2Cx, DISABLE); +} + +static inline bool i2c_wait_for_flag(I2C_TypeDef *I2Cx, uint32_t flag, FlagStatus status, unsigned int timeout) { + do { + auto flagStatus = I2C_GetFlagStatus(I2Cx, flag); + if (flagStatus == status) { + return true; + } + } while (timeout-- > 0); + + return false; +} + +static inline bool i2c_wait_for_event(I2C_TypeDef *I2Cx, uint32_t expected, unsigned int timeout) { + uint32_t actual; + do { + actual = I2C_GetLastEvent(I2Cx); + if (actual == expected) { + return true; + } + } while (timeout-- > 0); + + dbg_printf("i2c_wait_for_event, expected=%08" PRIx32 ", actual=%08" PRIx32 "\n", expected, actual); + + return false; +} + +const unsigned int timeout = 1000 * 1000; + +bool i2c_write(I2C_TypeDef *port, uint8_t address, uint8_t *buf, uint8_t count, bool generate_stop) { + if (!i2c_wait_for_flag(port, I2C_FLAG_BUSY, RESET, timeout)) { + dbg_printf("Failed while waiting for I2C_FLAG_BUSY\n"); + return false; + } + + I2C_GenerateSTART(port, ENABLE); + + if (!i2c_wait_for_event(port, I2C_EVENT_MASTER_MODE_SELECT, timeout)) { + dbg_printf("Failed while waiting for I2C_EVENT_MASTER_MODE_SELECT\n"); + return false; + } + + I2C_Send7bitAddress(port, address, I2C_Direction_Transmitter); + + if (!i2c_wait_for_event(port, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED, timeout)) { + dbg_printf("Failed while waiting for I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED\n"); + return false; + } + + do { + I2C_SendData(port, *buf++); + + if (!i2c_wait_for_event(port, I2C_EVENT_MASTER_BYTE_TRANSMITTED, timeout)) { + dbg_printf("Failed while waiting for I2C_EVENT_MASTER_BYTE_TRANSMITTED\n"); + return false; + } + } while (--count); + + if (generate_stop) { + I2C_GenerateSTOP(port, ENABLE); + + while (I2C_GetFlagStatus(port, I2C_FLAG_STOPF)) { + __NOP(); + } + } + + return true; +} + +bool i2c_read(I2C_TypeDef *port, uint8_t address, uint8_t *buf, uint8_t count, bool generate_start) { + start_wait_count = 0; + int dbg_counter = 0; + (void) dbg_counter; + + if (generate_start) { + if (!i2c_wait_for_flag(port, I2C_FLAG_BUSY, RESET, timeout)) { + dbg_printf("Failed while waiting for I2C_FLAG_BUSY\n"); + return false; + } + + I2C_AcknowledgeConfig(port, ENABLE); +// dbg_printf("%2d SR2 SR1 = %08" PRIx32 "\n", dbg_counter, I2C_GetLastEvent(port)); + I2C_NACKPositionConfig(port, I2C_NACKPosition_Current); +// dbg_printf("%2d SR2 SR1 = %08" PRIx32 "\n", dbg_counter, I2C_GetLastEvent(port)); + + I2C_GenerateSTART(port, ENABLE); + +// dbg_printf("%2d SR2 SR1 = %08" PRIx32 "\n", dbg_counter, I2C_GetLastEvent(port)); + + /* I2C_EVENT_MASTER_MODE_SELECT = BUSY, MSL and SB flag */ + if (!i2c_wait_for_event(port, I2C_EVENT_MASTER_MODE_SELECT, timeout)) { + dbg_printf("Failed while waiting for I2C_EVENT_MASTER_MODE_SELECT\n"); + return false; + } + + I2C_Send7bitAddress(port, address, I2C_Direction_Receiver); + + // I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED == BUSY, MSL and ADDR + if (!i2c_wait_for_event(port, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED, timeout)) { + dbg_printf("Failed while waiting for I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED\n"); + return false; + } + } + + if (count == 1) { + I2C_AcknowledgeConfig(port, DISABLE); + + __disable_irq(); + (void) port->SR2; + I2C_GenerateSTOP(port, ENABLE); + __enable_irq(); + + while (!I2C_CheckEvent(port, I2C_EVENT_MASTER_BYTE_RECEIVED)) { + __NOP(); + } + + *buf = I2C_ReceiveData(port); + } else if (count == 2) { + I2C_NACKPositionConfig(port, I2C_NACKPosition_Next); + + __disable_irq(); + (void) port->SR2; + I2C_AcknowledgeConfig(port, DISABLE); + __enable_irq(); + + while (!I2C_CheckEvent(port, I2C_EVENT_MASTER_BYTE_RECEIVED)) { + __NOP(); + } + + __disable_irq(); + I2C_GenerateSTOP(port, ENABLE); + *buf++ = I2C_ReceiveData(port); + __enable_irq(); + *buf = I2C_ReceiveData(port); + } else { + do { + if (!i2c_wait_for_event(port, I2C_EVENT_MASTER_BYTE_RECEIVED, timeout)) { + dbg_printf("Failed while waiting for I2C_EVENT_MASTER_BYTE_RECEIVED, count=%d\n", count); + return false; + } + + *buf++ = I2C_ReceiveData(port); + } while (--count != 2); + + I2C_AcknowledgeConfig(port, DISABLE); + + __disable_irq(); + *buf++ = I2C_ReceiveData(port); + I2C_GenerateSTOP(port, ENABLE); + __enable_irq(); + + *buf++ = I2C_ReceiveData(port); + + if (!i2c_wait_for_event(port, I2C_EVENT_MASTER_BYTE_RECEIVED, timeout)) { + dbg_printf("Failed while waiting for I2C_EVENT_MASTER_BYTE_RECEIVED\n"); + return false; + } + + *buf = I2C_ReceiveData(port); + } + + while (I2C_GetFlagStatus(port, I2C_FLAG_STOPF)) { + __NOP(); + } + + return true; +} + +int main() { + SystemInit(); + + init_printf(nullptr, dbg_putc); + + dbg_printf("i2c1\n"); + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO + | RCC_APB2Periph_USART1 + | RCC_APB2Periph_GPIOA + | RCC_APB2Periph_GPIOB + | RCC_APB2Periph_GPIOC, + ENABLE); + + /* ***************************************** */ + + // Debug on port B + + RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, DISABLE); + + // Make Port B's pin #5 the debug output pin + GPIO_InitTypeDef init; + GPIO_StructInit(&init); + init.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; + init.GPIO_Mode = GPIO_Mode_Out_PP; + init.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_Init(GPIOB, &init); + + /* ***************************************** */ + + RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, + ENABLE); + + /* + * PB10 I2C2_SCL + * PB11 I2C2_SDA + */ + + RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2, DISABLE); + + GPIO_StructInit(&init); + init.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; + init.GPIO_Mode = GPIO_Mode_AF_OD; + GPIO_Init(GPIOB, &init); + + /* + i2c2->CR2 |= 36; // APB1 freq is 36 MHz + // 36 MHz = 27.78 ns, 400 kHz = 2500ns + // 2500 ns / 27.78 ns = 89.99 + i2c2->CCR |= I2C_CCR_FS | 90; + */ + + I2C_TypeDef *const i2c_port = I2C2; + I2C_DeInit(i2c_port); + I2C_InitTypeDef i2c_init; + I2C_StructInit(&i2c_init); + i2c_init.I2C_ClockSpeed = 100 * 1000; + i2c_init.I2C_Ack = I2C_Ack_Enable; + i2c_init.I2C_Mode = I2C_Mode_I2C; + I2C_Init(i2c_port, &i2c_init); + I2C_Cmd(i2c_port, ENABLE); + + const int DS3231_address = 0b11010000; // 0x68 + + run = true; + bool toggle = true; + bool success = true; + while (run) { + GPIO_WriteBit(GPIOB, GPIO_Pin_5, toggle ? Bit_SET : Bit_RESET); + GPIO_WriteBit(GPIOB, GPIO_Pin_6, toggle ? Bit_SET : Bit_RESET); + GPIO_WriteBit(GPIOB, GPIO_Pin_7, toggle ? Bit_SET : Bit_RESET); + toggle = !toggle; + + if (!success) { + dbg_printf("resetting...\n"); + i2c_hard_reset(i2c_port, i2c_init); + } + + uint8_t buf[12]; + for (size_t i = 0; i < SizeOfArray(buf); i++) { + buf[i] = 0; + } + + success = i2c_write(i2c_port, DS3231_address, buf, 1, false); + + if (!success) { + dbg_printf("i2c_write failed\n"); + continue; + } + + success = i2c_read(i2c_port, DS3231_address, buf, SizeOfArray(buf), false); + + if (success) { + dbg_printf( + "%3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n" +// "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x" /*" %02x %02x %02x %02x"*/ "\n" + "\n", +// buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], +// buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15], + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], + buf[9], buf[10], buf[11]/*, buf[12], buf[13], buf[14], buf[15]*/); + } + } + + return 0; +} + -- cgit v1.2.3