blob: e59da380c4838d15a5974aba8790861bfaab374f [file] [log] [blame]
/*
* 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;
}