From 843423e4fda9fecf67b545dc61658e8ea84910a3 Mon Sep 17 00:00:00 2001 From: bcostm Date: Thu, 12 Mar 2015 10:19:14 +0100 Subject: [PATCH] [STM32L0] Add common hal files (refactoring) --- .../TARGET_STM32L0/PeripheralPins.h | 66 +++ .../TARGET_STM/TARGET_STM32L0/analogin_api.c | 176 ++++++++ .../TARGET_STM/TARGET_STM32L0/analogout_api.c | 161 +++++++ .../hal/TARGET_STM/TARGET_STM32L0/gpio_api.c | 77 ++++ .../TARGET_STM/TARGET_STM32L0/gpio_irq_api.c | 267 ++++++++++++ .../TARGET_STM/TARGET_STM32L0/gpio_object.h | 75 ++++ .../hal/TARGET_STM/TARGET_STM32L0/i2c_api.c | 409 ++++++++++++++++++ .../TARGET_STM32L0/mbed_overrides.c | 35 ++ .../hal/TARGET_STM/TARGET_STM32L0/pinmap.c | 143 ++++++ .../hal/TARGET_STM/TARGET_STM32L0/port_api.c | 103 +++++ .../TARGET_STM/TARGET_STM32L0/pwmout_api.c | 193 +++++++++ .../TARGET_STM/TARGET_STM32L0/serial_api.c | 406 +++++++++++++++++ .../hal/TARGET_STM/TARGET_STM32L0/sleep.c | 61 +++ .../hal/TARGET_STM/TARGET_STM32L0/spi_api.c | 269 ++++++++++++ 14 files changed, 2441 insertions(+) create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/PeripheralPins.h create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/analogin_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/analogout_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_irq_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_object.h create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/i2c_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/mbed_overrides.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/pinmap.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/port_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/pwmout_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/serial_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/sleep.c create mode 100644 libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/spi_api.c diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/PeripheralPins.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/PeripheralPins.h new file mode 100644 index 0000000000..cc2fcaaf11 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/PeripheralPins.h @@ -0,0 +1,66 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ + +#ifndef MBED_PERIPHERALPINS_H +#define MBED_PERIPHERALPINS_H + +#include "pinmap.h" +#include "PeripheralNames.h" + +//*** ADC *** + +extern const PinMap PinMap_ADC[]; + +//*** DAC *** + +extern const PinMap PinMap_DAC[]; + +//*** I2C *** + +extern const PinMap PinMap_I2C_SDA[]; +extern const PinMap PinMap_I2C_SCL[]; + +//*** PWM *** + +extern const PinMap PinMap_PWM[]; + +//*** SERIAL *** + +extern const PinMap PinMap_UART_TX[]; +extern const PinMap PinMap_UART_RX[]; + +//*** SPI *** + +extern const PinMap PinMap_SPI_MOSI[]; +extern const PinMap PinMap_SPI_MISO[]; +extern const PinMap PinMap_SPI_SCLK[]; +extern const PinMap PinMap_SPI_SSEL[]; + +#endif diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/analogin_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/analogin_api.c new file mode 100644 index 0000000000..7af8188b0f --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/analogin_api.c @@ -0,0 +1,176 @@ +/* mbed Microcontroller Library + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "mbed_assert.h" +#include "analogin_api.h" + +#if DEVICE_ANALOGIN + +#include "wait_api.h" +#include "cmsis.h" +#include "pinmap.h" +#include "PeripheralPins.h" + +ADC_HandleTypeDef AdcHandle; + +int adc_inited = 0; + +void analogin_init(analogin_t *obj, PinName pin) +{ + // Get the peripheral name from the pin and assign it to the object + obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC); + MBED_ASSERT(obj->adc != (ADCName)NC); + + // Configure GPIO + pinmap_pinout(pin, PinMap_ADC); + + // Save pin number for the read function + obj->pin = pin; + + // The ADC initialization is done once + if (adc_inited == 0) { + adc_inited = 1; + + AdcHandle.Instance = (ADC_TypeDef *)(obj->adc); + + // Enable ADC clock + __ADC1_CLK_ENABLE(); + + // Configure ADC + AdcHandle.Init.OversamplingMode = DISABLE; + AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV1; + AdcHandle.Init.Resolution = ADC_RESOLUTION12b; + AdcHandle.Init.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; + AdcHandle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; + AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT; + AdcHandle.Init.ContinuousConvMode = DISABLE; + AdcHandle.Init.DiscontinuousConvMode = DISABLE; + AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIG_EDGE_NONE; + AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIG0_T6_TRGO; // Not used here + AdcHandle.Init.DMAContinuousRequests = DISABLE; + AdcHandle.Init.EOCSelection = EOC_SINGLE_CONV; + AdcHandle.Init.Overrun = OVR_DATA_OVERWRITTEN; + AdcHandle.Init.LowPowerAutoWait = ENABLE; + AdcHandle.Init.LowPowerFrequencyMode = DISABLE; // To be enabled only if ADC clock < 2.8 MHz + AdcHandle.Init.LowPowerAutoPowerOff = DISABLE; + HAL_ADC_Init(&AdcHandle); + + // Calibration + HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_SINGLE_ENDED); + + __HAL_ADC_ENABLE(&AdcHandle); + } +} + +static inline uint16_t adc_read(analogin_t *obj) +{ + ADC_ChannelConfTypeDef sConfig; + + AdcHandle.Instance = (ADC_TypeDef *)(obj->adc); + + // Configure ADC channel + switch (obj->pin) { + case PA_0: + sConfig.Channel = ADC_CHANNEL_0; + break; + case PA_1: + sConfig.Channel = ADC_CHANNEL_1; + break; + case PA_2: + sConfig.Channel = ADC_CHANNEL_2; + break; + case PA_3: + sConfig.Channel = ADC_CHANNEL_3; + break; + case PA_4: + sConfig.Channel = ADC_CHANNEL_4; + break; + case PA_5: + sConfig.Channel = ADC_CHANNEL_5; + break; + case PA_6: + sConfig.Channel = ADC_CHANNEL_6; + break; + case PA_7: + sConfig.Channel = ADC_CHANNEL_7; + break; + case PB_0: + sConfig.Channel = ADC_CHANNEL_8; + break; + case PB_1: + sConfig.Channel = ADC_CHANNEL_9; + break; + case PC_0: + sConfig.Channel = ADC_CHANNEL_10; + break; + case PC_1: + sConfig.Channel = ADC_CHANNEL_11; + break; + case PC_2: + sConfig.Channel = ADC_CHANNEL_12; + break; + case PC_3: + sConfig.Channel = ADC_CHANNEL_13; + break; + case PC_4: + sConfig.Channel = ADC_CHANNEL_14; + break; + case PC_5: + sConfig.Channel = ADC_CHANNEL_15; + break; + default: + return 0; + } + + ADC1->CHSELR = 0; // [TODO] Workaround. To be removed after Cube driver is corrected. + HAL_ADC_ConfigChannel(&AdcHandle, &sConfig); + + HAL_ADC_Start(&AdcHandle); // Start conversion + + // Wait end of conversion and get value + if (HAL_ADC_PollForConversion(&AdcHandle, 10) == HAL_OK) { + return (HAL_ADC_GetValue(&AdcHandle)); + } else { + return 0; + } +} + +uint16_t analogin_read_u16(analogin_t *obj) +{ + uint16_t value = adc_read(obj); + // 12-bit to 16-bit conversion + value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); + return value; +} + +float analogin_read(analogin_t *obj) +{ + uint16_t value = adc_read(obj); + return (float)value * (1.0f / (float)0xFFF); // 12 bits range +} + +#endif diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/analogout_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/analogout_api.c new file mode 100644 index 0000000000..001c583d50 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/analogout_api.c @@ -0,0 +1,161 @@ +/* mbed Microcontroller Library + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "mbed_assert.h" +#include "analogout_api.h" + +#if DEVICE_ANALOGOUT + +#include "cmsis.h" +#include "pinmap.h" +#include "mbed_error.h" +#include "PeripheralPins.h" + +#define DAC_RANGE (0xFFF) // 12 bits + +static DAC_HandleTypeDef DacHandle; + +// These variables are used for the "free" function +static int pa4_used = 0; +static int pa5_used = 0; + +void analogout_init(dac_t *obj, PinName pin) +{ + DAC_ChannelConfTypeDef sConfig; + + // Get the peripheral name from the pin and assign it to the object + obj->dac = (DACName)pinmap_peripheral(pin, PinMap_DAC); + MBED_ASSERT(obj->dac != (DACName)NC); + + // Configure GPIO + pinmap_pinout(pin, PinMap_DAC); + + // Save the pin for future use + obj->pin = pin; + + // Enable DAC clock + __DAC_CLK_ENABLE(); + + // Configure DAC + DacHandle.Instance = DAC; + + sConfig.DAC_Trigger = DAC_TRIGGER_NONE; + sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE; + + if (pin == PA_4) { + HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DAC_CHANNEL_1); + pa4_used = 1; + } + +#if defined(DAC_CHANNEL_2) + if (pin == PA_5) { + HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DAC_CHANNEL_2); + pa5_used = 1; + } +#endif + + analogout_write_u16(obj, 0); +} + +void analogout_free(dac_t *obj) +{ + // Reset DAC and disable clock + if (obj->pin == PA_4) pa4_used = 0; + if (obj->pin == PA_5) pa5_used = 0; + + if ((pa4_used == 0) && (pa5_used == 0)) { + __DAC_FORCE_RESET(); + __DAC_RELEASE_RESET(); + __DAC_CLK_DISABLE(); + } + + // Configure GPIO + pin_function(obj->pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); +} + +static inline void dac_write(dac_t *obj, uint16_t value) +{ + if (obj->pin == PA_4) { + HAL_DAC_SetValue(&DacHandle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value); + HAL_DAC_Start(&DacHandle, DAC_CHANNEL_1); + } + +#if defined(DAC_CHANNEL_2) + if (obj->pin == PA_5) { + HAL_DAC_SetValue(&DacHandle, DAC_CHANNEL_2, DAC_ALIGN_12B_R, value); + HAL_DAC_Start(&DacHandle, DAC_CHANNEL_2); + } +#endif +} + +static inline int dac_read(dac_t *obj) +{ + if (obj->pin == PA_4) { + return (int)HAL_DAC_GetValue(&DacHandle, DAC_CHANNEL_1); + } +#if defined(DAC_CHANNEL_2) + else if (obj->pin == PA_5) { + return (int)HAL_DAC_GetValue(&DacHandle, DAC_CHANNEL_2); + } +#endif + else { + return 0; + } +} + +void analogout_write(dac_t *obj, float value) +{ + if (value < 0.0f) { + dac_write(obj, 0); // Min value + } else if (value > 1.0f) { + dac_write(obj, (uint16_t)DAC_RANGE); // Max value + } else { + dac_write(obj, (uint16_t)(value * (float)DAC_RANGE)); + } +} + +void analogout_write_u16(dac_t *obj, uint16_t value) +{ + if (value > (uint16_t)DAC_RANGE) { + dac_write(obj, (uint16_t)DAC_RANGE); // Max value + } else { + dac_write(obj, value); + } +} + +float analogout_read(dac_t *obj) +{ + uint32_t value = dac_read(obj); + return (float)((float)value * (1.0f / (float)DAC_RANGE)); +} + +uint16_t analogout_read_u16(dac_t *obj) +{ + return (uint16_t)dac_read(obj); +} + +#endif // DEVICE_ANALOGOUT diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_api.c new file mode 100644 index 0000000000..c8dd2c0150 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_api.c @@ -0,0 +1,77 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#include "mbed_assert.h" +#include "gpio_api.h" +#include "pinmap.h" +#include "mbed_error.h" + +extern uint32_t Set_GPIO_Clock(uint32_t port_idx); + +uint32_t gpio_set(PinName pin) +{ + MBED_ASSERT(pin != (PinName)NC); + + pin_function(pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + return (uint32_t)(1 << ((uint32_t)pin & 0xF)); // Return the pin mask +} + +void gpio_init(gpio_t *obj, PinName pin) +{ + obj->pin = pin; + if (pin == (PinName)NC) + return; + + uint32_t port_index = STM_PORT(pin); + + // Enable GPIO clock + uint32_t gpio_add = Set_GPIO_Clock(port_index); + GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add; + + // Fill GPIO object structure for future use + obj->mask = gpio_set(pin); + obj->reg_in = &gpio->IDR; + obj->reg_set = &gpio->BSRR; + obj->reg_clr = &gpio->BRR; +} + +void gpio_mode(gpio_t *obj, PinMode mode) +{ + pin_mode(obj->pin, mode); +} + +void gpio_dir(gpio_t *obj, PinDirection direction) +{ + MBED_ASSERT(obj->pin != (PinName)NC); + if (direction == PIN_OUTPUT) { + pin_function(obj->pin, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0)); + } else { // PIN_INPUT + pin_function(obj->pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + } +} diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_irq_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_irq_api.c new file mode 100644 index 0000000000..2f08bb5506 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_irq_api.c @@ -0,0 +1,267 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#include +#include "cmsis.h" +#include "gpio_irq_api.h" +#include "pinmap.h" +#include "mbed_error.h" + +#define EDGE_NONE (0) +#define EDGE_RISE (1) +#define EDGE_FALL (2) +#define EDGE_BOTH (3) + +// Number of EXTI irq vectors (EXTI0_1, EXTI2_3, EXTI4_15) +#define CHANNEL_NUM (3) + +// Max pins for one line (max with EXTI4_15) +#define MAX_PIN_LINE (12) + +typedef struct gpio_channel { + uint32_t pin_mask; // bitmask representing which pins are configured for receiving interrupts + uint32_t channel_ids[MAX_PIN_LINE]; // mbed "gpio_irq_t gpio_irq" field of instance + uint32_t channel_gpio[MAX_PIN_LINE]; // base address of gpio port group + uint32_t channel_pin[MAX_PIN_LINE]; // pin number in port group +} gpio_channel_t; + +static gpio_channel_t channels[CHANNEL_NUM] = { + {.pin_mask = 0}, + {.pin_mask = 0}, + {.pin_mask = 0} +}; + +// Used to return the index for channels array. +static uint32_t pin_base_nr[16] = { + // EXTI0_1 + 0, // pin 0 + 1, // pin 1 + // EXTI2_3 + 0, // pin 2 + 1, // pin 3 + // EXTI4_15 + 0, // pin 4 + 1, // pin 5 + 2, // pin 6 + 3, // pin 7 + 4, // pin 8 + 5, // pin 9 + 6, // pin 10 + 7, // pin 11 + 8, // pin 12 + 9, // pin 13 + 10, // pin 14 + 11 // pin 15 +}; + +static gpio_irq_handler irq_handler; + +static void handle_interrupt_in(uint32_t irq_index, uint32_t max_num_pin_line) +{ + gpio_channel_t *gpio_channel = &channels[irq_index]; + uint32_t gpio_idx; + + for (gpio_idx = 0; gpio_idx < max_num_pin_line; gpio_idx++) { + uint32_t current_mask = (1 << gpio_idx); + + if (gpio_channel->pin_mask & current_mask) { + // Retrieve the gpio and pin that generate the irq + GPIO_TypeDef *gpio = (GPIO_TypeDef *)(gpio_channel->channel_gpio[gpio_idx]); + uint32_t pin = (uint32_t)(1 << (gpio_channel->channel_pin[gpio_idx])); + + // Clear interrupt flag + if (__HAL_GPIO_EXTI_GET_FLAG(pin) != RESET) { + __HAL_GPIO_EXTI_CLEAR_FLAG(pin); + + if (gpio_channel->channel_ids[gpio_idx] == 0) continue; + + // Check which edge has generated the irq + if ((gpio->IDR & pin) == 0) { + irq_handler(gpio_channel->channel_ids[gpio_idx], IRQ_FALL); + } else { + irq_handler(gpio_channel->channel_ids[gpio_idx], IRQ_RISE); + } + } + } + } +} + +// EXTI lines 0 to 1 +static void gpio_irq0(void) +{ + handle_interrupt_in(0, 2); +} + +// EXTI lines 2 to 3 +static void gpio_irq1(void) +{ + handle_interrupt_in(1, 2); +} + +// EXTI lines 4 to 15 +static void gpio_irq2(void) +{ + handle_interrupt_in(2, 12); +} + +extern uint32_t Set_GPIO_Clock(uint32_t port_idx); + +int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) +{ + IRQn_Type irq_n = (IRQn_Type)0; + uint32_t vector = 0; + uint32_t irq_index; + gpio_channel_t *gpio_channel; + uint32_t gpio_idx; + + if (pin == NC) return -1; + + uint32_t port_index = STM_PORT(pin); + uint32_t pin_index = STM_PIN(pin); + + // Select irq number and interrupt routine + if ((pin_index == 0) || (pin_index == 1)) { + irq_n = EXTI0_1_IRQn; + vector = (uint32_t)&gpio_irq0; + irq_index = 0; + } else if ((pin_index == 2) || (pin_index == 3)) { + irq_n = EXTI2_3_IRQn; + vector = (uint32_t)&gpio_irq1; + irq_index = 1; + } else if ((pin_index > 3) && (pin_index < 16)) { + irq_n = EXTI4_15_IRQn; + vector = (uint32_t)&gpio_irq2; + irq_index = 2; + } else { + error("InterruptIn error: pin not supported.\n"); + return -1; + } + + // Enable GPIO clock + uint32_t gpio_add = Set_GPIO_Clock(port_index); + + // Configure GPIO + pin_function(pin, STM_PIN_DATA(STM_MODE_IT_FALLING, GPIO_NOPULL, 0)); + + // Enable EXTI interrupt + NVIC_SetVector(irq_n, vector); + NVIC_EnableIRQ(irq_n); + + // Save informations for future use + obj->irq_n = irq_n; + obj->irq_index = irq_index; + obj->event = EDGE_NONE; + obj->pin = pin; + + gpio_channel = &channels[irq_index]; + gpio_idx = pin_base_nr[pin_index]; + gpio_channel->pin_mask |= (1 << gpio_idx); + gpio_channel->channel_ids[gpio_idx] = id; + gpio_channel->channel_gpio[gpio_idx] = gpio_add; + gpio_channel->channel_pin[gpio_idx] = pin_index; + + irq_handler = handler; + + return 0; +} + +void gpio_irq_free(gpio_irq_t *obj) +{ + gpio_channel_t *gpio_channel = &channels[obj->irq_index]; + uint32_t pin_index = STM_PIN(obj->pin); + uint32_t gpio_idx = pin_base_nr[pin_index]; + + gpio_channel->pin_mask &= ~(1 << gpio_idx); + gpio_channel->channel_ids[gpio_idx] = 0; + gpio_channel->channel_gpio[gpio_idx] = 0; + gpio_channel->channel_pin[gpio_idx] = 0; + + // Disable EXTI line + pin_function(obj->pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + obj->event = EDGE_NONE; +} + +void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) +{ + uint32_t mode = STM_MODE_IT_EVT_RESET; + uint32_t pull = GPIO_NOPULL; + + if (enable) { + if (event == IRQ_RISE) { + if ((obj->event == EDGE_FALL) || (obj->event == EDGE_BOTH)) { + mode = STM_MODE_IT_RISING_FALLING; + obj->event = EDGE_BOTH; + } else { // NONE or RISE + mode = STM_MODE_IT_RISING; + obj->event = EDGE_RISE; + } + } + if (event == IRQ_FALL) { + if ((obj->event == EDGE_RISE) || (obj->event == EDGE_BOTH)) { + mode = STM_MODE_IT_RISING_FALLING; + obj->event = EDGE_BOTH; + } else { // NONE or FALL + mode = STM_MODE_IT_FALLING; + obj->event = EDGE_FALL; + } + } + } else { // Disable + if (event == IRQ_RISE) { + if ((obj->event == EDGE_FALL) || (obj->event == EDGE_BOTH)) { + mode = STM_MODE_IT_FALLING; + obj->event = EDGE_FALL; + } else { // NONE or RISE + mode = STM_MODE_IT_EVT_RESET; + obj->event = EDGE_NONE; + } + } + if (event == IRQ_FALL) { + if ((obj->event == EDGE_RISE) || (obj->event == EDGE_BOTH)) { + mode = STM_MODE_IT_RISING; + obj->event = EDGE_RISE; + } else { // NONE or FALL + mode = STM_MODE_IT_EVT_RESET; + obj->event = EDGE_NONE; + } + } + } + + pin_function(obj->pin, STM_PIN_DATA(mode, pull, 0)); +} + +void gpio_irq_enable(gpio_irq_t *obj) +{ + NVIC_EnableIRQ(obj->irq_n); +} + +void gpio_irq_disable(gpio_irq_t *obj) +{ + NVIC_DisableIRQ(obj->irq_n); + obj->event = EDGE_NONE; +} diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_object.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_object.h new file mode 100644 index 0000000000..684d968757 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/gpio_object.h @@ -0,0 +1,75 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#ifndef MBED_GPIO_OBJECT_H +#define MBED_GPIO_OBJECT_H + +#include "mbed_assert.h" +#include "cmsis.h" +#include "PortNames.h" +#include "PeripheralNames.h" +#include "PinNames.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PinName pin; + uint32_t mask; + __IO uint32_t *reg_in; + __IO uint32_t *reg_set; + __IO uint32_t *reg_clr; +} gpio_t; + +static inline void gpio_write(gpio_t *obj, int value) +{ + MBED_ASSERT(obj->pin != (PinName)NC); + if (value) { + *obj->reg_set = obj->mask; + } else { + *obj->reg_clr = obj->mask; + } +} + +static inline int gpio_read(gpio_t *obj) +{ + MBED_ASSERT(obj->pin != (PinName)NC); + return ((*obj->reg_in & obj->mask) ? 1 : 0); +} + +static inline int gpio_is_connected(const gpio_t *obj) { + return obj->pin != (PinName)NC; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/i2c_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/i2c_api.c new file mode 100644 index 0000000000..dde40d6e52 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/i2c_api.c @@ -0,0 +1,409 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#include "mbed_assert.h" +#include "i2c_api.h" + +#if DEVICE_I2C + +#include "cmsis.h" +#include "pinmap.h" +#include "PeripheralPins.h" + +/* Timeout values for flags and events waiting loops. These timeouts are + not based on accurate values, they just guarantee that the application will + not remain stuck if the I2C communication is corrupted. */ +#define FLAG_TIMEOUT ((int)0x1000) +#define LONG_TIMEOUT ((int)0x8000) + +I2C_HandleTypeDef I2cHandle; + +void i2c_init(i2c_t *obj, PinName sda, PinName scl) +{ + static int i2c1_inited = 0; + static int i2c2_inited = 0; +#if defined(I2C3_BASE) + static int i2c3_inited = 0; +#endif + + // Determine the I2C to use + I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA); + I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL); + + obj->i2c = (I2CName)pinmap_merge(i2c_sda, i2c_scl); + MBED_ASSERT(obj->i2c != (I2CName)NC); + + // Enable I2C1 clock and pinout if not done + if ((obj->i2c == I2C_1) && !i2c1_inited) { + i2c1_inited = 1; + __HAL_RCC_I2C1_CONFIG(RCC_I2C1CLKSOURCE_SYSCLK); + __I2C1_CLK_ENABLE(); + // Configure I2C pins + pinmap_pinout(sda, PinMap_I2C_SDA); + pinmap_pinout(scl, PinMap_I2C_SCL); + pin_mode(sda, OpenDrain); + pin_mode(scl, OpenDrain); + } + + // Enable I2C2 clock and pinout if not done + if ((obj->i2c == I2C_2) && !i2c2_inited) { + i2c2_inited = 1; + __I2C2_CLK_ENABLE(); + // Configure I2C pins + pinmap_pinout(sda, PinMap_I2C_SDA); + pinmap_pinout(scl, PinMap_I2C_SCL); + pin_mode(sda, OpenDrain); + pin_mode(scl, OpenDrain); + } + +#if defined(I2C3_BASE) + // Enable I2C3 clock and pinout if not done + if ((obj->i2c == I2C_3) && !i2c3_inited) { + i2c3_inited = 1; + __I2C3_CLK_ENABLE(); + // Configure I2C pins + pinmap_pinout(sda, PinMap_I2C_SDA); + pinmap_pinout(scl, PinMap_I2C_SCL); + pin_mode(sda, OpenDrain); + pin_mode(scl, OpenDrain); + } +#endif + + // Reset to clear pending flags if any + i2c_reset(obj); + + // I2C configuration + i2c_frequency(obj, 100000); // 100 kHz per default +} + +void i2c_frequency(i2c_t *obj, int hz) +{ + MBED_ASSERT((hz == 100000) || (hz == 400000) || (hz == 1000000)); + I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c); + int timeout; + + // wait before init + timeout = LONG_TIMEOUT; + while ((__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY)) && (timeout-- != 0)); + + // Common settings: I2C clock = 32 MHz, Analog filter = ON, Digital filter coefficient = 0 + switch (hz) { + case 100000: + I2cHandle.Init.Timing = 0x20602938; // Standard mode with Rise Time = 400ns and Fall Time = 100ns + break; + case 400000: + I2cHandle.Init.Timing = 0x00B0122A; // Fast mode with Rise Time = 250ns and Fall Time = 100ns + break; + case 1000000: + I2cHandle.Init.Timing = 0x0030040E; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns + break; + default: + break; + } + + // I2C configuration + I2cHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; + I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; + I2cHandle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; + I2cHandle.Init.OwnAddress1 = 0; + I2cHandle.Init.OwnAddress2 = 0; + I2cHandle.Init.OwnAddress2Masks = I2C_OA2_NOMASK; + HAL_I2C_Init(&I2cHandle); +} + +inline int i2c_start(i2c_t *obj) +{ + I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c); + int timeout; + + I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c); + + // Clear Acknowledge failure flag + __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_AF); + + // Generate the START condition + i2c->CR2 |= I2C_CR2_START; + + // Wait the START condition has been correctly sent + timeout = FLAG_TIMEOUT; + while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == RESET) { + if ((timeout--) == 0) { + return 1; + } + } + + return 0; +} + +inline int i2c_stop(i2c_t *obj) +{ + I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c); + + // Generate the STOP condition + i2c->CR2 |= I2C_CR2_STOP; + + return 0; +} + +int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) +{ + I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c); + I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c); + int timeout; + int count; + int value; + + /* update CR2 register */ + i2c->CR2 = (i2c->CR2 & (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP))) + | (uint32_t)(((uint32_t)address & I2C_CR2_SADD) | (((uint32_t)length << 16) & I2C_CR2_NBYTES) | (uint32_t)I2C_SOFTEND_MODE | (uint32_t)I2C_GENERATE_START_READ); + + // Read all bytes + for (count = 0; count < length; count++) { + value = i2c_byte_read(obj, 0); + data[count] = (char)value; + } + + // Wait transfer complete + timeout = FLAG_TIMEOUT; + while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TC) == RESET) { + timeout--; + if (timeout == 0) { + return -1; + } + } + + __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_TC); + + // If not repeated start, send stop. + if (stop) { + i2c_stop(obj); + /* Wait until STOPF flag is set */ + timeout = FLAG_TIMEOUT; + while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_STOPF) == RESET) { + timeout--; + if (timeout == 0) { + return -1; + } + } + /* Clear STOP Flag */ + __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_STOPF); + } + + return length; +} + +int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) +{ + I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c); + I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c); + int timeout; + int count; + + /* update CR2 register */ + i2c->CR2 = (i2c->CR2 & (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP))) + | (uint32_t)(((uint32_t)address & I2C_CR2_SADD) | (((uint32_t)length << 16) & I2C_CR2_NBYTES) | (uint32_t)I2C_SOFTEND_MODE | (uint32_t)I2C_GENERATE_START_WRITE); + + for (count = 0; count < length; count++) { + i2c_byte_write(obj, data[count]); + } + + // Wait transfer complete + timeout = FLAG_TIMEOUT; + while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TC) == RESET) { + timeout--; + if (timeout == 0) { + return -1; + } + } + + __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_TC); + + // If not repeated start, send stop. + if (stop) { + i2c_stop(obj); + /* Wait until STOPF flag is set */ + timeout = FLAG_TIMEOUT; + while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_STOPF) == RESET) { + timeout--; + if (timeout == 0) { + return -1; + } + } + /* Clear STOP Flag */ + __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_STOPF); + } + + return count; +} + +int i2c_byte_read(i2c_t *obj, int last) +{ + I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c); + int timeout; + + // Wait until the byte is received + timeout = FLAG_TIMEOUT; + while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_RXNE) == RESET) { + if ((timeout--) == 0) { + return -1; + } + } + + return (int)i2c->RXDR; +} + +int i2c_byte_write(i2c_t *obj, int data) +{ + I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c); + int timeout; + + // Wait until the previous byte is transmitted + timeout = FLAG_TIMEOUT; + while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TXIS) == RESET) { + if ((timeout--) == 0) { + return 0; + } + } + + i2c->TXDR = (uint8_t)data; + + return 1; +} + +void i2c_reset(i2c_t *obj) +{ + int timeout; + + // wait before reset + timeout = LONG_TIMEOUT; + while ((__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY)) && (timeout-- != 0)); + + if (obj->i2c == I2C_1) { + __I2C1_FORCE_RESET(); + __I2C1_RELEASE_RESET(); + } + if (obj->i2c == I2C_2) { + __I2C2_FORCE_RESET(); + __I2C2_RELEASE_RESET(); + } +} + +#if DEVICE_I2CSLAVE + +void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) +{ + I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c); + uint16_t tmpreg; + + // disable + i2c->OAR1 &= (uint32_t)(~I2C_OAR1_OA1EN); + // Get the old register value + tmpreg = i2c->OAR1; + // Reset address bits + tmpreg &= 0xFC00; + // Set new address + tmpreg |= (uint16_t)((uint16_t)address & (uint16_t)0x00FE); // 7-bits + // Store the new register value + i2c->OAR1 = tmpreg; + // enable + i2c->OAR1 |= I2C_OAR1_OA1EN; +} + +void i2c_slave_mode(i2c_t *obj, int enable_slave) +{ + + I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c); + uint16_t tmpreg; + + // Get the old register value + tmpreg = i2c->OAR1; + + // Enable / disable slave + if (enable_slave == 1) { + tmpreg |= I2C_OAR1_OA1EN; + } else { + tmpreg &= (uint32_t)(~I2C_OAR1_OA1EN); + } + + // Set new mode + i2c->OAR1 = tmpreg; + +} + +// See I2CSlave.h +#define NoData 0 // the slave has not been addressed +#define ReadAddressed 1 // the master has requested a read from this slave (slave = transmitter) +#define WriteGeneral 2 // the master is writing to all slave +#define WriteAddressed 3 // the master is writing to this slave (slave = receiver) + +int i2c_slave_receive(i2c_t *obj) +{ + I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c); + int retValue = NoData; + + if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == 1) { + if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_ADDR) == 1) { + if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_DIR) == 1) + retValue = ReadAddressed; + else + retValue = WriteAddressed; + __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_ADDR); + } + } + + return (retValue); +} + +int i2c_slave_read(i2c_t *obj, char *data, int length) +{ + char size = 0; + + while (size < length) data[size++] = (char)i2c_byte_read(obj, 0); + + return size; +} + +int i2c_slave_write(i2c_t *obj, const char *data, int length) +{ + char size = 0; + I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c); + + do { + i2c_byte_write(obj, data[size]); + size++; + } while (size < length); + + return size; +} + + +#endif // DEVICE_I2CSLAVE + +#endif // DEVICE_I2C diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/mbed_overrides.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/mbed_overrides.c new file mode 100644 index 0000000000..74ce0cf19d --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/mbed_overrides.c @@ -0,0 +1,35 @@ +/* mbed Microcontroller Library + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "cmsis.h" + +// This function is called after RAM initialization and before main. +void mbed_sdk_init() +{ + // Update the SystemCoreClock variable. + SystemCoreClockUpdate(); +} diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/pinmap.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/pinmap.c new file mode 100644 index 0000000000..91a3186c75 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/pinmap.c @@ -0,0 +1,143 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#include "mbed_assert.h" +#include "pinmap.h" +#include "PortNames.h" +#include "mbed_error.h" + +// GPIO mode look-up table +static const uint32_t gpio_mode[13] = { + 0x00000000, // 0 = GPIO_MODE_INPUT + 0x00000001, // 1 = GPIO_MODE_OUTPUT_PP + 0x00000011, // 2 = GPIO_MODE_OUTPUT_OD + 0x00000002, // 3 = GPIO_MODE_AF_PP + 0x00000012, // 4 = GPIO_MODE_AF_OD + 0x00000003, // 5 = GPIO_MODE_ANALOG + 0x10110000, // 6 = GPIO_MODE_IT_RISING + 0x10210000, // 7 = GPIO_MODE_IT_FALLING + 0x10310000, // 8 = GPIO_MODE_IT_RISING_FALLING + 0x10120000, // 9 = GPIO_MODE_EVT_RISING + 0x10220000, // 10 = GPIO_MODE_EVT_FALLING + 0x10320000, // 11 = GPIO_MODE_EVT_RISING_FALLING + 0x10000000 // 12 = Reset IT and EVT (not in STM32Cube HAL) +}; + +// Enable GPIO clock and return GPIO base address +uint32_t Set_GPIO_Clock(uint32_t port_idx) +{ + uint32_t gpio_add = 0; + switch (port_idx) { + case PortA: + gpio_add = GPIOA_BASE; + __GPIOA_CLK_ENABLE(); + break; + case PortB: + gpio_add = GPIOB_BASE; + __GPIOB_CLK_ENABLE(); + break; + case PortC: + gpio_add = GPIOC_BASE; + __GPIOC_CLK_ENABLE(); + break; + case PortD: + gpio_add = GPIOD_BASE; + __GPIOD_CLK_ENABLE(); + break; + case PortH: + gpio_add = GPIOH_BASE; + __GPIOH_CLK_ENABLE(); + break; + default: + error("Pinmap error: wrong port number."); + break; + } + return gpio_add; +} + +/** + * Configure pin (mode, speed, output type and pull-up/pull-down) + */ +void pin_function(PinName pin, int data) +{ + MBED_ASSERT(pin != (PinName)NC); + // Get the pin informations + uint32_t mode = STM_PIN_MODE(data); + uint32_t pupd = STM_PIN_PUPD(data); + uint32_t afnum = STM_PIN_AFNUM(data); + + uint32_t port_index = STM_PORT(pin); + uint32_t pin_index = STM_PIN(pin); + + // Enable GPIO clock + uint32_t gpio_add = Set_GPIO_Clock(port_index); + GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add; + + // Configure GPIO + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Pin = (uint32_t)(1 << pin_index); + GPIO_InitStructure.Mode = gpio_mode[mode]; + GPIO_InitStructure.Pull = pupd; + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Alternate = afnum; + HAL_GPIO_Init(gpio, &GPIO_InitStructure); + + // [TODO] Disconnect JTAG-DP + SW-DP signals. + // Warning: Need to reconnect under reset + //if ((pin == PA_13) || (pin == PA_14)) { + // + //} + //if ((pin == PA_15) || (pin == PB_3) || (pin == PB_4)) { + // + //} +} + +/** + * Configure pin pull-up/pull-down + */ +void pin_mode(PinName pin, PinMode mode) +{ + MBED_ASSERT(pin != (PinName)NC); + uint32_t port_index = STM_PORT(pin); + uint32_t pin_index = STM_PIN(pin); + + // Enable GPIO clock + uint32_t gpio_add = Set_GPIO_Clock(port_index); + GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add; + + // Configure pull-up/pull-down resistors + uint32_t pupd = (uint32_t)mode; + if (pupd > 2) + { + pupd = 0; // Open-drain = No pull-up/No pull-down + } + gpio->PUPDR &= (uint32_t)(~(GPIO_PUPDR_PUPD0 << (pin_index * 2))); + gpio->PUPDR |= (uint32_t)(pupd << (pin_index * 2)); + +} diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/port_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/port_api.c new file mode 100644 index 0000000000..e982858665 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/port_api.c @@ -0,0 +1,103 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#include "port_api.h" +#include "pinmap.h" +#include "gpio_api.h" +#include "mbed_error.h" + +#if DEVICE_PORTIN || DEVICE_PORTOUT + +extern uint32_t Set_GPIO_Clock(uint32_t port_idx); + +// high nibble = port number (0=A, 1=B, 2=C, 3=D, 4=E, 5=F, ...) +// low nibble = pin number +PinName port_pin(PortName port, int pin_n) +{ + return (PinName)(pin_n + (port << 4)); +} + +void port_init(port_t *obj, PortName port, int mask, PinDirection dir) +{ + uint32_t port_index = (uint32_t)port; + + // Enable GPIO clock + uint32_t gpio_add = Set_GPIO_Clock(port_index); + GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add; + + // Fill PORT object structure for future use + obj->port = port; + obj->mask = mask; + obj->direction = dir; + obj->reg_in = &gpio->IDR; + obj->reg_out = &gpio->ODR; + + port_dir(obj, dir); +} + +void port_dir(port_t *obj, PinDirection dir) +{ + uint32_t i; + obj->direction = dir; + for (i = 0; i < 16; i++) { // Process all pins + if (obj->mask & (1 << i)) { // If the pin is used + if (dir == PIN_OUTPUT) { + pin_function(port_pin(obj->port, i), STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0)); + } else { // PIN_INPUT + pin_function(port_pin(obj->port, i), STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + } + } + } +} + +void port_mode(port_t *obj, PinMode mode) +{ + uint32_t i; + for (i = 0; i < 16; i++) { // Process all pins + if (obj->mask & (1 << i)) { // If the pin is used + pin_mode(port_pin(obj->port, i), mode); + } + } +} + +void port_write(port_t *obj, int value) +{ + *obj->reg_out = (*obj->reg_out & ~obj->mask) | (value & obj->mask); +} + +int port_read(port_t *obj) +{ + if (obj->direction == PIN_OUTPUT) { + return (*obj->reg_out & obj->mask); + } else { // PIN_INPUT + return (*obj->reg_in & obj->mask); + } +} + +#endif diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/pwmout_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/pwmout_api.c new file mode 100644 index 0000000000..a260fa6a55 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/pwmout_api.c @@ -0,0 +1,193 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#include "pwmout_api.h" + +#if DEVICE_PWMOUT + +#include "cmsis.h" +#include "pinmap.h" +#include "mbed_error.h" +#include "PeripheralPins.h" + +static TIM_HandleTypeDef TimHandle; + +void pwmout_init(pwmout_t* obj, PinName pin) +{ + // Get the peripheral name from the pin and assign it to the object + obj->pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM); + + if (obj->pwm == (PWMName)NC) { + error("PWM error: pinout mapping failed."); + } + + // Enable TIM clock + if (obj->pwm == PWM_2) __TIM2_CLK_ENABLE(); +#if defined(TIM3_BASE) + if (obj->pwm == PWM_3) __TIM3_CLK_ENABLE(); +#endif + if (obj->pwm == PWM_21) __TIM21_CLK_ENABLE(); + if (obj->pwm == PWM_22) __TIM22_CLK_ENABLE(); + + // Configure GPIO + pinmap_pinout(pin, PinMap_PWM); + + obj->pin = pin; + obj->period = 0; + obj->pulse = 0; + + pwmout_period_us(obj, 20000); // 20 ms per default +} + +void pwmout_free(pwmout_t* obj) +{ + // Configure GPIO + pin_function(obj->pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); +} + +void pwmout_write(pwmout_t* obj, float value) +{ + TIM_OC_InitTypeDef sConfig; + int channel = 0; + + TimHandle.Instance = (TIM_TypeDef *)(obj->pwm); + + if (value < (float)0.0) { + value = 0.0; + } else if (value > (float)1.0) { + value = 1.0; + } + + obj->pulse = (uint32_t)((float)obj->period * value); + + // Configure channels + sConfig.OCMode = TIM_OCMODE_PWM1; + sConfig.Pulse = obj->pulse; + sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfig.OCFastMode = TIM_OCFAST_ENABLE; + + switch (obj->pin) { + // Channels 1 + case PA_0: + case PA_5: + case PA_6: + case PA_15: + case PB_4: + case PC_6: + channel = TIM_CHANNEL_1; + break; + // Channels 2 + case PA_1: + case PA_7: + case PB_3: + case PB_5: + case PC_7: + channel = TIM_CHANNEL_2; + break; + // Channels 3 + case PA_2: + case PB_0: + case PB_10: + case PC_8: + channel = TIM_CHANNEL_3; + break; + // Channels 4 + case PA_3: + case PB_1: + case PB_11: + case PC_9: + channel = TIM_CHANNEL_4; + break; + default: + return; + } + + HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, channel); + HAL_TIM_PWM_Start(&TimHandle, channel); +} + +float pwmout_read(pwmout_t* obj) +{ + float value = 0; + if (obj->period > 0) { + value = (float)(obj->pulse) / (float)(obj->period); + } + return ((value > (float)1.0) ? (float)(1.0) : (value)); +} + +void pwmout_period(pwmout_t* obj, float seconds) +{ + pwmout_period_us(obj, seconds * 1000000.0f); +} + +void pwmout_period_ms(pwmout_t* obj, int ms) +{ + pwmout_period_us(obj, ms * 1000); +} + +void pwmout_period_us(pwmout_t* obj, int us) +{ + TimHandle.Instance = (TIM_TypeDef *)(obj->pwm); + + float dc = pwmout_read(obj); + + __HAL_TIM_DISABLE(&TimHandle); + + TimHandle.Init.Period = us - 1; + TimHandle.Init.Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1; // 1 us tick + TimHandle.Init.ClockDivision = 0; + TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; + HAL_TIM_PWM_Init(&TimHandle); + + // Set duty cycle again + pwmout_write(obj, dc); + + // Save for future use + obj->period = us; + + __HAL_TIM_ENABLE(&TimHandle); +} + +void pwmout_pulsewidth(pwmout_t* obj, float seconds) +{ + pwmout_pulsewidth_us(obj, seconds * 1000000.0f); +} + +void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) +{ + pwmout_pulsewidth_us(obj, ms * 1000); +} + +void pwmout_pulsewidth_us(pwmout_t* obj, int us) +{ + float value = (float)us / (float)obj->period; + pwmout_write(obj, value); +} + +#endif diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/serial_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/serial_api.c new file mode 100644 index 0000000000..9dc817713b --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/serial_api.c @@ -0,0 +1,406 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#include "mbed_assert.h" +#include "serial_api.h" + +#if DEVICE_SERIAL + +#include "cmsis.h" +#include "pinmap.h" +#include +#include "PeripheralPins.h" + +#define UART_NUM (5) + +static uint32_t serial_irq_ids[UART_NUM] = {0, 0, 0, 0, 0}; + +static uart_irq_handler irq_handler; + +UART_HandleTypeDef UartHandle; + +int stdio_uart_inited = 0; +serial_t stdio_uart; + +static void init_uart(serial_t *obj) +{ + UartHandle.Instance = (USART_TypeDef *)(obj->uart); + + if (obj->uart == LPUART_1) { + UartHandle.Init.BaudRate = obj->baudrate >> 1; + } else { + UartHandle.Init.BaudRate = obj->baudrate; + } + UartHandle.Init.WordLength = obj->databits; + UartHandle.Init.StopBits = obj->stopbits; + UartHandle.Init.Parity = obj->parity; + UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE; + + if (obj->pin_rx == NC) { + UartHandle.Init.Mode = UART_MODE_TX; + } else if (obj->pin_tx == NC) { + UartHandle.Init.Mode = UART_MODE_RX; + } else { + UartHandle.Init.Mode = UART_MODE_TX_RX; + } + + // Disable the reception overrun detection + UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT; + UartHandle.AdvancedInit.OverrunDisable = UART_ADVFEATURE_OVERRUN_DISABLE; + + HAL_UART_Init(&UartHandle); +} + +void serial_init(serial_t *obj, PinName tx, PinName rx) +{ + // Determine the UART to use (UART_1, UART_2, ...) + UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX); + UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX); + + // Get the peripheral name (UART_1, UART_2, ...) from the pin and assign it to the object + obj->uart = (UARTName)pinmap_merge(uart_tx, uart_rx); + MBED_ASSERT(obj->uart != (UARTName)NC); + + // Enable UART clock + if (obj->uart == UART_1) { + __HAL_RCC_USART1_CLK_ENABLE(); + obj->index = 0; + } + + if (obj->uart == UART_2) { + __HAL_RCC_USART2_CLK_ENABLE(); + obj->index = 1; + } + + if (obj->uart == LPUART_1) { + __HAL_RCC_LPUART1_CLK_ENABLE(); + obj->index = 2; + } + +#if defined(USART4_BASE) + if (obj->uart == UART_4) { + __HAL_RCC_USART4_CLK_ENABLE(); + obj->index = 3; + } +#endif + +#if defined(USART5_BASE) + if (obj->uart == UART_5) { + __HAL_RCC_USART5_CLK_ENABLE(); + obj->index = 4; + } +#endif + + // Configure the UART pins + pinmap_pinout(tx, PinMap_UART_TX); + pinmap_pinout(rx, PinMap_UART_RX); + if (tx != NC) { + pin_mode(tx, PullUp); + } + if (rx != NC) { + pin_mode(rx, PullUp); + } + + // Configure UART + obj->baudrate = 9600; + obj->databits = UART_WORDLENGTH_8B; + obj->stopbits = UART_STOPBITS_1; + obj->parity = UART_PARITY_NONE; + obj->pin_tx = tx; + obj->pin_rx = rx; + + init_uart(obj); + + // For stdio management + if (obj->uart == STDIO_UART) { + stdio_uart_inited = 1; + memcpy(&stdio_uart, obj, sizeof(serial_t)); + } +} + +void serial_free(serial_t *obj) +{ + // Reset UART and disable clock + if (obj->uart == UART_1) { + __HAL_RCC_USART1_FORCE_RESET(); + __HAL_RCC_USART1_RELEASE_RESET(); + __HAL_RCC_USART1_CLK_DISABLE(); + } + + if (obj->uart == UART_2) { + __HAL_RCC_USART2_FORCE_RESET(); + __HAL_RCC_USART2_RELEASE_RESET(); + __HAL_RCC_USART2_CLK_DISABLE(); + } + + if (obj->uart == LPUART_1) { + __HAL_RCC_LPUART1_FORCE_RESET(); + __HAL_RCC_LPUART1_RELEASE_RESET(); + __HAL_RCC_LPUART1_CLK_DISABLE(); + } + +#if defined(USART4_BASE) + if (obj->uart == UART_4) { + __HAL_RCC_USART4_FORCE_RESET(); + __HAL_RCC_USART4_RELEASE_RESET(); + __HAL_RCC_USART4_CLK_DISABLE(); + } +#endif + +#if defined(USART5_BASE) + if (obj->uart == UART_5) { + __HAL_RCC_USART5_FORCE_RESET(); + __HAL_RCC_USART5_RELEASE_RESET(); + __HAL_RCC_USART5_CLK_DISABLE(); + } +#endif + + // Configure GPIOs + pin_function(obj->pin_tx, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + pin_function(obj->pin_rx, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + + serial_irq_ids[obj->index] = 0; +} + +void serial_baud(serial_t *obj, int baudrate) +{ + obj->baudrate = baudrate; + init_uart(obj); +} + +void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) +{ + if (data_bits == 9) { + obj->databits = UART_WORDLENGTH_9B; + } else { + obj->databits = UART_WORDLENGTH_8B; + } + + switch (parity) { + case ParityOdd: + case ParityForced0: + obj->parity = UART_PARITY_ODD; + break; + case ParityEven: + case ParityForced1: + obj->parity = UART_PARITY_EVEN; + break; + default: // ParityNone + obj->parity = UART_PARITY_NONE; + break; + } + + if (stop_bits == 2) { + obj->stopbits = UART_STOPBITS_2; + } else { + obj->stopbits = UART_STOPBITS_1; + } + + init_uart(obj); +} + +/****************************************************************************** + * INTERRUPTS HANDLING + ******************************************************************************/ + +static void uart_irq(UARTName name, int id) +{ + UartHandle.Instance = (USART_TypeDef *)name; + if (serial_irq_ids[id] != 0) { + if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_TC) != RESET) { + irq_handler(serial_irq_ids[id], TxIrq); + __HAL_UART_CLEAR_IT(&UartHandle, UART_CLEAR_TCF); + } + if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_RXNE) != RESET) { + irq_handler(serial_irq_ids[id], RxIrq); + volatile uint32_t tmpval = UartHandle.Instance->RDR; // Clear RXNE bit + } + } +} + +static void uart1_irq(void) +{ + uart_irq(UART_1, 0); +} + +static void uart2_irq(void) +{ + uart_irq(UART_2, 1); +} + +static void lpuart1_irq(void) +{ + uart_irq(LPUART_1, 2); +} + +#if defined(USART4_BASE) +static void uart4_irq(void) +{ + uart_irq(UART_4, 3); +} +#endif + +#if defined(USART5_BASE) +static void uart5_irq(void) +{ + uart_irq(UART_5, 4); +} +#endif + +void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) +{ + irq_handler = handler; + serial_irq_ids[obj->index] = id; +} + +void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) +{ + IRQn_Type irq_n = (IRQn_Type)0; + uint32_t vector = 0; + + UartHandle.Instance = (USART_TypeDef *)(obj->uart); + + if (obj->uart == UART_1) { + irq_n = USART1_IRQn; + vector = (uint32_t)&uart1_irq; + } + + if (obj->uart == UART_2) { + irq_n = USART2_IRQn; + vector = (uint32_t)&uart2_irq; + } + + if (obj->uart == LPUART_1) { + irq_n = RNG_LPUART1_IRQn; + vector = (uint32_t)&lpuart1_irq; + } + +#if defined(USART4_BASE) + if (obj->uart == UART_4) { + irq_n = USART4_5_IRQn; + vector = (uint32_t)&uart4_irq; + } +#endif + +#if defined(USART5_BASE) + if (obj->uart == UART_5) { + irq_n = USART4_5_IRQn; + vector = (uint32_t)&uart5_irq; + } +#endif + + if (enable) { + + if (irq == RxIrq) { + __HAL_UART_ENABLE_IT(&UartHandle, UART_IT_RXNE); + } else { // TxIrq + __HAL_UART_ENABLE_IT(&UartHandle, UART_IT_TC); + } + + NVIC_SetVector(irq_n, vector); + NVIC_EnableIRQ(irq_n); + + } else { // disable + + int all_disabled = 0; + + if (irq == RxIrq) { + __HAL_UART_DISABLE_IT(&UartHandle, UART_IT_RXNE); + // Check if TxIrq is disabled too + if ((UartHandle.Instance->CR1 & USART_CR1_TCIE) == 0) all_disabled = 1; + } else { // TxIrq + __HAL_UART_DISABLE_IT(&UartHandle, UART_IT_TC); + // Check if RxIrq is disabled too + if ((UartHandle.Instance->CR1 & USART_CR1_RXNEIE) == 0) all_disabled = 1; + } + + if (all_disabled) NVIC_DisableIRQ(irq_n); + + } +} + +/****************************************************************************** + * READ/WRITE + ******************************************************************************/ + +int serial_getc(serial_t *obj) +{ + USART_TypeDef *uart = (USART_TypeDef *)(obj->uart); + while (!serial_readable(obj)); + return (int)(uart->RDR & (uint32_t)0xFF); +} + +void serial_putc(serial_t *obj, int c) +{ + USART_TypeDef *uart = (USART_TypeDef *)(obj->uart); + while (!serial_writable(obj)); + uart->TDR = (uint32_t)(c & (uint32_t)0xFF); +} + +int serial_readable(serial_t *obj) +{ + int status; + UartHandle.Instance = (USART_TypeDef *)(obj->uart); + // Check if data is received + status = ((__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_RXNE) != RESET) ? 1 : 0); + return status; +} + +int serial_writable(serial_t *obj) +{ + int status; + UartHandle.Instance = (USART_TypeDef *)(obj->uart); + // Check if data is transmitted + status = ((__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_TXE) != RESET) ? 1 : 0); + return status; +} + +void serial_clear(serial_t *obj) +{ + UartHandle.Instance = (USART_TypeDef *)(obj->uart); + __HAL_UART_CLEAR_IT(&UartHandle, UART_CLEAR_TCF); + __HAL_UART_SEND_REQ(&UartHandle, UART_RXDATA_FLUSH_REQUEST); +} + +void serial_pinout_tx(PinName tx) +{ + pinmap_pinout(tx, PinMap_UART_TX); +} + +void serial_break_set(serial_t *obj) +{ + UartHandle.Instance = (USART_TypeDef *)(obj->uart); + __HAL_UART_SEND_REQ(&UartHandle, UART_SENDBREAK_REQUEST); +} + +void serial_break_clear(serial_t *obj) +{ +} + +#endif diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/sleep.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/sleep.c new file mode 100644 index 0000000000..b2830d17f4 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/sleep.c @@ -0,0 +1,61 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#include "sleep_api.h" + +#if DEVICE_SLEEP + +#include "cmsis.h" + +static TIM_HandleTypeDef TimMasterHandle; + +void sleep(void) +{ + TimMasterHandle.Instance = TIM21; + + // Disable HAL tick interrupt + __HAL_TIM_DISABLE_IT(&TimMasterHandle, (TIM_IT_CC2 | TIM_IT_UPDATE)); + + // Request to enter SLEEP mode + HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); + + // Enable HAL tick interrupt + __HAL_TIM_ENABLE_IT(&TimMasterHandle, (TIM_IT_CC2 | TIM_IT_UPDATE)); +} + +void deepsleep(void) +{ + // Request to enter STOP mode with regulator in low power mode + HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); + + // After wake-up from STOP reconfigure the PLL + SetSysClock(); +} + +#endif diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/spi_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/spi_api.c new file mode 100644 index 0000000000..3bca3770cb --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32L0/spi_api.c @@ -0,0 +1,269 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2014, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#include "mbed_assert.h" +#include "spi_api.h" + +#if DEVICE_SPI + +#include +#include "cmsis.h" +#include "pinmap.h" +#include "PeripheralPins.h" + +static SPI_HandleTypeDef SpiHandle; + +static void init_spi(spi_t *obj) +{ + SpiHandle.Instance = (SPI_TypeDef *)(obj->spi); + + __HAL_SPI_DISABLE(&SpiHandle); + + SpiHandle.Init.Mode = obj->mode; + SpiHandle.Init.BaudRatePrescaler = obj->br_presc; + SpiHandle.Init.Direction = SPI_DIRECTION_2LINES; + SpiHandle.Init.CLKPhase = obj->cpha; + SpiHandle.Init.CLKPolarity = obj->cpol; + SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; + SpiHandle.Init.CRCPolynomial = 7; + SpiHandle.Init.DataSize = obj->bits; + SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB; + SpiHandle.Init.NSS = obj->nss; + SpiHandle.Init.TIMode = SPI_TIMODE_DISABLED; + + HAL_SPI_Init(&SpiHandle); + + __HAL_SPI_ENABLE(&SpiHandle); +} + +void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) +{ + // Determine the SPI to use + SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI); + SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO); + SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK); + SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL); + + SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso); + SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel); + + obj->spi = (SPIName)pinmap_merge(spi_data, spi_cntl); + MBED_ASSERT(obj->spi != (SPIName)NC); + + // Enable SPI clock + if (obj->spi == SPI_1) { + __SPI1_CLK_ENABLE(); + } + if (obj->spi == SPI_2) { + __SPI2_CLK_ENABLE(); + } + + // Configure the SPI pins + pinmap_pinout(mosi, PinMap_SPI_MOSI); + pinmap_pinout(miso, PinMap_SPI_MISO); + pinmap_pinout(sclk, PinMap_SPI_SCLK); + + // Save new values + obj->bits = SPI_DATASIZE_8BIT; + obj->cpol = SPI_POLARITY_LOW; + obj->cpha = SPI_PHASE_1EDGE; + obj->br_presc = SPI_BAUDRATEPRESCALER_256; + + obj->pin_miso = miso; + obj->pin_mosi = mosi; + obj->pin_sclk = sclk; + obj->pin_ssel = ssel; + + if (ssel == NC) { // SW NSS Master mode + obj->mode = SPI_MODE_MASTER; + obj->nss = SPI_NSS_SOFT; + } else { // Slave + pinmap_pinout(ssel, PinMap_SPI_SSEL); + obj->mode = SPI_MODE_SLAVE; + obj->nss = SPI_NSS_HARD_INPUT; + } + + init_spi(obj); +} + +void spi_free(spi_t *obj) +{ + // Reset SPI and disable clock + if (obj->spi == SPI_1) { + __SPI1_FORCE_RESET(); + __SPI1_RELEASE_RESET(); + __SPI1_CLK_DISABLE(); + } + + if (obj->spi == SPI_2) { + __SPI2_FORCE_RESET(); + __SPI2_RELEASE_RESET(); + __SPI2_CLK_DISABLE(); + } + + // Configure GPIO + pin_function(obj->pin_miso, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + pin_function(obj->pin_mosi, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + pin_function(obj->pin_sclk, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + pin_function(obj->pin_ssel, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); +} + +void spi_format(spi_t *obj, int bits, int mode, int slave) +{ + // Save new values + if (bits == 16) { + obj->bits = SPI_DATASIZE_16BIT; + } else { + obj->bits = SPI_DATASIZE_8BIT; + } + + switch (mode) { + case 0: + obj->cpol = SPI_POLARITY_LOW; + obj->cpha = SPI_PHASE_1EDGE; + break; + case 1: + obj->cpol = SPI_POLARITY_LOW; + obj->cpha = SPI_PHASE_2EDGE; + break; + case 2: + obj->cpol = SPI_POLARITY_HIGH; + obj->cpha = SPI_PHASE_1EDGE; + break; + default: + obj->cpol = SPI_POLARITY_HIGH; + obj->cpha = SPI_PHASE_2EDGE; + break; + } + + if (slave == 0) { + obj->mode = SPI_MODE_MASTER; + obj->nss = SPI_NSS_SOFT; + } else { + obj->mode = SPI_MODE_SLAVE; + obj->nss = SPI_NSS_HARD_INPUT; + } + + init_spi(obj); +} + +void spi_frequency(spi_t *obj, int hz) +{ + // Note: The frequencies are obtained with SPI1 clock = 32 MHz (APB2 clock) + if (hz < 250000) { + obj->br_presc = SPI_BAUDRATEPRESCALER_256; // 125 kHz + } else if ((hz >= 250000) && (hz < 500000)) { + obj->br_presc = SPI_BAUDRATEPRESCALER_128; // 250 kHz + } else if ((hz >= 500000) && (hz < 1000000)) { + obj->br_presc = SPI_BAUDRATEPRESCALER_64; // 500 kHz + } else if ((hz >= 1000000) && (hz < 2000000)) { + obj->br_presc = SPI_BAUDRATEPRESCALER_32; // 1 MHz + } else if ((hz >= 2000000) && (hz < 4000000)) { + obj->br_presc = SPI_BAUDRATEPRESCALER_16; // 2 MHz + } else if ((hz >= 4000000) && (hz < 8000000)) { + obj->br_presc = SPI_BAUDRATEPRESCALER_8; // 4 MHz + } else if ((hz >= 8000000) && (hz < 16000000)) { + obj->br_presc = SPI_BAUDRATEPRESCALER_4; // 8 MHz + } else { // >= 16000000 + obj->br_presc = SPI_BAUDRATEPRESCALER_2; // 16 MHz + } + init_spi(obj); +} + +static inline int ssp_readable(spi_t *obj) +{ + int status; + SpiHandle.Instance = (SPI_TypeDef *)(obj->spi); + // Check if data is received + status = ((__HAL_SPI_GET_FLAG(&SpiHandle, SPI_FLAG_RXNE) != RESET) ? 1 : 0); + return status; +} + +static inline int ssp_writeable(spi_t *obj) +{ + int status; + SpiHandle.Instance = (SPI_TypeDef *)(obj->spi); + // Check if data is transmitted + status = ((__HAL_SPI_GET_FLAG(&SpiHandle, SPI_FLAG_TXE) != RESET) ? 1 : 0); + return status; +} + +static inline void ssp_write(spi_t *obj, int value) +{ + SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi); + while (!ssp_writeable(obj)); + spi->DR = (uint16_t)value; +} + +static inline int ssp_read(spi_t *obj) +{ + SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi); + while (!ssp_readable(obj)); + return (int)spi->DR; +} + +static inline int ssp_busy(spi_t *obj) +{ + int status; + SpiHandle.Instance = (SPI_TypeDef *)(obj->spi); + status = ((__HAL_SPI_GET_FLAG(&SpiHandle, SPI_FLAG_BSY) != RESET) ? 1 : 0); + return status; +} + +int spi_master_write(spi_t *obj, int value) +{ + ssp_write(obj, value); + return ssp_read(obj); +} + +int spi_slave_receive(spi_t *obj) +{ + return (ssp_readable(obj) ? 1 : 0); +}; + +int spi_slave_read(spi_t *obj) +{ + SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi); + while (!ssp_readable(obj)); + return (int)spi->DR; +} + +void spi_slave_write(spi_t *obj, int value) +{ + SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi); + while (!ssp_writeable(obj)); + spi->DR = (uint16_t)value; +} + +int spi_busy(spi_t *obj) +{ + return ssp_busy(obj); +} + +#endif