| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 <string.h> |
| #include <stdlib.h> |
| #include <assert.h> |
| |
| #include "os/mynewt.h" |
| |
| #include <hal/hal_i2c.h> |
| #include <hal/hal_gpio.h> |
| |
| #include <mcu/stm32_hal.h> |
| |
| #define HAL_I2C_MAX_DEVS 3 |
| |
| #define I2C_ADDRESS 0xae |
| |
| extern HAL_StatusTypeDef HAL_I2C_Master_Transmit_Custom(I2C_HandleTypeDef *hi2c, |
| uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout, |
| uint8_t LastOp); |
| extern HAL_StatusTypeDef HAL_I2C_Master_Receive_Custom(I2C_HandleTypeDef *hi2c, |
| uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout, |
| uint8_t LastOp); |
| |
| struct stm32_hal_i2c { |
| I2C_HandleTypeDef hid_handle; |
| }; |
| |
| #if MYNEWT_VAL(I2C_0) |
| static struct stm32_hal_i2c i2c0; |
| #endif |
| #if MYNEWT_VAL(I2C_1) |
| static struct stm32_hal_i2c i2c1; |
| #endif |
| #if MYNEWT_VAL(I2C_2) |
| static struct stm32_hal_i2c i2c2; |
| #endif |
| |
| static struct stm32_hal_i2c *hal_i2c_devs[HAL_I2C_MAX_DEVS] = { |
| #if MYNEWT_VAL(I2C_0) |
| &i2c0, |
| #else |
| NULL, |
| #endif |
| #if MYNEWT_VAL(I2C_1) |
| &i2c1, |
| #else |
| NULL, |
| #endif |
| #if MYNEWT_VAL(I2C_2) |
| &i2c2, |
| #else |
| NULL, |
| #endif |
| }; |
| |
| #if MYNEWT_VAL(MCU_STM32F1) |
| static void |
| i2c_reset(I2C_HandleTypeDef *hi2c) |
| { |
| __HAL_I2C_DISABLE(hi2c); |
| hi2c->Instance->CR1 |= I2C_CR1_SWRST; |
| hi2c->Instance->CR1 &= ~I2C_CR1_SWRST; |
| __HAL_I2C_ENABLE(hi2c); |
| } |
| #endif |
| |
| int |
| hal_i2c_init(uint8_t i2c_num, void *usercfg) |
| { |
| struct stm32_hal_i2c_cfg *cfg = (struct stm32_hal_i2c_cfg *)usercfg; |
| struct stm32_hal_i2c *dev; |
| I2C_InitTypeDef *init; |
| #if MYNEWT_VAL(MCU_STM32F1) |
| GPIO_InitTypeDef gpio; |
| #endif |
| int rc; |
| |
| if (i2c_num >= HAL_I2C_MAX_DEVS || !(dev = hal_i2c_devs[i2c_num])) { |
| return -1; |
| } |
| |
| init = &dev->hid_handle.Init; |
| dev->hid_handle.Instance = cfg->hic_i2c; |
| #if !MYNEWT_VAL(STM32_HAL_I2C_HAS_CLOCKSPEED) |
| init->Timing = cfg->hic_timingr; |
| #else |
| init->ClockSpeed = cfg->hic_speed; |
| #endif |
| if (cfg->hic_10bit) { |
| init->AddressingMode = I2C_ADDRESSINGMODE_10BIT; |
| } else { |
| init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; |
| } |
| init->OwnAddress1 = I2C_ADDRESS; |
| init->OwnAddress2 = 0xFE; |
| |
| /* |
| * Configure GPIO pins for I2C. |
| * Enable clock routing for I2C. |
| */ |
| #if !MYNEWT_VAL(MCU_STM32F1) |
| rc = hal_gpio_init_af(cfg->hic_pin_sda, cfg->hic_pin_af, HAL_GPIO_PULL_UP, |
| 1); |
| if (rc) { |
| goto err; |
| } |
| rc = hal_gpio_init_af(cfg->hic_pin_scl, cfg->hic_pin_af, HAL_GPIO_PULL_UP, |
| 1); |
| if (rc) { |
| goto err; |
| } |
| |
| *cfg->hic_rcc_reg |= cfg->hic_rcc_dev; |
| #else |
| /* For STM32F1x initialize I2C clock before GPIOs */ |
| *cfg->hic_rcc_reg |= cfg->hic_rcc_dev; |
| |
| if (cfg->hic_pin_remap_fn != NULL) { |
| cfg->hic_pin_remap_fn(); |
| } |
| |
| /* |
| * The block below applies a workaround described in 2.13.7 |
| * of the STM32F103 errata (also described on F105/107 errata). |
| */ |
| gpio.Mode = GPIO_MODE_OUTPUT_OD; |
| gpio.Speed = GPIO_SPEED_FREQ_LOW; |
| gpio.Pull = GPIO_NOPULL; |
| |
| hal_gpio_init_stm(cfg->hic_pin_sda, &gpio); |
| hal_gpio_write(cfg->hic_pin_sda, 1); |
| hal_gpio_init_stm(cfg->hic_pin_scl, &gpio); |
| hal_gpio_write(cfg->hic_pin_scl, 1); |
| |
| assert(hal_gpio_read(cfg->hic_pin_sda) == 1); |
| assert(hal_gpio_read(cfg->hic_pin_scl) == 1); |
| |
| hal_gpio_write(cfg->hic_pin_sda, 0); |
| assert(hal_gpio_read(cfg->hic_pin_sda) == 0); |
| |
| hal_gpio_write(cfg->hic_pin_scl, 0); |
| assert(hal_gpio_read(cfg->hic_pin_scl) == 0); |
| |
| hal_gpio_write(cfg->hic_pin_scl, 1); |
| assert(hal_gpio_read(cfg->hic_pin_scl) == 1); |
| |
| hal_gpio_write(cfg->hic_pin_sda, 1); |
| assert(hal_gpio_read(cfg->hic_pin_sda) == 1); |
| |
| /* |
| * Normal I2C PIN initialization |
| */ |
| gpio.Mode = GPIO_MODE_AF_OD; |
| gpio.Speed = GPIO_SPEED_FREQ_HIGH; |
| /* NOTE: Pull is not used in AF mode */ |
| gpio.Pull = GPIO_NOPULL; |
| |
| hal_gpio_init_stm(cfg->hic_pin_scl, &gpio); |
| hal_gpio_init_stm(cfg->hic_pin_sda, &gpio); |
| |
| /* |
| * Reset I2C |
| */ |
| dev->hid_handle.Instance->CR1 = I2C_CR1_SWRST; |
| dev->hid_handle.Instance->CR1 = 0; |
| #endif |
| |
| rc = HAL_I2C_Init(&dev->hid_handle); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| *cfg->hic_rcc_reg &= ~cfg->hic_rcc_dev; |
| return rc; |
| } |
| |
| int |
| hal_i2c_master_write(uint8_t i2c_num, struct hal_i2c_master_data *data, |
| uint32_t timo, uint8_t last_op) |
| { |
| struct stm32_hal_i2c *dev; |
| |
| if (i2c_num >= HAL_I2C_MAX_DEVS || !(dev = hal_i2c_devs[i2c_num])) { |
| return -1; |
| } |
| |
| return HAL_I2C_Master_Transmit_Custom(&dev->hid_handle, data->address << 1, |
| data->buffer, data->len, timo, last_op); |
| } |
| |
| int |
| hal_i2c_master_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata, |
| uint32_t timo, uint8_t last_op) |
| { |
| struct stm32_hal_i2c *dev; |
| |
| if (i2c_num >= HAL_I2C_MAX_DEVS || !(dev = hal_i2c_devs[i2c_num])) { |
| return -1; |
| } |
| |
| return HAL_I2C_Master_Receive_Custom(&dev->hid_handle, pdata->address << 1, |
| pdata->buffer, pdata->len, timo, last_op); |
| } |
| |
| int |
| hal_i2c_master_probe(uint8_t i2c_num, uint8_t address, uint32_t timo) |
| { |
| struct stm32_hal_i2c *dev; |
| int rc; |
| |
| if (i2c_num >= HAL_I2C_MAX_DEVS || !(dev = hal_i2c_devs[i2c_num])) { |
| return -1; |
| } |
| |
| rc = HAL_I2C_IsDeviceReady(&dev->hid_handle, address << 1, 1, timo); |
| |
| #if MYNEWT_VAL(MCU_STM32F1) |
| if (rc == HAL_BUSY) { |
| i2c_reset(&dev->hid_handle); |
| } |
| #endif |
| |
| return rc; |
| } |