diff --git a/common/mode_config.h b/common/mode_config.h index 3787a1ff..03603c7f 100644 --- a/common/mode_config.h +++ b/common/mode_config.h @@ -50,12 +50,13 @@ typedef struct long dev_parity; /* For UART */ long dev_stop_bit; /* For UART */ - uint32_t : 25; // not used reserved for future use + uint32_t : 24; // not used reserved for future use uint32_t altAUX : 2; // 4 AUX tbd uint32_t periodicService : 1; uint32_t lsbEN : 1; uint32_t HiZ : 1; uint32_t int16 : 1; // 16 bits output? + uint32_t ack_pending : 1; // I2C Read Ack pending uint32_t wwr : 1; // write with read uint8_t buffer_tx[256]; diff --git a/drv/stm32cube/bsp.c b/drv/stm32cube/bsp.c index fd96ffc5..cf21be29 100644 --- a/drv/stm32cube/bsp.c +++ b/drv/stm32cube/bsp.c @@ -13,11 +13,36 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include "bsp.h" #include "stm32f405xx.h" #include "stm32f4xx_hal.h" static uint32_t uwTick = 0; +/* Internal Cycle Counter */ +#if !defined(IOREG32) || defined(__DOXYGEN__) + typedef volatile uint32_t IOREG32; +#endif + +#if !defined(CMx_DWT) || defined(__DOXYGEN__) + typedef struct + { + IOREG32 CTRL; + IOREG32 CYCCNT; + } CMx_DWT; + #define DWTBase ((CMx_DWT *)0xE0001000U) + #define DWT_CTRL (DWTBase->CTRL) + #define DWT_CTRL_CYCCNTENA (0x1U << 0) +#endif + +#if !defined(clear_cyclecounter) || defined(__DOXYGEN__) + #define clear_cyclecounter() ( DWTBase->CYCCNT = 0 ) +#endif + +#if !defined(get_cyclecounter) || defined(__DOXYGEN__) + #define get_cyclecounter() ( DWTBase->CYCCNT ) +#endif + void HAL_IncTick(void) { uwTick++; @@ -28,3 +53,49 @@ uint32_t HAL_GetTick(void) HAL_IncTick(); return uwTick; } + +uint32_t HAL_RCC_GetPCLK1Freq(void) +{ + return 42000000; +} + +uint32_t HAL_RCC_GetPCLK2Freq(void) +{ + return 84000000; +} + +bool delay_is_expired(bool start, uint32_t wait_nb_cycles) +{ + if(start == TRUE) + { + /* Disable IRQ globally */ + __asm__("cpsid i"); + clear_cyclecounter(); + }else + { + /* Minus 10 cycles to take into account code overhead */ + if(get_cyclecounter() >= (wait_nb_cycles-10)) + { + /* Enable IRQ globally */ + __asm__("cpsie i"); + return TRUE; + } + } + return FALSE; +} + +void wait_delay(uint32_t wait_nb_cycles) +{ + /* Disable IRQ globally */ + __asm__("cpsid i"); + + clear_cyclecounter(); + /* Minus 10 cycles to take into account code overhead */ + while(get_cyclecounter() < (wait_nb_cycles-10)) + { + __asm__("nop"); + } + + /* Enable IRQ globally */ + __asm__("cpsie i"); +} diff --git a/drv/stm32cube/bsp.h b/drv/stm32cube/bsp.h index 9eaf987b..0c9225d9 100644 --- a/drv/stm32cube/bsp.h +++ b/drv/stm32cube/bsp.h @@ -16,6 +16,25 @@ #ifndef _BSP_H_ #define _BSP_H_ +#include + +/* UBTN PA0 Configured as Input */ +#undef USER_BUTTON +#define USER_BUTTON (palReadPad(GPIOA, 0)) + +/* Macro for fast read, set & clear GPIO pin */ +#define gpio_get_pin(GPIOx, GPIO_Pin) (GPIOx->IDR & GPIO_Pin) +#define gpio_set_pin(GPIOx, GPIO_Pin) (GPIOx->BSRRH = GPIO_Pin) +#define gpio_clr_pin(GPIOx, GPIO_Pin) (GPIOx->BSRRL = GPIO_Pin) + +#if !defined(bool) || defined(__DOXYGEN__) +typedef enum +{ + FALSE = 0, + TRUE = (!FALSE) +} bool; +#endif + /* Same definition as HAL_StatusTypeDef, used as abstraction layer to avoid dependencies with stm32f4xx_hal_def.h */ @@ -27,4 +46,10 @@ typedef enum BSP_TIMEOUT = 0x03 } bsp_status_t; +/* wait_nb_cycles shall be min 10 */ +bool delay_is_expired(bool start, uint32_t wait_nb_cycles); + +/* wait_nb_cycles shall be min 10 */ +void wait_delay(uint32_t wait_nb_cycles); + #endif /* _BSP_H_ */ diff --git a/drv/stm32cube/bsp_i2c.c b/drv/stm32cube/bsp_i2c.c new file mode 100644 index 00000000..6ee0d905 --- /dev/null +++ b/drv/stm32cube/bsp_i2c.c @@ -0,0 +1,277 @@ +/* + HydraBus/HydraNFC - Copyright (C) 2014 Benjamin VERNOUX + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +#include "bsp_i2c.h" +#include "bsp_i2c_conf.h" +#include "stm32f405xx.h" +#include "stm32f4xx_hal.h" + +#define BSP_I2C_DELAY_HC_50KHZ (1680) /* 50KHz*2 (Half Clock) in number of cycles @168MHz */ +#define BSP_I2C_DELAY_HC_100KHZ (840) /* 100KHz*2 (Half Clock) in number of cycles @168MHz */ +#define BSP_I2C_DELAY_HC_400KHZ (210) /* 400KHz*2 (Half Clock) in number of cycles @168MHz */ +/* Corresponds to Delay of half clock */ +#define I2C_SPEED_MAX (3) +const int i2c_speed[I2C_SPEED_MAX] = { BSP_I2C_DELAY_HC_50KHZ, BSP_I2C_DELAY_HC_100KHZ, BSP_I2C_DELAY_HC_400KHZ }; +int i2c_speed_delay; +bool i2c_started; + +/* Set SCL LOW = 0/GND (0/GND => Set pin = logic reversed in open drain) */ +#define set_scl_low() (gpio_set_pin(BSP_I2C1_SCL_SDA_GPIO_PORT, BSP_I2C1_SCL_PIN)) +/* Set SCL HIGH / Floating Input (HIGH => clr pin = logic reversed in open drain) */ +#define set_scl_float() (gpio_clr_pin(BSP_I2C1_SCL_SDA_GPIO_PORT, BSP_I2C1_SCL_PIN)) + +/* Set SDA LOW = 0/GND (0/GND => Set pin = logic reversed in open drain) */ +#define set_sda_low() (gpio_set_pin(BSP_I2C1_SCL_SDA_GPIO_PORT, BSP_I2C1_SDA_PIN)) +/* Set SDA HIGH / Floating Input (HIGH => clr pin = logic reversed in open drain) */ +#define set_sda_float() (gpio_clr_pin(BSP_I2C1_SCL_SDA_GPIO_PORT, BSP_I2C1_SDA_PIN)) + +/* Get SDA pin state 0 or 1 */ +#define get_sda() (gpio_get_pin(BSP_I2C1_SCL_SDA_GPIO_PORT, BSP_I2C1_SDA_PIN)) + +/* wait I2C half clock delay */ +#define i2c_sw_delay() (wait_delay(i2c_speed_delay)) + +/** + * @brief I2C SW Bit Banging GPIO HW DeInit. + * @param dev_num: I2C dev num + * @retval None + */ +static void i2c_gpio_hw_deinit(bsp_dev_i2c_t dev_num) +{ + (void)dev_num; + + /* Disable peripherals and GPIO Clocks */ + HAL_GPIO_DeInit(BSP_I2C1_SCL_SDA_GPIO_PORT, (BSP_I2C1_SCL_PIN | BSP_I2C1_SDA_PIN)); +} + +/** + * @brief I2C SW Bit Banging GPIO HW Init. + * @param dev_num: I2C dev num + * @retval None + */ +static void i2c_gpio_hw_init(bsp_dev_i2c_t dev_num) +{ + (void)dev_num; + GPIO_InitTypeDef gpio_init; + + /* BSP_I2C1 SCL and SDA pins configuration ---------------------------*/ + gpio_init.Pin = BSP_I2C1_SCL_PIN | BSP_I2C1_SDA_PIN; + gpio_init.Mode = GPIO_MODE_OUTPUT_OD; /* output open drain */ + gpio_init.Speed = GPIO_SPEED_FAST; + gpio_init.Pull = GPIO_PULLUP; //GPIO_NOPULL; + gpio_init.Alternate = 0; /* Not used */ + HAL_GPIO_Init(BSP_I2C1_SCL_SDA_GPIO_PORT, &gpio_init); +} + +/** + * @brief Init I2C device. + * @param dev_num: I2C dev num. + * @param mode_conf: Mode config proto. + * @retval status: status of the init. + */ +bsp_status_t bsp_i2c_init(bsp_dev_i2c_t dev_num, mode_config_proto_t* mode_conf) +{ + bsp_i2c_deinit(dev_num); + + /* I2C peripheral configuration */ + if(mode_conf->dev_speed < I2C_SPEED_MAX) + i2c_speed_delay = i2c_speed[mode_conf->dev_speed]; + else + return BSP_ERROR; + + /* Init the I2C */ + i2c_gpio_hw_init(dev_num); + + set_sda_float(); + set_scl_float(); + + i2c_started = FALSE; + return BSP_OK; +} + +/** + * @brief De-initialize the I2C comunication bus + * @param dev_num: I2C dev num. + * @retval status: status of the deinit. + */ +bsp_status_t bsp_i2c_deinit(bsp_dev_i2c_t dev_num) +{ + /* DeInit the low level hardware: GPIO, CLOCK, NVIC... */ + i2c_gpio_hw_deinit(dev_num); + + return BSP_OK; +} + +/** + * @brief Sends START BIT in blocking mode and set the status. + * @param dev_num: I2C dev num. + * @retval status of the transfer. + */ +bsp_status_t bsp_i2c_start(bsp_dev_i2c_t dev_num) +{ + (void)dev_num; + + if(i2c_started == TRUE) + { + /* Re-Start condition */ + set_sda_float(); + i2c_sw_delay(); + + set_scl_float(); + i2c_sw_delay(); + } + + /* Generate START */ + /* SDA & SCL are assumed to be floating = HIGH */ + set_sda_low(); + i2c_sw_delay(); + + set_scl_low(); + + i2c_started = TRUE; + return BSP_OK; +} + +/** + * @brief Sends STOP BIT in blocking mode and set the status. + * @param dev_num: I2C dev num. + * @retval status of the transfer. + */ +bsp_status_t bsp_i2c_stop(bsp_dev_i2c_t dev_num) +{ + (void)dev_num; + + /* Generate STOP condition */ + set_sda_low(); + i2c_sw_delay(); + + set_scl_float(); + i2c_sw_delay(); + + set_sda_float(); + i2c_sw_delay(); + + i2c_started = FALSE; + return BSP_OK; +} + +/** + * @brief Sends a Byte in blocking mode and set the status. + * @param dev_num: I2C dev num. + * @param tx_data: data to send. + * @param tx_ack_flag: TRUE means ACK, FALSE means NACK. + * @retval status of the transfer. + */ +bsp_status_t bsp_i2c_master_write_u8(bsp_dev_i2c_t dev_num, uint8_t tx_data, bool* tx_ack_flag) +{ + (void)dev_num; + int i; + unsigned char ack_val; + + /* Write 8 bits */ + for(i = 0; i < 8; i++) + { + if(tx_data & 0x80) + set_sda_float(); + else + set_sda_low(); + + i2c_sw_delay(); + + set_scl_float(); + i2c_sw_delay(); + + set_scl_low(); + tx_data <<= 1; + } + + /* Read 1 bit ACK or NACK */ + set_sda_float(); + i2c_sw_delay(); + + set_scl_float(); + i2c_sw_delay(); + + ack_val = get_sda(); + + set_scl_low(); + i2c_sw_delay(); + + if(ack_val == 0) + *tx_ack_flag = TRUE; + else + *tx_ack_flag = FALSE; + + return BSP_OK; +} + +/** + * @brief Write ACK or NACK at end of Read. + * @param dev_num: I2C dev num. + * @retval None + */ +void bsp_i2c_read_ack(bsp_dev_i2c_t dev_num, bool enable_ack) +{ + (void)dev_num; + + /* Write 1 bit ACK or NACK */ + if(enable_ack == TRUE) + set_sda_low(); /* ACK */ + else + set_sda_float(); /* NACK */ + + i2c_sw_delay(); + + set_scl_float(); + i2c_sw_delay(); + + set_scl_low(); +} + +/** + * @brief Read a Byte in blocking mode and set the status. + * @param dev_num: I2C dev num. + * @param rx_data: The received byte. + * @retval status of the transfer. + */ +bsp_status_t bsp_i2c_master_read_u8(bsp_dev_i2c_t dev_num, uint8_t* rx_data) +{ + (void)dev_num; + unsigned char data; + int i; + + /* Read 8 bits */ + data = 0; + for(i = 0; i < 8; i++) + { + set_sda_float(); + i2c_sw_delay(); + + set_scl_float(); + i2c_sw_delay(); + + data <<= 1; + if(get_sda()) + data |= 1; + + set_scl_low(); + i2c_sw_delay(); + } + *rx_data = data; + + /* Do not Send ACK / NACK because sent by bsp_i2c_read_ack() */ + + return BSP_OK; +} diff --git a/drv/stm32cube/bsp_i2c.h b/drv/stm32cube/bsp_i2c.h new file mode 100644 index 00000000..9b58c970 --- /dev/null +++ b/drv/stm32cube/bsp_i2c.h @@ -0,0 +1,37 @@ +/* + HydraBus/HydraNFC - Copyright (C) 2014 Benjamin VERNOUX + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +#ifndef _BSP_I2C_H_ +#define _BSP_I2C_H_ + +#include "bsp.h" +#include "mode_config.h" + +typedef enum +{ + BSP_DEV_I2C1 = 0, +} bsp_dev_i2c_t; + +bsp_status_t bsp_i2c_init(bsp_dev_i2c_t dev_num, mode_config_proto_t* mode_conf); +bsp_status_t bsp_i2c_deinit(bsp_dev_i2c_t dev_num); + +bsp_status_t bsp_i2c_start(bsp_dev_i2c_t dev_num); +bsp_status_t bsp_i2c_stop(bsp_dev_i2c_t dev_num); + +bsp_status_t bsp_i2c_master_write_u8(bsp_dev_i2c_t dev_num, uint8_t tx_data, bool* tx_ack_flag); +bsp_status_t bsp_i2c_master_read_u8(bsp_dev_i2c_t dev_num, uint8_t* rx_data); +void bsp_i2c_read_ack(bsp_dev_i2c_t dev_num, bool enable_ack); + +#endif /* _BSP_I2C_H_ */ diff --git a/drv/stm32cube/bsp_i2c_conf.h b/drv/stm32cube/bsp_i2c_conf.h new file mode 100644 index 00000000..64ea9612 --- /dev/null +++ b/drv/stm32cube/bsp_i2c_conf.h @@ -0,0 +1,25 @@ +/* + HydraBus/HydraNFC - Copyright (C) 2014 Benjamin VERNOUX + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef _BSP_I2C_CONF_H_ +#define _BSP_I2C_CONF_H_ + +/* I2C peripheral configuration */ +#define BSP_I2C1_SCL_SDA_GPIO_PORT GPIOB +#define BSP_I2C1_SCL_PIN GPIO_PIN_6 +#define BSP_I2C1_SDA_PIN GPIO_PIN_7 + +#endif /* _BSP_I2C_CONF_H_ */ diff --git a/drv/stm32cube/bsp_spi.c b/drv/stm32cube/bsp_spi.c index b17ef892..ea7ad022 100644 --- a/drv/stm32cube/bsp_spi.c +++ b/drv/stm32cube/bsp_spi.c @@ -13,10 +13,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include "stm32f405xx.h" -#include "stm32f4xx_hal.h" #include "bsp_spi.h" #include "bsp_spi_conf.h" +#include "stm32f405xx.h" +#include "stm32f4xx_hal.h" /* Warning in order to use this driver all GPIOs peripherals shall be enabled. @@ -145,7 +145,7 @@ static void spi_error(bsp_dev_spi_t dev_num) { if(bsp_spi_deinit(dev_num) == BSP_OK) { - /* Re-Initiaize the SPI comunication bus */ + /* Re-Initialize the SPI comunication bus */ bsp_spi_init(dev_num, spi_mode_conf[dev_num]); } } diff --git a/drv/stm32cube/bsp_uart.c b/drv/stm32cube/bsp_uart.c index 29884d46..ceed09f2 100644 --- a/drv/stm32cube/bsp_uart.c +++ b/drv/stm32cube/bsp_uart.c @@ -13,10 +13,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include "stm32f405xx.h" -#include "stm32f4xx_hal.h" #include "bsp_uart.h" #include "bsp_uart_conf.h" +#include "stm32f405xx.h" +#include "stm32f4xx_hal.h" /* Warning in order to use this driver all GPIOs peripherals shall be enabled. @@ -28,16 +28,6 @@ Warning in order to use this driver all GPIOs peripherals shall be enabled. static UART_HandleTypeDef uart_handle[NB_UART]; static mode_config_proto_t* uart_mode_conf[NB_UART]; -uint32_t HAL_RCC_GetPCLK1Freq(void) -{ - return 42000000; -} - -uint32_t HAL_RCC_GetPCLK2Freq(void) -{ - return 84000000; -} - const uint32_t dev_param_speed[] = { /* 0 */ 300, @@ -160,7 +150,7 @@ static void uart_error(bsp_dev_uart_t dev_num) { if(bsp_uart_deinit(dev_num) == BSP_OK) { - /* Re-Initiaize the UART comunication bus */ + /* Re-Initialize the UART comunication bus */ bsp_uart_init(dev_num, uart_mode_conf[dev_num]); } } diff --git a/drv/stm32cube/bsp_uart_conf.h b/drv/stm32cube/bsp_uart_conf.h index a7921581..a517d550 100644 --- a/drv/stm32cube/bsp_uart_conf.h +++ b/drv/stm32cube/bsp_uart_conf.h @@ -23,10 +23,10 @@ #define BSP_UART1_AF GPIO_AF7_USART1 /* UART1 TX */ #define BSP_UART1_TX_PORT GPIOA -#define BSP_UART1_TX_PIN GPIO_PIN_4 /* PA.09 */ +#define BSP_UART1_TX_PIN GPIO_PIN_9 /* PA.09 */ /* UART1 RX */ #define BSP_UART1_RX_PORT GPIOA -#define BSP_UART1_RX_PIN GPIO_PIN_5 /* PA.10 */ +#define BSP_UART1_RX_PIN GPIO_PIN_10 /* PA.10 */ /* UART2 */ #define BSP_UART2 USART2 diff --git a/drv/stm32cube/stm32cube.mk b/drv/stm32cube/stm32cube.mk index d528ad29..b25271f0 100644 --- a/drv/stm32cube/stm32cube.mk +++ b/drv/stm32cube/stm32cube.mk @@ -5,7 +5,8 @@ STM32CUBESRC = ./drv/stm32cube/stm32f4xx_hal_msp.c \ ./drv/stm32cube/src/stm32f4xx_hal_uart.c \ ./drv/stm32cube/bsp.c \ ./drv/stm32cube/bsp_spi.c \ - ./drv/stm32cube/bsp_uart.c + ./drv/stm32cube/bsp_uart.c \ + ./drv/stm32cube/bsp_i2c.c # Required include directories STM32CUBEINC = ./drv/stm32cube \ diff --git a/hydrabus/hydrabus.mk b/hydrabus/hydrabus.mk index 856d8c2c..56c054a2 100644 --- a/hydrabus/hydrabus.mk +++ b/hydrabus/hydrabus.mk @@ -5,6 +5,7 @@ HYDRABUSSRC = hydrabus/hydrabus.c \ hydrabus/hydrabus_mode_conf.c \ hydrabus/hydrabus_mode_hiz.c \ hydrabus/hydrabus_mode_spi.c \ - hydrabus/hydrabus_mode_uart.c + hydrabus/hydrabus_mode_uart.c \ + hydrabus/hydrabus_mode_i2c.c # Required include directories HYDRABUSINC = ./hydrabus diff --git a/hydrabus/hydrabus_mode.c b/hydrabus/hydrabus_mode.c index 9d441ff0..d3bcac9e 100644 --- a/hydrabus/hydrabus_mode.c +++ b/hydrabus/hydrabus_mode.c @@ -56,7 +56,7 @@ const char hydrabus_mode_str_write_read_u8[] = "WRITE: 0x%02X READ: 0x%02X\r\n"; const char hydrabus_mode_str_mul_write[] = "WRITE: "; const char hydrabus_mode_str_mul_read[] = "READ: "; const char hydrabus_mode_str_mul_value_u8[] = "0x%02X "; -const char hydrabus_mode_str_mul_end_of_line[] = "\r\n"; +const char hydrabus_mode_str_mul_br[] = "\r\n"; static const char mode_str_delay_us[] = "DELAY %dus\r\n"; static const char mode_str_delay_ms[] = "DELAY %dms\r\n"; @@ -90,9 +90,11 @@ void hydrabus_mode_help(t_hydra_console *con) int i; BaseSequentialStream* chp = con->bss; - for(i=0; i < HYDRABUS_MODE_NB_CONF; i++) + chprintf(chp, "%d=%s", 1, hydrabus_mode_conf[0]->mode_str_name(0)); + for(i = 1; i < HYDRABUS_MODE_NB_CONF; i++) { - chprintf(chp, "%d=%s, ", i+1, hydrabus_mode_conf[i]->mode_str_name(0)); + chprintf(chp, ", "); + chprintf(chp, "%d=%s", i+1, hydrabus_mode_conf[i]->mode_str_name(0)); } chprintf(chp, "\r\n"); } diff --git a/hydrabus/hydrabus_mode.h b/hydrabus/hydrabus_mode.h index d03ce0e6..c33dcbcd 100644 --- a/hydrabus/hydrabus_mode.h +++ b/hydrabus/hydrabus_mode.h @@ -54,7 +54,7 @@ extern const char hydrabus_mode_str_mul_read[]; extern const char hydrabus_mode_str_mul_value_u8[]; /* "\r\n" */ -extern const char hydrabus_mode_str_mul_end_of_line[]; +extern const char hydrabus_mode_str_mul_br[]; typedef struct { diff --git a/hydrabus/hydrabus_mode_conf.c b/hydrabus/hydrabus_mode_conf.c index 0e19ce67..8d9675b7 100644 --- a/hydrabus/hydrabus_mode_conf.c +++ b/hydrabus/hydrabus_mode_conf.c @@ -19,18 +19,13 @@ #include "hydrabus_mode_hiz.h" #include "hydrabus_mode_spi.h" #include "hydrabus_mode_uart.h" +#include "hydrabus_mode_i2c.h" const mode_exec_t* hydrabus_mode_conf[HYDRABUS_MODE_NB_CONF] = { /* 0 */ &mode_hiz_exec, /* 1 */ &mode_spi_exec, - /* 2 */ &mode_uart_exec -#if 0 - /* 3 */ &mode_hiz_exec, - /* 4 */ &mode_hiz_exec, - /* 5 */ &mode_hiz_exec, - /* 6 */ &mode_hiz_exec, - /* 7 */ &mode_hiz_exec -#endif + /* 2 */ &mode_uart_exec, + /* 3 */ &mode_i2c_exec }; diff --git a/hydrabus/hydrabus_mode_conf.h b/hydrabus/hydrabus_mode_conf.h index c0d2dae8..5c7ee523 100644 --- a/hydrabus/hydrabus_mode_conf.h +++ b/hydrabus/hydrabus_mode_conf.h @@ -19,7 +19,7 @@ #include "hydrabus_mode.h" -#define HYDRABUS_MODE_NB_CONF (3) +#define HYDRABUS_MODE_NB_CONF (4) extern const mode_exec_t* hydrabus_mode_conf[HYDRABUS_MODE_NB_CONF]; #endif /* _HYDRABUS_MODE_CONF_H_ */ diff --git a/hydrabus/hydrabus_mode_hiz.c b/hydrabus/hydrabus_mode_hiz.c index 101ef2ad..c87eba17 100644 --- a/hydrabus/hydrabus_mode_hiz.c +++ b/hydrabus/hydrabus_mode_hiz.c @@ -100,7 +100,7 @@ uint32_t mode_write_hiz(t_hydra_console *con, uint8_t *tx_data, uint8_t nb_data) { chprintf(chp, hydrabus_mode_str_mul_value_u8, tx_data[i]); } - chprintf(chp, hydrabus_mode_str_mul_end_of_line); + chprintf(chp, hydrabus_mode_str_mul_br); } return 0; @@ -130,7 +130,7 @@ uint32_t mode_read_hiz(t_hydra_console *con, uint8_t *rx_data, uint8_t nb_data) { chprintf(chp, hydrabus_mode_str_mul_value_u8, rx_data[i]); } - chprintf(chp, hydrabus_mode_str_mul_end_of_line); + chprintf(chp, hydrabus_mode_str_mul_br); } return 0; } diff --git a/hydrabus/hydrabus_mode_i2c.c b/hydrabus/hydrabus_mode_i2c.c new file mode 100644 index 00000000..0bf76c2e --- /dev/null +++ b/hydrabus/hydrabus_mode_i2c.c @@ -0,0 +1,379 @@ +/* + HydraBus/HydraNFC - Copyright (C) 2014 Benjamin VERNOUX + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +#include "hydrabus_mode_i2c.h" +#include "chprintf.h" +#include "xatoi.h" +#include "bsp_i2c.h" + +#define I2C_DEV_NUM (1) + +static const char* str_i2c_start_br = { "I2C START\r\n" }; +static const char* str_i2c_stop_br = { "I2C STOP\r\n" }; +static const char* str_i2c_ack = { "ACK" }; +static const char* str_i2c_ack_br = { "ACK\r\n" }; +static const char* str_i2c_nack = { "NACK" }; +static const char* str_i2c_nack_br = { "NACK\r\n" }; + +const mode_exec_t mode_i2c_exec = +{ + .mode_cmd = &mode_cmd_i2c, /* Terminal parameters specific to this mode */ + .mode_start = &mode_start_i2c, /* Start command '[' */ + .mode_startR = &mode_startR_i2c, /* Start Read command '{' */ + .mode_stop = &mode_stop_i2c, /* Stop command ']' */ + .mode_stopR = &mode_stopR_i2c, /* Stop Read command '}' */ + .mode_write = &mode_write_i2c, /* Write/Send 1 data */ + .mode_read = &mode_read_i2c, /* Read 1 data command 'r' */ + .mode_write_read = &mode_write_read_i2c,/* Write & Read 1 data implicitely with mode_write command */ + .mode_clkh = &mode_clkh_i2c, /* Set CLK High (x-WIRE or other raw mode ...) command '/' */ + .mode_clkl = &mode_clkl_i2c, /* Set CLK Low (x-WIRE or other raw mode ...) command '\' */ + .mode_dath = &mode_dath_i2c, /* Set DAT High (x-WIRE or other raw mode ...) command '-' */ + .mode_datl = &mode_datl_i2c, /* Set DAT Low (x-WIRE or other raw mode ...) command '_' */ + .mode_dats = &mode_dats_i2c, /* Read Bit (x-WIRE or other raw mode ...) command '!' */ + .mode_clk = &mode_clk_i2c, /* CLK Tick (x-WIRE or other raw mode ...) command '^' */ + .mode_bitr = &mode_bitr_i2c, /* DAT Read (x-WIRE or other raw mode ...) command '.' */ + .mode_periodic = &mode_periodic_i2c, /* Periodic service called (like UART sniffer...) */ + .mode_macro = &mode_macro_i2c, /* Macro command "(x)", "(0)" List current macros */ + .mode_setup = &mode_setup_i2c, /* Configure the device internal params with user parameters (before Power On) */ + .mode_setup_exc = &mode_setup_exc_i2c, /* Configure the physical device after Power On (command 'W') */ + .mode_cleanup = &mode_cleanup_i2c, /* Exit mode, disable device enter safe mode I2C... */ + .mode_str_pins = &mode_str_pins_i2c, /* Pins used string */ + .mode_str_settings = &mode_str_settings_i2c, /* Settings string */ + .mode_str_name = &mode_str_name_i2c, /* Mode name string */ + .mode_str_prompt = &mode_str_prompt_i2c /* Prompt name string */ +}; + +/* TODO support Slave mode (by default only Master) */ +/* +static const char* str_dev_param_mode[2]= +{ + "1=Slave", + "2=Master" +}; +static const char* str_dev_arg_mode[]={ + "Choose I2C Mode: 1=Slave, 2=Master\r\n" }; +*/ + +static const char* str_dev_param_speed[]= +{ + /* I2C1 */ + /* 0 */ "1=50KHz", + /* 1 */ "2=100KHz", + /* 2 */ "3=400KHz" +}; +static const char* str_dev_arg_speed[] = { "Choose I2C1 Freq:\r\n1=50KHz, 2=100KHz, 3=400KHz\r\n" }; + +/* +TODO I2C Addr number of bits mode 7 or 10 +static const char* str_dev_numbits[]={ + "Choose I2C Addr number of bits\r\n1=7 bits, 2=10 bits\r\n" }; +*/ + +static const mode_dev_arg_t mode_dev_arg[] = +{ + /* argv0 */ { .min=1, .max=3, .dec_val=TRUE, .param=DEV_SPEED, .argc_help=ARRAY_SIZE(str_dev_arg_speed), .argv_help=str_dev_arg_speed }, +}; +#define MODE_DEV_NB_ARGC ((int)ARRAY_SIZE(mode_dev_arg)) /* Number of arguments/parameters for this mode */ + +#define STR_I2C_SIZE (32) +static char str_i2c[STR_I2C_SIZE+1]; + +/* Terminal parameters management specific to this mode */ +/* Return TRUE if success else FALSE */ +bool mode_cmd_i2c(t_hydra_console *con, int argc, const char* const* argv) +{ + long dev_val; + int arg_no; + + if(argc == 0) + { + hydrabus_mode_dev_manage_arg(con, 0, NULL, 0, 0, (mode_dev_arg_t*)&mode_dev_arg); + return FALSE; + } + + /* Ignore additional parameters */ + if(argc > MODE_DEV_NB_ARGC) + argc = MODE_DEV_NB_ARGC; + + for(arg_no = 0; arg_no < argc; arg_no++) + { + dev_val = hydrabus_mode_dev_manage_arg(con, argc, argv, MODE_DEV_NB_ARGC, arg_no, (mode_dev_arg_t*)&mode_dev_arg); + if(dev_val == HYDRABUS_MODE_DEV_INVALID) + { + return FALSE; + } + } + + if(argc == MODE_DEV_NB_ARGC) + { + mode_setup_exc_i2c(con); + return TRUE; + }else + { + return FALSE; + } +} + +/* Start command '[' */ +void mode_start_i2c(t_hydra_console *con) +{ + BaseSequentialStream* chp = con->bss; + mode_config_proto_t* proto = &con->mode->proto; + + if(proto->ack_pending) + { + /* Send I2C NACK*/ + bsp_i2c_read_ack(I2C_DEV_NUM, FALSE); + chprintf(chp, str_i2c_nack_br); + proto->ack_pending = 0; + } + + bsp_i2c_start(I2C_DEV_NUM); + chprintf(chp, str_i2c_start_br); +} + +/* Start Read command '{' => Same as Start for I2C */ +void mode_startR_i2c(t_hydra_console *con) +{ + mode_start_i2c(con); +} + +/* Stop command ']' */ +void mode_stop_i2c(t_hydra_console *con) +{ + BaseSequentialStream* chp = con->bss; + mode_config_proto_t* proto = &con->mode->proto; + + if(proto->ack_pending) + { + /* Send I2C NACK */ + bsp_i2c_read_ack(I2C_DEV_NUM, FALSE); + chprintf(chp, str_i2c_nack_br); + proto->ack_pending = 0; + } + bsp_i2c_stop(I2C_DEV_NUM); + chprintf(chp, str_i2c_stop_br); +} + +/* Stop Read command '}' => Same as Stop for I2C */ +void mode_stopR_i2c(t_hydra_console *con) +{ + mode_stop_i2c(con); +} + +/* Write/Send x data return status 0=BSP_OK + Nota nb_data shall be only equal to 1 multiple byte is not managed +*/ +uint32_t mode_write_i2c(t_hydra_console *con, uint8_t *tx_data, uint8_t nb_data) +{ + int i; + uint32_t status; + bool tx_ack_flag; + BaseSequentialStream* chp = con->bss; + mode_config_proto_t* proto = &con->mode->proto; + + if(proto->ack_pending) + { + /* Send I2C ACK */ + bsp_i2c_read_ack(I2C_DEV_NUM, TRUE); + chprintf(chp, str_i2c_ack_br); + proto->ack_pending = 0; + } + + chprintf(chp, hydrabus_mode_str_mul_write); + for(i = 0; i < nb_data; i++) + { + status = bsp_i2c_master_write_u8(I2C_DEV_NUM, tx_data[0], &tx_ack_flag); + /* Write 1 data */ + chprintf(chp, hydrabus_mode_str_mul_value_u8, tx_data[0]); + /* Print received ACK or NACK */ + if(tx_ack_flag) + chprintf(chp, str_i2c_ack); + else + chprintf(chp, str_i2c_nack); + + chprintf(chp, " "); + if(status != BSP_OK) + break; + } + chprintf(chp, hydrabus_mode_str_mul_br); + + return status; +} + +/* Read x data command 'r' return status 0=BSP_OK */ +uint32_t mode_read_i2c(t_hydra_console *con, uint8_t *rx_data, uint8_t nb_data) +{ + int i; + uint32_t status; + BaseSequentialStream* chp = con->bss; + mode_config_proto_t* proto = &con->mode->proto; + + for(i = 0; i < nb_data; i++) + { + if(proto->ack_pending) + { + /* Send I2C ACK */ + bsp_i2c_read_ack(I2C_DEV_NUM, TRUE); + chprintf(chp, str_i2c_ack); + chprintf(chp, hydrabus_mode_str_mul_br); + } + + status = bsp_i2c_master_read_u8(proto->dev_num, rx_data); + /* Read 1 data */ + chprintf(chp, hydrabus_mode_str_mul_read); + chprintf(chp, hydrabus_mode_str_mul_value_u8, rx_data[0]); + if(status != BSP_OK) + break; + + proto->ack_pending = 1; + } + return status; +} + +/* Write & Read x data return status 0=BSP_OK */ +uint32_t mode_write_read_i2c(t_hydra_console *con, uint8_t *tx_data, uint8_t *rx_data, uint8_t nb_data) +{ + (void)con; + (void)tx_data; + (void)rx_data; + (void)nb_data; + /* Write/Read not supported in I2C */ + return BSP_ERROR; +} + +/* Set CLK High (x-WIRE or other raw mode ...) command '/' */ +void mode_clkh_i2c(t_hydra_console *con) +{ + (void)con; + /* Nothing to do in I2C mode */ +} + +/* Set CLK Low (x-WIRE or other raw mode ...) command '\' */ +void mode_clkl_i2c(t_hydra_console *con) +{ + (void)con; + /* Nothing to do in I2C mode */ +} + +/* Set DAT High (x-WIRE or other raw mode ...) command '-' */ +void mode_dath_i2c(t_hydra_console *con) +{ + (void)con; + /* Nothing to do in I2C mode */ +} + +/* Set DAT Low (x-WIRE or other raw mode ...) command '_' */ +void mode_datl_i2c(t_hydra_console *con) +{ + (void)con; + /* Nothing to do in I2C mode */ +} + +/* Read Bit (x-WIRE or other raw mode ...) command '!' */ +void mode_dats_i2c(t_hydra_console *con) +{ + (void)con; + /* Nothing to do in I2C mode */ +} + +/* CLK Tick (x-WIRE or other raw mode ...) command '^' */ +void mode_clk_i2c(t_hydra_console *con) +{ + (void)con; + /* Nothing to do in I2C mode */ +} + +/* DAT Read (x-WIRE or other raw mode ...) command '.' */ +void mode_bitr_i2c(t_hydra_console *con) +{ + (void)con; + /* Nothing to do in I2C mode */ +} + +/* Periodic service called (like UART sniffer...) */ +uint32_t mode_periodic_i2c(t_hydra_console *con) +{ + (void)con; + /* Nothing to do in I2C mode */ + return 0; +} + +/* Macro command "(x)", "(0)" List current macros */ +void mode_macro_i2c(t_hydra_console *con, uint32_t macro_num) +{ + (void)con; + (void)macro_num; + /* TODO mode_i2c Macro command "(x)" */ +} + +/* Configure the device internal params with user parameters (before Power On) */ +void mode_setup_i2c(t_hydra_console *con) +{ + (void)con; + /* Nothing to do in I2C mode */ +} + +/* Configure the physical device after Power On (command 'W') */ +void mode_setup_exc_i2c(t_hydra_console *con) +{ + mode_config_proto_t* proto; + + proto = &con->mode->proto; + proto->ack_pending = 0; + bsp_i2c_init(proto->dev_num, proto); +} + +/* Exit mode, disable device safe mode I2C... */ +void mode_cleanup_i2c(t_hydra_console *con) +{ + mode_config_proto_t* proto; + + proto = &con->mode->proto; + bsp_i2c_deinit(proto->dev_num); +} + +/* String pins used */ +const char* mode_str_pins_i2c(t_hydra_console *con) +{ + (void)con; + return "I2C1 SCL=PB6, SDA=PB7"; +} + +/* String settings */ +const char* mode_str_settings_i2c(t_hydra_console *con) +{ + mode_config_proto_t* proto; + proto = &con->mode->proto; + + chsnprintf((char *)str_i2c, STR_I2C_SIZE, "I2C%d Speed:%s", + proto->dev_num+1, + str_dev_param_speed[proto->dev_speed]); + return str_i2c; +} + +/* Return mode name */ +const char* mode_str_name_i2c(t_hydra_console *con) +{ + (void)con; + return "I2C"; +} + +/* Return Prompt name */ +const char* mode_str_prompt_i2c(t_hydra_console *con) +{ + (void)con; + return "i2c1> "; +} diff --git a/hydrabus/hydrabus_mode_i2c.h b/hydrabus/hydrabus_mode_i2c.h new file mode 100644 index 00000000..52b2659c --- /dev/null +++ b/hydrabus/hydrabus_mode_i2c.h @@ -0,0 +1,80 @@ +/* + HydraBus/HydraNFC - Copyright (C) 2014 Benjamin VERNOUX + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef _HYDRABUS_MODE_I2C_H_ +#define _HYDRABUS_MODE_I2C_H_ + +#include "hydrabus_mode.h" + +extern const mode_exec_t mode_i2c_exec; + +bool mode_cmd_i2c(t_hydra_console *con, int argc, const char* const* argv); + +/* Start command '[' */ +void mode_start_i2c(t_hydra_console *con); +/* Start Read command '{' */ +void mode_startR_i2c(t_hydra_console *con); +/* Stop command ']' */ +void mode_stop_i2c(t_hydra_console *con); +/* Stop Read command '}' */ +void mode_stopR_i2c(t_hydra_console *con); + +/* Write/Send x data (return status 0=OK) */ +uint32_t mode_write_i2c(t_hydra_console *con, uint8_t *tx_data, uint8_t nb_data); +/* Read x data command 'r' or 'r:x' (return status 0=OK) */ +uint32_t mode_read_i2c(t_hydra_console *con, uint8_t *rx_data, uint8_t nb_data); + /* Write & Read x data (return status 0=OK) */ +uint32_t mode_write_read_i2c(t_hydra_console *con, uint8_t *tx_data, uint8_t *rx_data, uint8_t nb_data); + +/* Set CLK High (x-WIRE or other raw mode ...) command '/' */ +void mode_clkh_i2c(t_hydra_console *con); +/* Set CLK Low (x-WIRE or other raw mode ...) command '\' */ +void mode_clkl_i2c(t_hydra_console *con); +/* Set DAT High (x-WIRE or other raw mode ...) command '-' */ +void mode_dath_i2c(t_hydra_console *con); +/* Set DAT Low (x-WIRE or other raw mode ...) command '_' */ +void mode_datl_i2c(t_hydra_console *con); +/* Read Bit (x-WIRE or other raw mode ...) command '!' */ +void mode_dats_i2c(t_hydra_console *con); +/* CLK Tick (x-WIRE or other raw mode ...) command '^' */ +void mode_clk_i2c(t_hydra_console *con); +/* DAT Read (x-WIRE or other raw mode ...) command '.' */ +void mode_bitr_i2c(t_hydra_console *con); + +/* Periodic service called (like UART sniffer...) */ +uint32_t mode_periodic_i2c(t_hydra_console *con); + +/* Macro command "(x)", "(0)" List current macros */ +void mode_macro_i2c(t_hydra_console *con, uint32_t macro_num); + +/* Configure the device internal params with user parameters (before Power On) */ +void mode_setup_i2c(t_hydra_console *con); +/* Configure the physical device after Power On (command 'W') */ +void mode_setup_exc_i2c(t_hydra_console *con); + +/* Exit mode, disable device safe mode I2C... */ +void mode_cleanup_i2c(t_hydra_console *con); + +/* Pins used string */ +const char* mode_str_pins_i2c(t_hydra_console *con); +/* Settings string */ +const char* mode_str_settings_i2c(t_hydra_console *con); +/* Mode name string */ +const char* mode_str_name_i2c(t_hydra_console *con); +/* Mode prompt string*/ +const char* mode_str_prompt_i2c(t_hydra_console *con); + +#endif /* _HYDRABUS_MODE_I2C_H_ */ diff --git a/hydrabus/hydrabus_mode_spi.c b/hydrabus/hydrabus_mode_spi.c index 91e61f02..482297a5 100644 --- a/hydrabus/hydrabus_mode_spi.c +++ b/hydrabus/hydrabus_mode_spi.c @@ -224,7 +224,7 @@ uint32_t mode_write_spi(t_hydra_console *con, uint8_t *tx_data, uint8_t nb_data) { chprintf(chp, hydrabus_mode_str_mul_value_u8, tx_data[i]); } - chprintf(chp, hydrabus_mode_str_mul_end_of_line); + chprintf(chp, hydrabus_mode_str_mul_br); } } return status; @@ -253,7 +253,7 @@ uint32_t mode_read_spi(t_hydra_console *con, uint8_t *rx_data, uint8_t nb_data) { chprintf(chp, hydrabus_mode_str_mul_value_u8, rx_data[i]); } - chprintf(chp, hydrabus_mode_str_mul_end_of_line); + chprintf(chp, hydrabus_mode_str_mul_br); } } return status; diff --git a/hydrabus/hydrabus_mode_uart.c b/hydrabus/hydrabus_mode_uart.c index b345d35c..fb3c2742 100644 --- a/hydrabus/hydrabus_mode_uart.c +++ b/hydrabus/hydrabus_mode_uart.c @@ -189,7 +189,7 @@ uint32_t mode_write_uart(t_hydra_console *con, uint8_t *tx_data, uint8_t nb_data { chprintf(chp, hydrabus_mode_str_mul_value_u8, tx_data[i]); } - chprintf(chp, hydrabus_mode_str_mul_end_of_line); + chprintf(chp, hydrabus_mode_str_mul_br); } } return status; @@ -218,7 +218,7 @@ uint32_t mode_read_uart(t_hydra_console *con, uint8_t *rx_data, uint8_t nb_data) { chprintf(chp, hydrabus_mode_str_mul_value_u8, rx_data[i]); } - chprintf(chp, hydrabus_mode_str_mul_end_of_line); + chprintf(chp, hydrabus_mode_str_mul_br); } } return status;