mirror of https://github.com/ARMmbed/mbed-os.git
[BEETLE] Add initial Beetle HAL files
This patch adds support for BEETLE SoC Target into the HAL layer. It contains: * Beetle Platform Configuration * I2C API * SPI API * Serial API * Port API * us Ticker API Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>pull/1852/head
parent
44be0626a6
commit
09b5551d41
|
@ -0,0 +1,82 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 MBED_PERIPHERALNAMES_H
|
||||
#define MBED_PERIPHERALNAMES_H
|
||||
|
||||
#include "cmsis.h"
|
||||
#include "i2c_def.h"
|
||||
#include "spi_def.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
UART_0 = (int)CMSDK_UART0_BASE,
|
||||
UART_1 = (int)CMSDK_UART1_BASE
|
||||
} UARTName;
|
||||
|
||||
typedef enum {
|
||||
I2C_0 = (int)I2C0_BASE,
|
||||
I2C_1 = (int)I2C1_BASE
|
||||
|
||||
} I2CName;
|
||||
|
||||
typedef enum {
|
||||
ADC0_0 = 0,
|
||||
ADC0_1,
|
||||
ADC0_2,
|
||||
ADC0_3,
|
||||
ADC0_4,
|
||||
ADC0_5
|
||||
} ADCName;
|
||||
|
||||
typedef enum {
|
||||
SPI_0 = (int)SPI0_BASE,
|
||||
SPI_1 = (int)SPI1_BASE
|
||||
} SPIName;
|
||||
|
||||
typedef enum {
|
||||
PWM_1 = 0,
|
||||
PWM_2,
|
||||
PWM_3,
|
||||
PWM_4,
|
||||
PWM_5,
|
||||
PWM_6,
|
||||
PWM_7,
|
||||
PWM_8,
|
||||
PWM_9,
|
||||
PWM_10,
|
||||
PWM_11
|
||||
} PWMName;
|
||||
|
||||
#define STDIO_UART_TX UART_TX1
|
||||
#define STDIO_UART_RX UART_RX1
|
||||
#define STDIO_UART UART_1
|
||||
|
||||
#define MBED_UART0 UART_TX0, UART_RX0
|
||||
#define MBED_UART1 UART_TX1, UART_RX1
|
||||
#define MBED_UARTUSB UART_TX1, UART_RX1
|
||||
|
||||
//USB UART
|
||||
#define USBTX UART_TX1
|
||||
#define USBRX UART_RX1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,151 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 MBED_PINNAMES_H
|
||||
#define MBED_PINNAMES_H
|
||||
|
||||
#include "cmsis.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
PIN_INPUT,
|
||||
PIN_OUTPUT
|
||||
} PinDirection;
|
||||
|
||||
#define PORT_SHIFT 5
|
||||
|
||||
typedef enum {
|
||||
/* BEETLE Pin Names */
|
||||
/* GPIO0 */
|
||||
P0_0 = 0,
|
||||
P0_1 = 1,
|
||||
P0_2 = 2,
|
||||
P0_3 = 3,
|
||||
P0_4 = 4,
|
||||
P0_5 = 5,
|
||||
P0_6 = 6,
|
||||
P0_7 = 7,
|
||||
P0_8 = 8,
|
||||
P0_9 = 9,
|
||||
P0_10 = 10,
|
||||
P0_11 = 11,
|
||||
P0_12 = 12,
|
||||
P0_13 = 13,
|
||||
P0_14 = 14,
|
||||
P0_15 = 15,
|
||||
|
||||
/* GPIO1 */
|
||||
P1_0 = 16,
|
||||
P1_1 = 17,
|
||||
P1_2 = 18,
|
||||
P1_3 = 19,
|
||||
P1_4 = 20,
|
||||
P1_5 = 21,
|
||||
P1_6 = 22,
|
||||
P1_7 = 23,
|
||||
P1_8 = 24,
|
||||
P1_9 = 25,
|
||||
P1_10 = 26,
|
||||
P1_11 = 27,
|
||||
P1_12 = 28,
|
||||
P1_13 = 29,
|
||||
P1_14 = 30,
|
||||
P1_15 = 31,
|
||||
|
||||
/* Arduino Connector Namings */
|
||||
A0 = 600,
|
||||
A1 = 601,
|
||||
A2 = 602,
|
||||
A3 = 603,
|
||||
A4 = 604,
|
||||
A5 = 605,
|
||||
D0 = P0_0,
|
||||
D1 = P0_1,
|
||||
D2 = P0_2,
|
||||
D3 = P0_3,
|
||||
D4 = P0_4,
|
||||
D5 = P0_5,
|
||||
D6 = P0_6,
|
||||
D7 = P0_7,
|
||||
D8 = P0_8,
|
||||
D9 = P0_9,
|
||||
D10 = P0_10,
|
||||
D11 = P0_11,
|
||||
D12 = P0_12,
|
||||
D13 = P0_13,
|
||||
D14 = P0_14,
|
||||
D15 = P0_15,
|
||||
|
||||
/* TRACE Ports */
|
||||
TRACECLK = P0_2,
|
||||
TRACED0 = P0_6,
|
||||
TRACED1 = P0_7,
|
||||
TRACED2 = P0_8,
|
||||
TRACED3 = P0_9,
|
||||
|
||||
/* Other BEETLE Pin Names */
|
||||
|
||||
//Shield SPI
|
||||
SHIELD_SPI_SCK = 320,
|
||||
SHIELD_SPI_MOSI = 321,
|
||||
SHIELD_SPI_MISO = 322,
|
||||
SHIELD_SPI_nCS = 323,
|
||||
|
||||
//ADC SPI
|
||||
ADC_SPI_MOSI = 650,
|
||||
ADC_SPI_MISO = 651,
|
||||
ADC_SPI_SCK = 652,
|
||||
ADC_SPI_nCS = 653,
|
||||
|
||||
//Uart
|
||||
UART_TX0 = 400,
|
||||
UART_RX0 = 401,
|
||||
UART_TX1 = 402,
|
||||
UART_RX1 = 403,
|
||||
|
||||
//Shield I2C
|
||||
SHIELD_SDA = 504,
|
||||
SHIELD_SCL = 505,
|
||||
|
||||
// Internal I2C for temperature and acceleromter sensor
|
||||
SENSOR_SDA = 506,
|
||||
SENSOR_SCL = 507,
|
||||
|
||||
// Not connected
|
||||
NC = (int)0xFFFFFFFF,
|
||||
// LEDS not connected
|
||||
LED1 = NC,
|
||||
LED2 = NC,
|
||||
LED3 = NC,
|
||||
LED4 = NC,
|
||||
} PinName;
|
||||
|
||||
typedef enum {
|
||||
PullUp = 2,
|
||||
PullDown = 1,
|
||||
PullNone = 0,
|
||||
Repeater = 3,
|
||||
OpenDrain = 4,
|
||||
PullDefault = PullDown
|
||||
} PinMode;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 MBED_PORTNAMES_H
|
||||
#define MBED_PORTNAMES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
Port0 = 0,
|
||||
Port1 = 1
|
||||
} PortName;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* PackageLicenseDeclared: Apache-2.0
|
||||
* Copyright (c) 2016 ARM Limited
|
||||
*
|
||||
* 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 "cmsis.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "wait_api.h"
|
||||
#include "analogin_api.h"
|
||||
#include "gpio_api.h"
|
||||
#include "spi_api.h"
|
||||
#include "pinmap.h"
|
||||
|
||||
#if DEVICE_ANALOGIN
|
||||
|
||||
/*
|
||||
* Channel Address for the next acquisition:
|
||||
* XXAAAXXX XXXXXXXX
|
||||
*/
|
||||
#define ADC_SPI_ADDRESS 11
|
||||
|
||||
/* ADC Resolution */
|
||||
#define ADC_RESOLUTION 0xFFF
|
||||
|
||||
/* ADC Voltage Divider */
|
||||
#define ADC_DIV 819.0
|
||||
|
||||
/* PinMap structure for ADC IN */
|
||||
static const PinMap PinMap_ADC[] = {
|
||||
{A0, ADC0_0, 0},
|
||||
{A1, ADC0_1, 0},
|
||||
{A2, ADC0_2, 0},
|
||||
{A3, ADC0_3, 0},
|
||||
{A4, ADC0_4, 0},
|
||||
{A5, ADC0_5, 0},
|
||||
{NC, NC, 0}
|
||||
};
|
||||
|
||||
/* ADC SPI Private Data */
|
||||
typedef struct {
|
||||
/* ADC SPI */
|
||||
spi_t analogin_spi;
|
||||
/* ADC SPI CS */
|
||||
gpio_t adc_spi_cs_gpio;
|
||||
/* ADC SPI State */
|
||||
uint32_t analog_spi_inited;
|
||||
} analogin_spi_t;
|
||||
/* ADC SPI Device */
|
||||
static analogin_spi_t analogin_spi_dev;
|
||||
|
||||
/*
|
||||
* ADC SPI CS
|
||||
*/
|
||||
#define ADC_SPI_CS P1_2
|
||||
|
||||
/*
|
||||
* Initialize the analogin peripheral
|
||||
* Configures the pin used by analogin.
|
||||
* obj: The analogin object to initialize
|
||||
* pin: The analogin pin name
|
||||
*/
|
||||
void analogin_init(analogin_t *obj, PinName pin)
|
||||
{
|
||||
/* Initialize ADC Pin */
|
||||
obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
|
||||
/* Verify if pin is valid */
|
||||
MBED_ASSERT(obj->adc != (ADCName)NC);
|
||||
|
||||
/* Initialize the ADC SPI */
|
||||
if(analogin_spi_dev.analog_spi_inited == 0){
|
||||
/* Initialize SPI for ADC */
|
||||
spi_init(&(analogin_spi_dev.analogin_spi), ADC_SPI_MOSI,
|
||||
ADC_SPI_MISO, ADC_SPI_SCK, ADC_SPI_nCS);
|
||||
spi_format(&(analogin_spi_dev.analogin_spi), 16, 3, 0);
|
||||
/* Set SPI to MAX Freq */
|
||||
spi_frequency(&(analogin_spi_dev.analogin_spi), 0);
|
||||
|
||||
/* Initialize CS GPIO */
|
||||
gpio_init_out(&(analogin_spi_dev.adc_spi_cs_gpio), ADC_SPI_CS);
|
||||
|
||||
analogin_spi_dev.analog_spi_inited = 1;
|
||||
}
|
||||
|
||||
/* If pin is valid assign it to the ADC data structure */
|
||||
obj->pin = pin;
|
||||
obj->pin_number = pin-600;
|
||||
obj->address = (0x0000 | (pin-600));
|
||||
|
||||
/* Configure the pinout */
|
||||
pinmap_pinout(pin, PinMap_ADC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the value from analogin pin, represented as an unsigned 16bit value
|
||||
* obj: The analogin object
|
||||
* @return: An unsigned 16bit value representing the current input voltage
|
||||
*/
|
||||
uint16_t analogin_read_u16(analogin_t *obj)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
|
||||
/*
|
||||
* The ADC SPI hw is 8 bit format, 16 bit emulation is required
|
||||
* in the SPI driver.
|
||||
*/
|
||||
/* CS = 1 */
|
||||
gpio_write(&(analogin_spi_dev.adc_spi_cs_gpio), 1);
|
||||
/* Do the first read */
|
||||
(void)spi_master_write(&(analogin_spi_dev.analogin_spi),
|
||||
((obj->pin_number) << ADC_SPI_ADDRESS));
|
||||
/* CS = 0 */
|
||||
gpio_write(&(analogin_spi_dev.adc_spi_cs_gpio), 0);
|
||||
/* Wait 50 us */
|
||||
wait_us(50);
|
||||
/* CS = 1 */
|
||||
gpio_write(&(analogin_spi_dev.adc_spi_cs_gpio), 1);
|
||||
/* The second read provides the result */
|
||||
result = spi_master_write(&(analogin_spi_dev.analogin_spi),
|
||||
((obj->pin_number) << ADC_SPI_ADDRESS));
|
||||
/* CS = 0 */
|
||||
gpio_write(&(analogin_spi_dev.adc_spi_cs_gpio), 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the input voltage, represented as a float in the range [0.0, 1.0]
|
||||
* obj: The analogin object
|
||||
* @return: A floating value representing the current input voltage
|
||||
*/
|
||||
float analogin_read(analogin_t *obj)
|
||||
{
|
||||
uint16_t result = analogin_read_u16(obj);
|
||||
return (float)((result & ADC_RESOLUTION) * 1.0f) / ADC_DIV;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,21 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 MBED_DEVICE_H
|
||||
#define MBED_DEVICE_H
|
||||
|
||||
#include "objects.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,86 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 "gpio_api.h"
|
||||
#include "pinmap.h"
|
||||
|
||||
// function to enable the GPIO pin
|
||||
uint32_t gpio_set(PinName pin) {
|
||||
uint32_t pin_value = 0;
|
||||
|
||||
if(pin <= 15) {
|
||||
pin_value = pin;
|
||||
} else if (pin >= 16 && pin <= 31) {
|
||||
pin_value = pin-16;
|
||||
}
|
||||
|
||||
pin_function(pin, 0);
|
||||
|
||||
return (1 << pin_value);
|
||||
}
|
||||
|
||||
//function to initialise the gpio pin
|
||||
// this links the board control bits for each pin
|
||||
// with the object created for the pin
|
||||
void gpio_init(gpio_t *obj, PinName pin) {
|
||||
if (pin == NC) {
|
||||
return;
|
||||
} else {
|
||||
int pin_value = 0;
|
||||
obj->pin = pin;
|
||||
if (pin <=15) {
|
||||
pin_value = pin;
|
||||
} else if (pin >= 16 && pin <= 31) {
|
||||
pin_value = pin-16;
|
||||
}
|
||||
|
||||
obj->mask = 0x1 << pin_value;
|
||||
obj->pin_number = pin;
|
||||
if (pin <=15) {
|
||||
obj->reg_data = &CMSDK_GPIO0->DATAOUT;
|
||||
obj->reg_in = &CMSDK_GPIO0->DATA;
|
||||
obj->reg_dir = &CMSDK_GPIO0->OUTENABLESET;
|
||||
obj->reg_dirclr = &CMSDK_GPIO0->OUTENABLECLR;
|
||||
} else if (pin >= 16 && pin <= 31) {
|
||||
obj->reg_data = &CMSDK_GPIO1->DATAOUT;
|
||||
obj->reg_in = &CMSDK_GPIO1->DATA;
|
||||
obj->reg_dir = &CMSDK_GPIO1->OUTENABLESET;
|
||||
obj->reg_dirclr = &CMSDK_GPIO1->OUTENABLECLR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_mode(gpio_t *obj, PinMode mode) {
|
||||
pin_mode(obj->pin, mode);
|
||||
}
|
||||
|
||||
void gpio_dir(gpio_t *obj, PinDirection direction) {
|
||||
if(obj->pin >= 0 && obj->pin <= 31) {
|
||||
switch (direction) {
|
||||
case PIN_INPUT : *obj->reg_dirclr = obj->mask; break;
|
||||
case PIN_OUTPUT: *obj->reg_dir |= obj->mask; break;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int gpio_is_connected(const gpio_t *obj){
|
||||
if(obj->pin != (PinName)NC){
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 <stddef.h>
|
||||
#include "cmsis.h"
|
||||
#include "gpio_irq_api.h"
|
||||
#include "mbed_error.h"
|
||||
|
||||
#define CHANNEL_NUM 32
|
||||
#define CMSDK_GPIO_0 CMSDK_GPIO0
|
||||
#define CMSDK_GPIO_1 CMSDK_GPIO1
|
||||
#define PININT_IRQ 0
|
||||
|
||||
static uint32_t channel_ids[CHANNEL_NUM] = {0};
|
||||
static gpio_irq_handler irq_handler;
|
||||
|
||||
static inline void handle_interrupt_in(uint32_t channel) {
|
||||
uint32_t ch_bit = (1 << channel);
|
||||
// Return immediately if:
|
||||
// * The interrupt was already served
|
||||
// * There is no user handler
|
||||
// * It is a level interrupt, not an edge interrupt
|
||||
if (ch_bit <16){
|
||||
if (((CMSDK_GPIO_0->INTSTATUS) == 0) || (channel_ids[channel] == 0)
|
||||
|| ((CMSDK_GPIO_0->INTTYPESET) == 0))
|
||||
return;
|
||||
|
||||
if ((CMSDK_GPIO_0->INTTYPESET & ch_bit)
|
||||
&& (CMSDK_GPIO_0->INTPOLSET & ch_bit)) {
|
||||
irq_handler(channel_ids[channel], IRQ_RISE);
|
||||
CMSDK_GPIO_0->INTPOLSET = ch_bit;
|
||||
}
|
||||
if ((CMSDK_GPIO_0->INTTYPESET & ch_bit)
|
||||
&& ~(CMSDK_GPIO_0->INTPOLSET & ch_bit)) {
|
||||
irq_handler(channel_ids[channel], IRQ_FALL);
|
||||
}
|
||||
CMSDK_GPIO_0->INTCLEAR = ch_bit;
|
||||
}
|
||||
|
||||
if (ch_bit>=16) {
|
||||
if (((CMSDK_GPIO_1->INTSTATUS) == 0) || (channel_ids[channel] == 0)
|
||||
|| ((CMSDK_GPIO_1->INTTYPESET) == 0))
|
||||
return;
|
||||
|
||||
if ((CMSDK_GPIO_1->INTTYPESET & ch_bit)
|
||||
&& (CMSDK_GPIO_1->INTPOLSET & ch_bit)) {
|
||||
irq_handler(channel_ids[channel], IRQ_RISE);
|
||||
CMSDK_GPIO_1->INTPOLSET = ch_bit;
|
||||
}
|
||||
if ((CMSDK_GPIO_1->INTTYPESET & ch_bit)
|
||||
&& ~(CMSDK_GPIO_1->INTPOLSET & ch_bit)) {
|
||||
irq_handler(channel_ids[channel], IRQ_FALL);
|
||||
}
|
||||
CMSDK_GPIO_1->INTCLEAR = ch_bit;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio0_irq0(void) {
|
||||
handle_interrupt_in(0);
|
||||
}
|
||||
|
||||
void gpio0_irq1(void) {
|
||||
handle_interrupt_in(1);
|
||||
}
|
||||
|
||||
void gpio0_irq2(void) {
|
||||
handle_interrupt_in(2);
|
||||
}
|
||||
|
||||
void gpio0_irq3(void) {
|
||||
handle_interrupt_in(3);
|
||||
}
|
||||
|
||||
void gpio0_irq4(void) {
|
||||
handle_interrupt_in(4);
|
||||
}
|
||||
|
||||
void gpio0_irq5(void) {
|
||||
handle_interrupt_in(5);
|
||||
}
|
||||
|
||||
void gpio0_irq6(void) {
|
||||
handle_interrupt_in(6);
|
||||
}
|
||||
|
||||
void gpio0_irq7(void) {
|
||||
handle_interrupt_in(7);
|
||||
}
|
||||
|
||||
void gpio0_irq8(void) {
|
||||
handle_interrupt_in(8);
|
||||
}
|
||||
|
||||
void gpio0_irq9(void) {
|
||||
handle_interrupt_in(9);
|
||||
}
|
||||
|
||||
void gpio0_irq10(void) {
|
||||
handle_interrupt_in(10);
|
||||
}
|
||||
|
||||
void gpio0_irq11(void) {
|
||||
handle_interrupt_in(11);
|
||||
}
|
||||
|
||||
void gpio0_irq12(void) {
|
||||
handle_interrupt_in(12);
|
||||
}
|
||||
|
||||
void gpio0_irq13(void) {
|
||||
handle_interrupt_in(13);
|
||||
}
|
||||
|
||||
void gpio0_irq14(void) {
|
||||
handle_interrupt_in(14);
|
||||
}
|
||||
|
||||
void gpio0_irq15(void) {
|
||||
handle_interrupt_in(15);
|
||||
}
|
||||
|
||||
void gpio1_irq0(void) {
|
||||
handle_interrupt_in(16);
|
||||
}
|
||||
|
||||
void gpio1_irq1(void) {
|
||||
handle_interrupt_in(17);
|
||||
}
|
||||
|
||||
void gpio1_irq2(void) {
|
||||
handle_interrupt_in(18);
|
||||
}
|
||||
|
||||
void gpio1_irq3(void) {
|
||||
handle_interrupt_in(19);
|
||||
}
|
||||
|
||||
void gpio1_irq4(void) {
|
||||
handle_interrupt_in(20);
|
||||
}
|
||||
|
||||
void gpio1_irq5(void) {
|
||||
handle_interrupt_in(21);
|
||||
}
|
||||
|
||||
void gpio1_irq6(void) {
|
||||
handle_interrupt_in(22);
|
||||
}
|
||||
|
||||
void gpio1_irq7(void) {
|
||||
handle_interrupt_in(23);
|
||||
}
|
||||
|
||||
void gpio1_irq8(void) {
|
||||
handle_interrupt_in(24);
|
||||
}
|
||||
|
||||
void gpio1_irq9(void) {
|
||||
handle_interrupt_in(25);
|
||||
}
|
||||
|
||||
void gpio1_irq10(void) {
|
||||
handle_interrupt_in(26);
|
||||
}
|
||||
|
||||
void gpio1_irq11(void) {
|
||||
handle_interrupt_in(27);
|
||||
}
|
||||
|
||||
void gpio1_irq12(void) {
|
||||
handle_interrupt_in(28);
|
||||
}
|
||||
|
||||
void gpio1_irq13(void) {
|
||||
handle_interrupt_in(29);
|
||||
}
|
||||
|
||||
void gpio1_irq14(void) {
|
||||
handle_interrupt_in(30);
|
||||
}
|
||||
|
||||
void gpio1_irq15(void) {
|
||||
handle_interrupt_in(31);
|
||||
}
|
||||
|
||||
int gpio_irq_init(gpio_irq_t *obj, PinName pin,
|
||||
gpio_irq_handler handler, uint32_t id) {
|
||||
if (pin == NC) {return -1;}
|
||||
else {
|
||||
|
||||
irq_handler = handler;
|
||||
|
||||
int found_free_channel = 0;
|
||||
int i = 0;
|
||||
for (i=0; i<CHANNEL_NUM; i++) {
|
||||
if (channel_ids[i] == 0) {
|
||||
channel_ids[i] = id;
|
||||
obj->ch = i;
|
||||
found_free_channel = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found_free_channel)
|
||||
return -1;
|
||||
/* To select a pin for any of the eight pin interrupts, write the pin number
|
||||
* as 0 to 23 for pins PIO0_0 to PIO0_23 and 24 to 55.
|
||||
* @see: mbed_capi/PinNames.h
|
||||
*/
|
||||
if (pin <16) {
|
||||
CMSDK_GPIO_0->INTENSET |= (0x1 << pin);
|
||||
}
|
||||
|
||||
if (pin >= 16) {
|
||||
CMSDK_GPIO_1->INTENSET |= (0x1 << pin);
|
||||
}
|
||||
|
||||
void (*channels_irq)(void) = NULL;
|
||||
switch (obj->ch) {
|
||||
case 0:
|
||||
channels_irq = &gpio0_irq0;
|
||||
break;
|
||||
case 1:
|
||||
channels_irq = &gpio0_irq1;
|
||||
break;
|
||||
case 2:
|
||||
channels_irq = &gpio0_irq2;
|
||||
break;
|
||||
case 3:
|
||||
channels_irq = &gpio0_irq3;
|
||||
break;
|
||||
case 4:
|
||||
channels_irq = &gpio0_irq4;
|
||||
break;
|
||||
case 5:
|
||||
channels_irq = &gpio0_irq5;
|
||||
break;
|
||||
case 6:
|
||||
channels_irq = &gpio0_irq6;
|
||||
break;
|
||||
case 7:
|
||||
channels_irq = &gpio0_irq7;
|
||||
break;
|
||||
case 8:
|
||||
channels_irq = &gpio0_irq8;
|
||||
break;
|
||||
case 9:
|
||||
channels_irq = &gpio0_irq9;
|
||||
break;
|
||||
case 10:
|
||||
channels_irq = &gpio0_irq10;
|
||||
break;
|
||||
case 11:
|
||||
channels_irq = &gpio0_irq11;
|
||||
break;
|
||||
case 12:
|
||||
channels_irq = &gpio0_irq12;
|
||||
break;
|
||||
case 13:
|
||||
channels_irq = &gpio0_irq13;
|
||||
break;
|
||||
case 14:
|
||||
channels_irq = &gpio0_irq14;
|
||||
break;
|
||||
case 15:
|
||||
channels_irq = &gpio0_irq15;
|
||||
break;
|
||||
case 16:
|
||||
channels_irq = &gpio1_irq0;
|
||||
break;
|
||||
case 17:
|
||||
channels_irq = &gpio1_irq1;
|
||||
break;
|
||||
case 18:
|
||||
channels_irq = &gpio1_irq2;
|
||||
break;
|
||||
case 19:
|
||||
channels_irq = &gpio1_irq3;
|
||||
break;
|
||||
case 20:
|
||||
channels_irq = &gpio1_irq4;
|
||||
break;
|
||||
case 21:
|
||||
channels_irq = &gpio1_irq5;
|
||||
break;
|
||||
case 22:
|
||||
channels_irq = &gpio1_irq6;
|
||||
break;
|
||||
case 23:
|
||||
channels_irq = &gpio1_irq7;
|
||||
break;
|
||||
case 24:
|
||||
channels_irq = &gpio1_irq8;
|
||||
break;
|
||||
case 25:
|
||||
channels_irq = &gpio1_irq9;
|
||||
break;
|
||||
case 26:
|
||||
channels_irq = &gpio1_irq10;
|
||||
break;
|
||||
case 27:
|
||||
channels_irq = &gpio1_irq11;
|
||||
break;
|
||||
case 28:
|
||||
channels_irq = &gpio1_irq12;
|
||||
break;
|
||||
case 29:
|
||||
channels_irq = &gpio1_irq13;
|
||||
break;
|
||||
case 30:
|
||||
channels_irq = &gpio1_irq14;
|
||||
break;
|
||||
case 31:
|
||||
channels_irq = &gpio1_irq15;
|
||||
break;
|
||||
}
|
||||
NVIC_SetVector((IRQn_Type)(PININT_IRQ + obj->ch),
|
||||
(uint32_t)channels_irq);
|
||||
NVIC_EnableIRQ((IRQn_Type)(PININT_IRQ + obj->ch));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_free(gpio_irq_t *obj) {
|
||||
}
|
||||
|
||||
void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
||||
unsigned int ch_bit = (1 << obj->ch);
|
||||
|
||||
// Clear interrupt
|
||||
if (obj->ch <16) {
|
||||
if (!(CMSDK_GPIO_0->INTTYPESET & ch_bit)) {
|
||||
CMSDK_GPIO_0->INTCLEAR = ch_bit;
|
||||
}
|
||||
}
|
||||
if (obj->ch >= 16) {
|
||||
if (!(CMSDK_GPIO_1->INTTYPESET & ch_bit)) {
|
||||
CMSDK_GPIO_1->INTCLEAR = ch_bit;
|
||||
}
|
||||
}
|
||||
|
||||
// Edge trigger
|
||||
if (obj->ch <16) {
|
||||
CMSDK_GPIO_0->INTTYPESET &= ch_bit;
|
||||
if (event == IRQ_RISE) {
|
||||
CMSDK_GPIO_0->INTPOLSET |= ch_bit;
|
||||
if (enable) {
|
||||
CMSDK_GPIO_0->INTENSET |= ch_bit;
|
||||
} else {
|
||||
CMSDK_GPIO_0->INTENCLR |= ch_bit;
|
||||
}
|
||||
} else {
|
||||
CMSDK_GPIO_0->INTPOLCLR |= ch_bit;
|
||||
if (enable) {
|
||||
CMSDK_GPIO_0->INTENSET |= ch_bit;
|
||||
} else {
|
||||
CMSDK_GPIO_0->INTENCLR |= ch_bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (obj->ch >= 16) {
|
||||
CMSDK_GPIO_1->INTTYPESET &= ch_bit;
|
||||
if (event == IRQ_RISE) {
|
||||
CMSDK_GPIO_1->INTPOLSET |= ch_bit;
|
||||
if (enable) {
|
||||
CMSDK_GPIO_1->INTENSET |= ch_bit;
|
||||
} else {
|
||||
CMSDK_GPIO_1->INTENCLR |= ch_bit;
|
||||
}
|
||||
} else {
|
||||
CMSDK_GPIO_1->INTPOLCLR |= ch_bit;
|
||||
if (enable) {
|
||||
CMSDK_GPIO_1->INTENSET |= ch_bit;
|
||||
} else {
|
||||
CMSDK_GPIO_1->INTENCLR |= ch_bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
NVIC_EnableIRQ((IRQn_Type)(PININT_IRQ + obj->ch));
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
NVIC_DisableIRQ((IRQn_Type)(PININT_IRQ + obj->ch));
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 MBED_GPIO_OBJECT_H
|
||||
#define MBED_GPIO_OBJECT_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;
|
||||
uint32_t pin_number;
|
||||
|
||||
__IO uint32_t *reg_dir;
|
||||
__IO uint32_t *reg_dirclr;
|
||||
__IO uint32_t *reg_data;
|
||||
__I uint32_t *reg_in;
|
||||
} gpio_t;
|
||||
|
||||
static inline void gpio_write(gpio_t *obj, int value) {
|
||||
if (value == 1){
|
||||
*obj->reg_data |= (obj->mask);
|
||||
} else if (value == 0){
|
||||
*obj->reg_data &= ~(obj->mask);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int gpio_read(gpio_t *obj) {
|
||||
return ((*obj->reg_in & obj->mask) ? 1 : 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,508 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 "i2c_api.h"
|
||||
#include "i2c_def.h"
|
||||
#include "cmsis.h"
|
||||
#include "pinmap.h"
|
||||
#include "mbed_error.h"
|
||||
#include "wait_api.h"
|
||||
/* States of a possibly combined I2C transfer */
|
||||
typedef enum i2c_transfer_state_t {
|
||||
I2C_TRANSFER_SINGLE, /* Non combined transfer */
|
||||
I2C_TRANSFER_COMBINED_FIRST_MESSAGE, /*
|
||||
* First message of a
|
||||
* combined transfer
|
||||
*/
|
||||
I2C_TRANSFER_COMBINED_INTERMEDIATE_MESSAGE, /*
|
||||
* Message in the middle
|
||||
* of a combined
|
||||
* transfer
|
||||
*/
|
||||
I2C_TRANSFER_COMBINED_LAST_MESSAGE, /*
|
||||
* Last message of a combined
|
||||
* transfer
|
||||
*/
|
||||
} i2c_transfer_state_t;
|
||||
|
||||
/*
|
||||
* Driver private data structure that should not be shared by multiple
|
||||
* instances of the driver
|
||||
* (same driver for multiple instances of the IP)
|
||||
*/
|
||||
typedef struct private_i2c_t {
|
||||
/* State of a possibly combined ongoing i2c transfer */
|
||||
i2c_transfer_state_t transfer_state;
|
||||
}private_i2c_t;
|
||||
|
||||
|
||||
/*
|
||||
* Retrieve the private data of the instance related to a given IP
|
||||
*/
|
||||
static private_i2c_t* get_i2c_private(i2c_t *obj) {
|
||||
static private_i2c_t data0, data1;
|
||||
/*
|
||||
* Select which instance to give using the base
|
||||
* address of registers
|
||||
*/
|
||||
switch((intptr_t)obj->i2c) {
|
||||
case I2C0_BASE:
|
||||
return &data0;
|
||||
case I2C1_BASE:
|
||||
return &data1;
|
||||
default:
|
||||
error("i2c driver private data structure not found for this registers base address");
|
||||
return (void*)0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Infer the current state of a possibly combined transfer
|
||||
* (repeated restart) from the current state and the "stop" parameter
|
||||
* of read and write functions
|
||||
* MUST be called ONCE AND ONLY ONCE at the beginning of i2c transfer
|
||||
* functions (read and write)
|
||||
*/
|
||||
static i2c_transfer_state_t update_transfer_state(i2c_t *obj, int stop) {
|
||||
private_i2c_t* private_data = get_i2c_private(obj);
|
||||
i2c_transfer_state_t *state = &private_data->transfer_state;
|
||||
|
||||
/*
|
||||
* Choose the current and next state depending on the current state
|
||||
* This basically implements rising and falling edge detection on
|
||||
* "stop" variable
|
||||
*/
|
||||
switch(*state) {
|
||||
/* This is the default state for non restarted repeat transfer */
|
||||
default:
|
||||
case I2C_TRANSFER_SINGLE: /* Not a combined transfer */
|
||||
if (stop) {
|
||||
*state = I2C_TRANSFER_SINGLE;
|
||||
} else {
|
||||
*state = I2C_TRANSFER_COMBINED_FIRST_MESSAGE;
|
||||
}
|
||||
break;
|
||||
|
||||
/* First message of a combined transfer */
|
||||
case I2C_TRANSFER_COMBINED_FIRST_MESSAGE:
|
||||
/* Message in the middle of a combined transfer */
|
||||
case I2C_TRANSFER_COMBINED_INTERMEDIATE_MESSAGE:
|
||||
if (stop) {
|
||||
*state = I2C_TRANSFER_COMBINED_LAST_MESSAGE;
|
||||
} else {
|
||||
*state = I2C_TRANSFER_COMBINED_INTERMEDIATE_MESSAGE;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Last message of a combined transfer */
|
||||
case I2C_TRANSFER_COMBINED_LAST_MESSAGE:
|
||||
if (stop) {
|
||||
*state = I2C_TRANSFER_SINGLE;
|
||||
} else {
|
||||
*state = I2C_TRANSFER_COMBINED_FIRST_MESSAGE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return *state;
|
||||
}
|
||||
|
||||
|
||||
static const PinMap PinMap_I2C_SDA[] = {
|
||||
{SHIELD_SDA, I2C_0, 0},
|
||||
{SENSOR_SDA, I2C_1, 0},
|
||||
{NC, NC , 0}
|
||||
};
|
||||
|
||||
static const PinMap PinMap_I2C_SCL[] = {
|
||||
{SHIELD_SCL, I2C_0, 0},
|
||||
{SENSOR_SCL, I2C_1, 0},
|
||||
{NC, NC, 0}
|
||||
};
|
||||
|
||||
static void clear_isr(i2c_t *obj) {
|
||||
/*
|
||||
* Writing to the IRQ status register clears set bits. Therefore, to
|
||||
* clear indiscriminately, just read the register and write it back.
|
||||
*/
|
||||
uint32_t reg = obj->i2c->IRQ_STATUS;
|
||||
obj->i2c->IRQ_STATUS = reg;
|
||||
}
|
||||
|
||||
void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
|
||||
/* 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 = (I2C_TypeDef *)pinmap_merge(i2c_sda, i2c_scl);
|
||||
|
||||
if ((int)obj->i2c == NC) {
|
||||
error("I2C pin mapping failed");
|
||||
}
|
||||
|
||||
pinmap_pinout(sda, PinMap_I2C_SDA);
|
||||
pinmap_pinout(scl, PinMap_I2C_SCL);
|
||||
|
||||
/*
|
||||
* Default configuration:
|
||||
* - MS : Master mode
|
||||
* - NEA : Normal (7-bit) addressing
|
||||
* - ACKEN : Send ACKs when reading from slave
|
||||
* - CLR_FIFO : Not a configuration bit => clears the FIFO
|
||||
*/
|
||||
uint32_t reg = I2C_CTRL_MS | \
|
||||
I2C_CTRL_NEA | \
|
||||
I2C_CTRL_ACKEN | \
|
||||
I2C_CTRL_CLR_FIFO;
|
||||
|
||||
obj->i2c->CONTROL = reg;
|
||||
|
||||
get_i2c_private(obj)->transfer_state = I2C_TRANSFER_SINGLE;
|
||||
|
||||
i2c_frequency(obj, 100000); /* Default to 100kHz SCL frequency */
|
||||
}
|
||||
|
||||
int i2c_start(i2c_t *obj) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_stop(i2c_t *obj) {
|
||||
/* Clear the hardware FIFO */
|
||||
obj->i2c->CONTROL |= I2C_CTRL_CLR_FIFO;
|
||||
/* Clear the HOLD bit used for performing combined transfers */
|
||||
obj->i2c->CONTROL &= ~I2C_CTRL_HOLD;
|
||||
/* Reset the transfer size (read and write) */
|
||||
obj->i2c->TRANSFER_SIZE = 0;
|
||||
/* Clear interrupts */
|
||||
clear_isr(obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i2c_frequency(i2c_t *obj, int hz) {
|
||||
/*
|
||||
* Divider is split in two halfs : A and B
|
||||
* A is 2 bits wide and B is 6 bits wide
|
||||
* The Fscl frequency (SCL clock) is calculated with the following
|
||||
* equation:
|
||||
* Fscl=SystemCoreClock/(22*(A+1)*(B+1))
|
||||
* Here, we only calculate the B divisor which already enables a
|
||||
* wide enough range of values
|
||||
*/
|
||||
uint32_t divisor_a = 0; /* Could be changed if a wider range of hz
|
||||
is needed */
|
||||
uint32_t divisor_b = (SystemCoreClock / (22.0 * hz)) - 1;
|
||||
|
||||
/* Clamp the divisors to their maximal value */
|
||||
divisor_a = divisor_a > I2C_CTRL_DIVISOR_A_BIT_MASK ?
|
||||
I2C_CTRL_DIVISOR_A_BIT_MASK : divisor_a;
|
||||
divisor_b = divisor_b > I2C_CTRL_DIVISOR_B_BIT_MASK ?
|
||||
I2C_CTRL_DIVISOR_B_BIT_MASK : divisor_b;
|
||||
|
||||
uint8_t divisor_combinded = (divisor_a & I2C_CTRL_DIVISOR_A_BIT_MASK)
|
||||
| (divisor_b & I2C_CTRL_DIVISOR_B_BIT_MASK);
|
||||
|
||||
obj->i2c->CONTROL = (obj->i2c->CONTROL & ~I2C_CTRL_DIVISORS)
|
||||
| (divisor_combinded << I2C_CTRL_DIVISOR_OFFSET);
|
||||
}
|
||||
|
||||
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
|
||||
int bytes_read = 0;
|
||||
int length_backup = length;
|
||||
char *data_backup = data;
|
||||
obj->last_xfer_address = address;
|
||||
i2c_transfer_state_t transfer_state = update_transfer_state(obj, stop);
|
||||
|
||||
/* Try to write until it finally succeed or times out */
|
||||
int main_timeout = 10;
|
||||
int retry = 0;
|
||||
do {
|
||||
main_timeout--;
|
||||
|
||||
retry = 0;
|
||||
bytes_read = 0;
|
||||
length = length_backup;
|
||||
data = data_backup;
|
||||
|
||||
uint32_t reg = obj->i2c->CONTROL & 0xff7f;
|
||||
reg |= I2C_CTRL_RW | \
|
||||
I2C_CTRL_CLR_FIFO;
|
||||
/*
|
||||
* Only touch the HOLD bit at the beginning of
|
||||
* (possibly combined) transactions
|
||||
*/
|
||||
if(transfer_state == I2C_TRANSFER_COMBINED_FIRST_MESSAGE
|
||||
|| transfer_state == I2C_TRANSFER_SINGLE) {
|
||||
|
||||
reg |= I2C_CTRL_HOLD;
|
||||
}
|
||||
obj->i2c->CONTROL = reg;
|
||||
|
||||
/* Set the expected number of bytes to be received */
|
||||
if (length > I2C_TRANSFER_SIZE) {
|
||||
error("I2C transfer size too big for the FIFO");
|
||||
}
|
||||
obj->i2c->TRANSFER_SIZE = length & I2C_TRANSFER_SIZE;
|
||||
|
||||
clear_isr(obj);
|
||||
|
||||
/*
|
||||
* Start the transaction by writing address.
|
||||
* Discard the lower bit as it is automatically set
|
||||
* by the controller based on I2C_CTRL_RW bit in CONTROL
|
||||
* register
|
||||
*/
|
||||
obj->i2c->ADDRESS = (address & 0xFF) >> 1;
|
||||
|
||||
if(transfer_state == I2C_TRANSFER_COMBINED_LAST_MESSAGE
|
||||
|| transfer_state == I2C_TRANSFER_SINGLE) {
|
||||
|
||||
/* Clear the hold bit before reading the DATA register */
|
||||
obj->i2c->CONTROL &= ~I2C_CTRL_HOLD;
|
||||
}
|
||||
|
||||
/* Wait for completion of the address transfer */
|
||||
int completion_timeout = 1000;
|
||||
while (completion_timeout) {
|
||||
completion_timeout--;
|
||||
|
||||
uint32_t irq_status = obj->i2c->IRQ_STATUS;
|
||||
if (irq_status & I2C_IRQ_NACK
|
||||
|| irq_status & I2C_IRQ_ARB_LOST) {
|
||||
|
||||
retry = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(irq_status & I2C_IRQ_COMP) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If retry, jump to the beginning and try again */
|
||||
if (retry || !completion_timeout) {
|
||||
retry = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
clear_isr(obj);
|
||||
|
||||
/* Read the data from the DATA register */
|
||||
completion_timeout = 1000;
|
||||
while (length && completion_timeout) {
|
||||
completion_timeout--;
|
||||
|
||||
uint32_t irq_status = obj->i2c->IRQ_STATUS;
|
||||
uint32_t status = obj->i2c->STATUS;
|
||||
|
||||
if(irq_status & I2C_IRQ_NACK ||
|
||||
irq_status & I2C_IRQ_ARB_LOST) {
|
||||
|
||||
retry = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just wait for RXDV because COMP is only risen at the end
|
||||
* of the transfer
|
||||
*/
|
||||
if (status & I2C_STATUS_RXDV) {
|
||||
*data++ = obj->i2c->DATA & 0xFF;
|
||||
length--;
|
||||
bytes_read++;
|
||||
}
|
||||
|
||||
if (irq_status & I2C_IRQ_RX_UNF) {
|
||||
error("Reading more bytes than the I2C transfer size");
|
||||
retry = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If retry, jump to the beginning and try again */
|
||||
if (retry || !completion_timeout) {
|
||||
retry = 1;
|
||||
continue;
|
||||
}
|
||||
} while(retry && main_timeout);
|
||||
|
||||
if (!main_timeout) {
|
||||
bytes_read = 0;
|
||||
data = data_backup;
|
||||
}
|
||||
|
||||
obj->i2c->CONTROL |= I2C_CTRL_CLR_FIFO;
|
||||
clear_isr(obj);
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
int i2c_write(i2c_t *obj, int address, const char *data, int length,
|
||||
int stop) {
|
||||
|
||||
int bytes_written = 0;
|
||||
int length_backup = length;
|
||||
const char *data_backup = data;
|
||||
obj->last_xfer_address = address;
|
||||
i2c_transfer_state_t transfer_state = update_transfer_state(obj, stop);
|
||||
|
||||
/* Try to write until it finally succeed or times out */
|
||||
int main_timeout = 10;
|
||||
int retry = 0;
|
||||
do {
|
||||
main_timeout--;
|
||||
|
||||
retry = 0;
|
||||
bytes_written = 0;
|
||||
length = length_backup;
|
||||
data = data_backup;
|
||||
|
||||
/* Read the defined bits in the control register */
|
||||
uint32_t reg = obj->i2c->CONTROL & 0xff7f;
|
||||
reg |= I2C_CTRL_CLR_FIFO;
|
||||
reg &= ~I2C_CTRL_RW;
|
||||
|
||||
/*
|
||||
* Only touch the HOLD bit at the beginning of
|
||||
* (possibly combined) transactions
|
||||
*/
|
||||
if(transfer_state == I2C_TRANSFER_COMBINED_FIRST_MESSAGE
|
||||
|| transfer_state == I2C_TRANSFER_SINGLE) {
|
||||
|
||||
reg |= I2C_CTRL_HOLD;
|
||||
}
|
||||
obj->i2c->CONTROL = reg;
|
||||
|
||||
clear_isr(obj);
|
||||
|
||||
/* Set the expected number of bytes to be transmitted */
|
||||
if (length > I2C_TRANSFER_SIZE) {
|
||||
error("I2C transfer size too big for the FIFO");
|
||||
}
|
||||
|
||||
/* Set the expected number of bytes to be transmitted */
|
||||
obj->i2c->TRANSFER_SIZE = length & I2C_TRANSFER_SIZE;
|
||||
|
||||
/*
|
||||
* Write the address, triggering the start of the transfer
|
||||
* Discard the lower bit as it is automatically set
|
||||
* by the controller based on I2C_CTRL_RW bit in CONTROL
|
||||
* register
|
||||
*/
|
||||
obj->i2c->ADDRESS = (address & 0xFF) >> 1;
|
||||
|
||||
/* Send the data bytes */
|
||||
int write_timeout = 1000 + length;
|
||||
while (length && write_timeout) {
|
||||
write_timeout--;
|
||||
uint32_t irq_status = obj->i2c->IRQ_STATUS;
|
||||
/* If overflow, undo last step */
|
||||
if (irq_status & I2C_IRQ_TX_OVF) {
|
||||
*data--;
|
||||
length++;
|
||||
bytes_written--;
|
||||
/* Clear the bit by writing 1 to it */
|
||||
obj->i2c->IRQ_STATUS |= I2C_IRQ_TX_OVF;
|
||||
}
|
||||
|
||||
if (irq_status & I2C_IRQ_NACK
|
||||
|| irq_status & I2C_IRQ_ARB_LOST) {
|
||||
|
||||
retry = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
obj->i2c->DATA = *data++;
|
||||
length--;
|
||||
bytes_written++;
|
||||
}
|
||||
|
||||
/* If retry, jump to the beginning and try again */
|
||||
if (retry || !write_timeout) {
|
||||
retry = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(transfer_state == I2C_TRANSFER_COMBINED_LAST_MESSAGE
|
||||
|| transfer_state == I2C_TRANSFER_SINGLE) {
|
||||
/*
|
||||
* Clear the hold bit to signify the end
|
||||
* of the write sequence
|
||||
*/
|
||||
obj->i2c->CONTROL &= ~I2C_CTRL_HOLD;
|
||||
}
|
||||
|
||||
|
||||
/* Wait for transfer completion */
|
||||
int completion_timeout = 1000;
|
||||
while (completion_timeout) {
|
||||
completion_timeout--;
|
||||
|
||||
uint32_t irq_status = obj->i2c->IRQ_STATUS;
|
||||
if(irq_status & I2C_IRQ_NACK
|
||||
|| irq_status & I2C_IRQ_ARB_LOST) {
|
||||
retry = 1;
|
||||
break;
|
||||
}
|
||||
if(irq_status & I2C_IRQ_COMP) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If retry, jump to the beginning and try again */
|
||||
if (retry || !completion_timeout) {
|
||||
continue;
|
||||
}
|
||||
|
||||
obj->i2c->CONTROL |= I2C_CTRL_CLR_FIFO;
|
||||
clear_isr(obj);
|
||||
} while(retry && main_timeout);
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
void i2c_reset(i2c_t *obj) {
|
||||
i2c_stop(obj);
|
||||
}
|
||||
|
||||
int i2c_byte_read(i2c_t *obj, int last) {
|
||||
char i2c_ret = 0;
|
||||
i2c_read(obj, obj->last_xfer_address, &i2c_ret, 1, last);
|
||||
return i2c_ret;
|
||||
}
|
||||
|
||||
int i2c_byte_write(i2c_t *obj, int data) {
|
||||
/* Store the number of written bytes */
|
||||
uint32_t wb = i2c_write(obj, obj->last_xfer_address, (char*)&data, 1, 0);
|
||||
if (wb == 1)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i2c_slave_mode(i2c_t *obj, int enable_slave) {
|
||||
}
|
||||
|
||||
int i2c_slave_receive(i2c_t *obj) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_slave_read(i2c_t *obj, char *data, int length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_slave_write(i2c_t *obj, const char *data, int length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* I2C interface Support
|
||||
* =====================
|
||||
*/
|
||||
|
||||
#ifndef MBED_I2C_DEF_H
|
||||
#define MBED_I2C_DEF_H
|
||||
|
||||
#include <stdint.h> /* standard types definitions */
|
||||
|
||||
typedef struct beetle_i2c
|
||||
{
|
||||
__IO uint32_t CONTROL; /* RW Control register */
|
||||
__I uint32_t STATUS; /* RO Status register */
|
||||
__IO uint32_t ADDRESS; /* RW I2C address register */
|
||||
__IO uint32_t DATA; /* RW I2C data register */
|
||||
__IO uint32_t IRQ_STATUS; /* RO Interrupt status register ( read only but write to clear bits) */
|
||||
__IO uint32_t TRANSFER_SIZE; /* RW Transfer size register */
|
||||
__IO uint32_t SLAVE_MONITOR; /* RW Slave monitor pause register */
|
||||
__IO uint32_t TIMEOUT; /* RW Time out register */
|
||||
__I uint32_t IRQ_MASK; /* RO Interrupt mask register */
|
||||
__O uint32_t IRQ_ENABLE; /* WO Interrupt enable register */
|
||||
__O uint32_t IRQ_DISABLE; /* WO Interrupt disable register */
|
||||
|
||||
}I2C_TypeDef;
|
||||
|
||||
#define I2C0_BASE (0x40007000ul) /* Shield Header I2C Base Address */
|
||||
#define I2C1_BASE (0x4000E000ul) /* Onboard I2C Base Address */
|
||||
|
||||
#define SHIELD_I2C ((I2C_TypeDef *) I2C0_BASE )
|
||||
#define BOARD_I2C ((I2C_TypeDef *) I2C1_BASE )
|
||||
|
||||
/* Control Register Masks */
|
||||
#define I2C_CTRL_RW 0x0001 /* Transfer direction */
|
||||
#define I2C_CTRL_MS 0x0002 /* Mode (master / slave) */
|
||||
#define I2C_CTRL_NEA 0x0004 /* Addressing mode */
|
||||
#define I2C_CTRL_ACKEN 0x0008 /* ACK enable */
|
||||
#define I2C_CTRL_HOLD 0x0010 /* Clock hold enable */
|
||||
#define I2C_SLVMON 0x0020 /* Slave monitor mode */
|
||||
#define I2C_CTRL_CLR_FIFO 0x0040 /* Force clear of FIFO */
|
||||
#define I2C_CTRL_DIVISOR_B 0x3F00 /* Stage B clock divider */
|
||||
#define I2C_CTRL_DIVISOR_A 0xA000 /* Stage A clock divider */
|
||||
#define I2C_CTRL_DIVISORS 0xFF00 /* Combined A and B fields */
|
||||
#define I2C_CTRL_DIVISOR_OFFSET 8 /* Offset of the clock divisor in
|
||||
* the CONTROL register
|
||||
*/
|
||||
#define I2C_CTRL_DIVISOR_A_BIT_MASK 0x03
|
||||
/*
|
||||
* First part of the clock
|
||||
* divisor in the CONTROL register
|
||||
*/
|
||||
#define I2C_CTRL_DIVISOR_B_BIT_MASK 0x3F
|
||||
/*
|
||||
* Second part of the clock
|
||||
* divisor in the CONTROL register
|
||||
*/
|
||||
|
||||
/* Status Register Masks */
|
||||
#define I2C_STATUS_RXRW 0x0008 /* Mode of transmission from master */
|
||||
#define I2C_STATUS_RXDV 0x0020 /* Valid data waiting to be read */
|
||||
#define I2C_STATUS_TXDV 0x0040 /* Still a data byte to be sent */
|
||||
#define I2C_STATUS_RXOVF 0x0080 /* Receiver overflow */
|
||||
#define I2C_STATUS_BA 0x0100 /* Bus active */
|
||||
|
||||
/* Address Register Masks */
|
||||
#define I2C_ADDRESS_7BIT 0x007F
|
||||
|
||||
/* Interrupt Status / Enable / Disable Register Masks */
|
||||
#define I2C_IRQ_COMP 0x0001 /* Transfer complete */
|
||||
#define I2C_IRQ_DATA 0x0002 /* More data */
|
||||
#define I2C_IRQ_NACK 0x0004 /* Transfer not acknowledged */
|
||||
#define I2C_IRQ_TO 0x0008 /* Transfer timed out */
|
||||
#define I2C_IRQ_SLV_RDY 0x0010 /* Monitored slave ready */
|
||||
#define I2C_IRQ_RX_OVF 0x0020 /* Receive overflow */
|
||||
#define I2C_IRQ_TX_OVF 0x0040 /* Transmit overflow */
|
||||
#define I2C_IRQ_RX_UNF 0x0080 /* Receive underflow */
|
||||
#define I2C_IRQ_ARB_LOST 0x0200 /* Arbitration lost */
|
||||
|
||||
/* Transfer Size Register Masks */
|
||||
#define I2C_TRANSFER_SIZE 0xFF
|
||||
|
||||
/* Error codes */
|
||||
#define E_SUCCESS 0x0
|
||||
#define E_INCOMPLETE_DATA 0x1
|
||||
|
||||
#endif
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* PackageLicenseDeclared: Apache-2.0
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 "cmsis.h"
|
||||
#include "device.h"
|
||||
#include "objects.h"
|
||||
#include "lp_ticker_api.h"
|
||||
|
||||
/* Private lp_ticker data */
|
||||
/* lp_ticker initialize */
|
||||
static uint32_t lp_ticker_initialized = 0;
|
||||
/* lp_ticker reload value */
|
||||
static uint32_t lp_ticker_reload = 0x0; /* Max Value */
|
||||
/* Store Overflow Count */
|
||||
static uint32_t lp_ticker_overflows_count = 0;
|
||||
|
||||
#if DEVICE_LOWPOWERTIMER
|
||||
/**
|
||||
* Interrupt Handler
|
||||
*/
|
||||
void __lp_ticker_irq_handler(void)
|
||||
{
|
||||
if (DualTimer_GetIRQInfo(DUALTIMER0) == SINGLETIMER2) {
|
||||
DualTimer_ClearInterrupt(DUALTIMER0);
|
||||
lp_ticker_overflows_count++;
|
||||
} else {
|
||||
lp_ticker_irq_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the low power ticker
|
||||
*/
|
||||
void lp_ticker_init(void)
|
||||
{
|
||||
uint32_t lp_ticker_irqn = 0;
|
||||
/* Verify if lp_ticker has been already Initialized */
|
||||
if (lp_ticker_initialized == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lp_ticker_initialized = 1;
|
||||
|
||||
/* Dualtimer Initialize */
|
||||
DualTimer_Initialize(DUALTIMER0, lp_ticker_reload);
|
||||
/* Dualtimer Enable */
|
||||
DualTimer_Enable(DUALTIMER0, DUALTIMER_COUNT_32
|
||||
//| DUALTIMER_PERIODIC
|
||||
);
|
||||
/* DualTimer get IRQn */
|
||||
lp_ticker_irqn = DualTimer_GetIRQn(DUALTIMER0);
|
||||
/* Enable lp_ticker IRQ */
|
||||
NVIC_SetVector((IRQn_Type)lp_ticker_irqn,
|
||||
(uint32_t)__lp_ticker_irq_handler);
|
||||
NVIC_EnableIRQ((IRQn_Type)lp_ticker_irqn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current counter
|
||||
* @return: The current timer's counter value in microseconds
|
||||
*/
|
||||
uint32_t lp_ticker_read(void)
|
||||
{
|
||||
uint32_t microseconds = 0;
|
||||
|
||||
/* Verify if lp_ticker has not been Initialized */
|
||||
if (lp_ticker_initialized == 0)
|
||||
lp_ticker_init();
|
||||
|
||||
/* Read Timer Value */
|
||||
microseconds = DualTimer_Read_2(DUALTIMER0);
|
||||
|
||||
return microseconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set interrupt for specified timestamp
|
||||
* timestamp: The time in microseconds to be set
|
||||
*/
|
||||
void lp_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
int32_t delta = 0;
|
||||
|
||||
/* Verify if lp_ticker has been not Initialized */
|
||||
if (lp_ticker_initialized == 0)
|
||||
lp_ticker_init();
|
||||
|
||||
/* Calculate the delta */
|
||||
delta = (int32_t)(timestamp - lp_ticker_read());
|
||||
/* Check if the event was in the past */
|
||||
if (delta <= 0) {
|
||||
/* This event was in the past */
|
||||
DualTimer_SetInterrupt_1(DUALTIMER0, 0,
|
||||
DUALTIMER_COUNT_32 | DUALTIMER_ONESHOT);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable interrupt on SingleTimer1 */
|
||||
DualTimer_SetInterrupt_1(DUALTIMER0, delta,
|
||||
DUALTIMER_COUNT_32 | DUALTIMER_ONESHOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable low power ticker interrupt
|
||||
*/
|
||||
void lp_ticker_disable_interrupt(void)
|
||||
{
|
||||
/* Disable Interrupt */
|
||||
DualTimer_DisableInterrupt(DUALTIMER0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the low power ticker interrupt
|
||||
*/
|
||||
void lp_ticker_clear_interrupt(void)
|
||||
{
|
||||
/* Clear Interrupt */
|
||||
DualTimer_ClearInterrupt(DUALTIMER0);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 "cmsis.h"
|
||||
|
||||
void mbed_sdk_init(void) {
|
||||
/* Beetle System Power Config */
|
||||
SystemPowerConfig();
|
||||
|
||||
/* Config EFlash Controller Clock */
|
||||
EFlash_Initialize();
|
||||
|
||||
/* Initialize Flash Cache */
|
||||
FCache_Initialize();
|
||||
FCache_Enable(1);
|
||||
FCache_Invalidate();
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 MBED_OBJECTS_H
|
||||
#define MBED_OBJECTS_H
|
||||
|
||||
#include "cmsis.h"
|
||||
#include "PortNames.h"
|
||||
#include "PeripheralNames.h"
|
||||
#include "PinNames.h"
|
||||
#include "i2c_def.h"
|
||||
#include "spi_def.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct gpio_irq_s {
|
||||
uint32_t ch;
|
||||
};
|
||||
|
||||
struct port_s {
|
||||
__IO uint32_t *reg_dir;
|
||||
__IO uint32_t *reg_dirclr;
|
||||
__IO uint32_t *reg_out;
|
||||
__IO uint32_t *reg_in;
|
||||
PortName port;
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
struct serial_s {
|
||||
CMSDK_UART_TypeDef *uart;
|
||||
int index;
|
||||
};
|
||||
|
||||
struct i2c_s {
|
||||
I2C_TypeDef *i2c;
|
||||
uint16_t last_xfer_address;
|
||||
};
|
||||
|
||||
struct spi_s {
|
||||
SPI_TypeDef *spi;
|
||||
};
|
||||
|
||||
struct analogin_s {
|
||||
ADCName adc;
|
||||
PinName pin;
|
||||
uint32_t pin_number;
|
||||
__IO uint32_t address;
|
||||
};
|
||||
|
||||
#include "gpio_object.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,27 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 "mbed_assert.h"
|
||||
#include "pinmap.h"
|
||||
#include "mbed_error.h"
|
||||
|
||||
void pin_function(PinName pin, int function) {
|
||||
MBED_ASSERT(pin != (PinName)NC);
|
||||
|
||||
}
|
||||
|
||||
void pin_mode(PinName pin, PinMode mode) {
|
||||
MBED_ASSERT(pin != (PinName)NC);
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 "port_api.h"
|
||||
#include "pinmap.h"
|
||||
#include "gpio_api.h"
|
||||
|
||||
PinName port_pin(PortName port, int pin_n) {
|
||||
return (PinName)((port << PORT_SHIFT) | pin_n);
|
||||
}
|
||||
|
||||
void port_init(port_t *obj, PortName port, int mask, PinDirection dir) {
|
||||
obj->port = port;
|
||||
obj->mask = mask;
|
||||
|
||||
CMSDK_GPIO_TypeDef *port_reg =
|
||||
(CMSDK_GPIO_TypeDef *)(CMSDK_GPIO0_BASE + ((int)port * 0x10));
|
||||
|
||||
obj->reg_in = &port_reg->DATAOUT;
|
||||
obj->reg_dir = &port_reg->OUTENABLESET;
|
||||
obj->reg_dirclr = &port_reg->OUTENABLECLR;
|
||||
|
||||
uint32_t i;
|
||||
// The function is set per pin: reuse gpio logic
|
||||
for (i=0; i<16; i++) {
|
||||
if (obj->mask & (1<<i)) {
|
||||
gpio_set(port_pin(obj->port, i));
|
||||
}
|
||||
}
|
||||
|
||||
port_dir(obj, dir);
|
||||
}
|
||||
|
||||
void port_mode(port_t *obj, PinMode mode) {
|
||||
uint32_t i;
|
||||
// The mode is set per pin: reuse pinmap logic
|
||||
for (i=0; i<32; i++) {
|
||||
if (obj->mask & (1<<i)) {
|
||||
pin_mode(port_pin(obj->port, i), mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void port_dir(port_t *obj, PinDirection dir) {
|
||||
switch (dir) {
|
||||
case PIN_INPUT : *obj->reg_dir &= ~obj->mask; break;
|
||||
case PIN_OUTPUT: *obj->reg_dir |= obj->mask; break;
|
||||
}
|
||||
}
|
||||
|
||||
void port_write(port_t *obj, int value) {
|
||||
*obj->reg_in = value;
|
||||
}
|
||||
|
||||
int port_read(port_t *obj) {
|
||||
return (*obj->reg_in);
|
||||
}
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// math.h required for floating point operations for baud rate calculation
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "serial_api.h"
|
||||
#include "cmsis.h"
|
||||
#include "pinmap.h"
|
||||
#include "PinNames.h"
|
||||
#include "mbed_error.h"
|
||||
#include "gpio_api.h"
|
||||
|
||||
/******************************************************************************
|
||||
* INITIALIZATION
|
||||
******************************************************************************/
|
||||
|
||||
static const PinMap PinMap_UART_TX[] = {
|
||||
{UART_TX0, UART_0, 0},
|
||||
{UART_TX1, UART_1, 0},
|
||||
{NC, NC, 0}
|
||||
};
|
||||
|
||||
static const PinMap PinMap_UART_RX[] = {
|
||||
{UART_RX0, UART_0, 0},
|
||||
{UART_RX1, UART_1, 0},
|
||||
{NC, NC, 0}
|
||||
};
|
||||
|
||||
#define UART_NUM 2
|
||||
|
||||
static uart_irq_handler irq_handler;
|
||||
|
||||
int stdio_uart_inited = 0;
|
||||
serial_t stdio_uart;
|
||||
|
||||
struct serial_global_data_s {
|
||||
uint32_t serial_irq_id;
|
||||
gpio_t sw_rts, sw_cts;
|
||||
uint8_t count, rx_irq_set_flow, rx_irq_set_api;
|
||||
};
|
||||
|
||||
static struct serial_global_data_s uart_data[UART_NUM];
|
||||
|
||||
void serial_init(serial_t *obj, PinName tx, PinName rx) {
|
||||
int is_stdio_uart = 0;
|
||||
|
||||
// determine the UART to use
|
||||
UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
|
||||
UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
|
||||
UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
|
||||
if ((int)uart == NC) {
|
||||
error("Serial pinout mapping failed");
|
||||
}
|
||||
|
||||
obj->uart = (CMSDK_UART_TypeDef *)uart;
|
||||
//set baud rate and enable Uart in normarl mode (RX and TX enabled)
|
||||
switch (uart) {
|
||||
case UART_0:
|
||||
{
|
||||
CMSDK_UART0->CTRL = 0; // Disable UART when changing configuration
|
||||
if ((int)tx != NC) {
|
||||
CMSDK_UART0->CTRL = 0x1; // TX enable
|
||||
}
|
||||
if ((int)rx != NC) {
|
||||
CMSDK_UART0->CTRL |= 0x2; // RX enable
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UART_1:
|
||||
{
|
||||
CMSDK_UART1->CTRL = 0; // Disable UART when changing configuration
|
||||
if((int)tx != NC) {
|
||||
CMSDK_UART1->CTRL = 0x1; // TX enable
|
||||
}
|
||||
if((int)rx != NC) {
|
||||
CMSDK_UART1->CTRL |= 0x2; // RX enable
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// set default baud rate and format
|
||||
serial_baud(obj, 9600);
|
||||
|
||||
// pinout the chosen uart
|
||||
pinmap_pinout(tx, PinMap_UART_TX);
|
||||
pinmap_pinout(rx, PinMap_UART_RX);
|
||||
|
||||
switch (uart) {
|
||||
case UART_0:
|
||||
obj->index = 0;
|
||||
break;
|
||||
case UART_1:
|
||||
obj->index = 1;
|
||||
break;
|
||||
}
|
||||
uart_data[obj->index].sw_rts.pin = NC;
|
||||
uart_data[obj->index].sw_cts.pin = NC;
|
||||
serial_set_flow_control(obj, FlowControlNone, NC, NC);
|
||||
|
||||
is_stdio_uart = (uart == STDIO_UART) ? (1) : (0);
|
||||
|
||||
if (is_stdio_uart) {
|
||||
stdio_uart_inited = 1;
|
||||
memcpy(&stdio_uart, obj, sizeof(serial_t));
|
||||
}
|
||||
}
|
||||
|
||||
void serial_free(serial_t *obj) {
|
||||
uart_data[obj->index].serial_irq_id = 0;
|
||||
}
|
||||
|
||||
// serial_baud
|
||||
// set the baud rate, taking in to account the current SystemFrequency
|
||||
void serial_baud(serial_t *obj, int baudrate) {
|
||||
// BEETLE has a simple divider to control the baud rate. The formula is:
|
||||
//
|
||||
// Baudrate = PCLK / BAUDDIV
|
||||
//
|
||||
// PCLK = SystemCoreClock
|
||||
// so for a desired baud rate of 9600
|
||||
// SystemCoreClock / 9600
|
||||
//
|
||||
//check to see if minimum baud value entered
|
||||
int baudrate_div = 0;
|
||||
baudrate_div = SystemCoreClock / baudrate;
|
||||
if (baudrate >= 16) {
|
||||
switch ((int)obj->uart) {
|
||||
case UART_0:
|
||||
CMSDK_UART0->BAUDDIV = baudrate_div;
|
||||
break;
|
||||
case UART_1:
|
||||
CMSDK_UART1->BAUDDIV = baudrate_div;
|
||||
break;
|
||||
default:
|
||||
error("serial_baud");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
error("serial_baud");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void serial_format(serial_t *obj, int data_bits,
|
||||
SerialParity parity, int stop_bits) {
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* INTERRUPTS HANDLING
|
||||
******************************************************************************/
|
||||
static inline void uart_irq(uint32_t intstatus, uint32_t index,
|
||||
CMSDK_UART_TypeDef *puart) {
|
||||
SerialIrq irq_type;
|
||||
switch (intstatus) {
|
||||
case 1:
|
||||
{
|
||||
irq_type = TxIrq;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
irq_type = RxIrq;
|
||||
}
|
||||
break;
|
||||
|
||||
default: return;
|
||||
} /* End of Switch */
|
||||
|
||||
if ((irq_type == RxIrq) && (NC != uart_data[index].sw_rts.pin)) {
|
||||
gpio_write(&uart_data[index].sw_rts, 1);
|
||||
// Disable interrupt if it wasn't enabled by other part of the application
|
||||
if (!uart_data[index].rx_irq_set_api) {
|
||||
// puart->CTRL &= ~(1 << RxIrq);
|
||||
/* Disable Rx interrupt */
|
||||
puart->CTRL &= ~(CMSDK_UART_CTRL_RXIRQEN_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
if (uart_data[index].serial_irq_id != 0) {
|
||||
if ((irq_type != RxIrq) || (uart_data[index].rx_irq_set_api)) {
|
||||
irq_handler(uart_data[index].serial_irq_id, irq_type);
|
||||
}
|
||||
}
|
||||
|
||||
if( irq_type == TxIrq ) {
|
||||
/* Clear the TX interrupt Flag */
|
||||
puart->INTCLEAR |= 0x01;
|
||||
} else {
|
||||
/* Clear the Rx interupt Flag */
|
||||
puart->INTCLEAR |= 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
void uart0_irq() {
|
||||
uart_irq(CMSDK_UART0->INTSTATUS & 0x3, 0,
|
||||
(CMSDK_UART_TypeDef*)CMSDK_UART0);
|
||||
}
|
||||
|
||||
void uart1_irq() {
|
||||
uart_irq(CMSDK_UART1->INTSTATUS & 0x3, 1,
|
||||
(CMSDK_UART_TypeDef*)CMSDK_UART1);
|
||||
}
|
||||
|
||||
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
|
||||
irq_handler = handler;
|
||||
uart_data[obj->index].serial_irq_id = id;
|
||||
}
|
||||
|
||||
static void serial_irq_set_internal(serial_t *obj, SerialIrq irq, uint32_t enable) {
|
||||
/* Declare a variable of type IRQn, initialise to 0 */
|
||||
IRQn_Type irq_n = (IRQn_Type)0;
|
||||
uint32_t vector = 0;
|
||||
switch ((int)obj->uart) {
|
||||
|
||||
/*********************************************************************
|
||||
* BEETLE SOC BOARD *
|
||||
*********************************************************************/
|
||||
case UART_0:
|
||||
{
|
||||
irq_n = UART0_IRQn;
|
||||
vector = (uint32_t)&uart0_irq;
|
||||
}
|
||||
break;
|
||||
case UART_1:
|
||||
{
|
||||
irq_n = UART1_IRQn;
|
||||
vector = (uint32_t)&uart1_irq;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
if(irq == TxIrq) {
|
||||
/* Transmit IRQ, set appripriate enable */
|
||||
|
||||
/* set TX interrupt enable in CTRL REG */
|
||||
obj->uart->CTRL |= CMSDK_UART_CTRL_TXIRQEN_Msk;
|
||||
} else {
|
||||
/* set Rx interrupt on in CTRL REG */
|
||||
obj->uart->CTRL |= CMSDK_UART_CTRL_RXIRQEN_Msk;
|
||||
}
|
||||
NVIC_SetVector(irq_n, vector);
|
||||
NVIC_EnableIRQ(irq_n);
|
||||
|
||||
} else if ((irq == TxIrq) || (uart_data[obj->index].rx_irq_set_api
|
||||
+ uart_data[obj->index].rx_irq_set_flow == 0)) {
|
||||
/* Disable IRQ */
|
||||
int all_disabled = 0;
|
||||
SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
|
||||
|
||||
obj->uart->CTRL &= ~(1 << (irq + 2));
|
||||
|
||||
all_disabled = (obj->uart->CTRL & (1 << (other_irq + 2))) == 0;
|
||||
|
||||
if (all_disabled) {
|
||||
NVIC_DisableIRQ(irq_n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
|
||||
if (RxIrq == irq)
|
||||
uart_data[obj->index].rx_irq_set_api = enable;
|
||||
serial_irq_set_internal(obj, irq, enable);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* READ/WRITE
|
||||
******************************************************************************/
|
||||
int serial_getc(serial_t *obj) {
|
||||
while (serial_readable(obj) == 0);
|
||||
int data = obj->uart->DATA;
|
||||
return data;
|
||||
}
|
||||
|
||||
void serial_putc(serial_t *obj, int c) {
|
||||
#ifdef SERIAL_TEST
|
||||
// Add CR to LF
|
||||
if (c == 0x0A) {
|
||||
while (serial_writable(obj));
|
||||
obj->uart->DATA = 0x0D;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (serial_writable(obj));
|
||||
obj->uart->DATA = c;
|
||||
}
|
||||
|
||||
int serial_readable(serial_t *obj) {
|
||||
return obj->uart->STATE & 2;
|
||||
}
|
||||
|
||||
int serial_writable(serial_t *obj) {
|
||||
return obj->uart->STATE & 1;
|
||||
}
|
||||
|
||||
void serial_clear(serial_t *obj) {
|
||||
obj->uart->DATA = 0x00;
|
||||
}
|
||||
|
||||
void serial_pinout_tx(PinName tx) {
|
||||
pinmap_pinout(tx, PinMap_UART_TX);
|
||||
}
|
||||
|
||||
void serial_break_set(serial_t *obj) {
|
||||
}
|
||||
|
||||
void serial_break_clear(serial_t *obj) {
|
||||
}
|
||||
void serial_set_flow_control(serial_t *obj, FlowControl type,
|
||||
PinName rxflow, PinName txflow) {
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 <math.h>
|
||||
|
||||
#include "spi_api.h"
|
||||
#include "spi_def.h"
|
||||
#include "cmsis.h"
|
||||
#include "pinmap.h"
|
||||
#include "mbed_error.h"
|
||||
#include "wait_api.h"
|
||||
|
||||
/*
|
||||
* Driver private data structure that should not be shared by multiple
|
||||
* instances of the driver (same driver for multiple instances of the IP)
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t size; /* size of an SPI frame in bits: can be 8 or 16 */
|
||||
} private_spi_t;
|
||||
|
||||
static const PinMap PinMap_SPI_SCLK[] = {
|
||||
{SHIELD_SPI_SCK , SPI_0, 0},
|
||||
{ADC_SPI_SCK , SPI_1, 0},
|
||||
{NC, NC, 0}
|
||||
};
|
||||
|
||||
static const PinMap PinMap_SPI_MOSI[] = {
|
||||
{SHIELD_SPI_MOSI, SPI_0, 0},
|
||||
{ADC_SPI_MOSI, SPI_1, 0},
|
||||
{NC, NC, 0}
|
||||
};
|
||||
|
||||
static const PinMap PinMap_SPI_MISO[] = {
|
||||
{SHIELD_SPI_MISO, SPI_0, 0},
|
||||
{ADC_SPI_MISO, SPI_1, 0},
|
||||
{NC, NC, 0}
|
||||
};
|
||||
|
||||
static const PinMap PinMap_SPI_SSEL[] = {
|
||||
{SHIELD_SPI_nCS, SPI_0, 0},
|
||||
{ADC_SPI_nCS, SPI_1, 0},
|
||||
{NC, NC, 0}
|
||||
};
|
||||
|
||||
/*
|
||||
* Retrieve the private data of the instance related to a given IP
|
||||
*/
|
||||
static private_spi_t* get_spi_private(spi_t *obj) {
|
||||
static private_spi_t data0, data1;
|
||||
/*
|
||||
* Select which instance to give using the base
|
||||
* address of registers
|
||||
*/
|
||||
switch ((intptr_t)obj->spi) {
|
||||
case SPI0_BASE:
|
||||
return &data0;
|
||||
case SPI1_BASE:
|
||||
return &data1;
|
||||
default:
|
||||
error("SPI driver private data structure not found for this registers base address");
|
||||
return (void*)0;
|
||||
}
|
||||
}
|
||||
|
||||
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 = (SPI_TypeDef*)pinmap_merge(spi_data, spi_cntl);
|
||||
if ((int)obj->spi == NC) {
|
||||
error("SPI pinout mapping failed");
|
||||
}
|
||||
|
||||
/* Set default format and frequency */
|
||||
if (ssel == NC) {
|
||||
spi_format(obj, 8, 0, 0); // 8 bits, mode SPI_MSB, master
|
||||
} else {
|
||||
spi_format(obj, 8, 0, 1); // 8 bits, mode SPI_LSB, slave
|
||||
}
|
||||
spi_frequency(obj, 1562500);
|
||||
|
||||
/* Pin out the spi pins */
|
||||
pinmap_pinout(mosi, PinMap_SPI_MOSI);
|
||||
pinmap_pinout(miso, PinMap_SPI_MISO);
|
||||
pinmap_pinout(sclk, PinMap_SPI_SCLK);
|
||||
if (ssel != NC) {
|
||||
pinmap_pinout(ssel, PinMap_SPI_SSEL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set desired enabled IRQs:
|
||||
* MF: Mode Fail
|
||||
* TF: TX FIFO Full
|
||||
* TNF: TX FIFO Not Full
|
||||
* RNE: RX FIFO Not Empty
|
||||
*/
|
||||
uint32_t irqs = (IRQ_ENABLE_MFE | IRQ_ENABLE_TFE
|
||||
| IRQ_ENABLE_TNFE | IRQ_ENABLE_RNEE);
|
||||
|
||||
/*
|
||||
* Enable:
|
||||
* - Master mode
|
||||
* - Manual start mode
|
||||
* - Manual chip select
|
||||
* - Peripheral select decode
|
||||
*/
|
||||
obj->spi->CONFIG |= (CONFIG_MSEL | CONFIG_MSE
|
||||
/*| CONFIG_MCSE | CONFIG_PSD*/);
|
||||
|
||||
/* Set all peripheral select lines high - these should be unused */
|
||||
obj->spi->CONFIG |= 0x00000; //CONFIG_PCSL;
|
||||
|
||||
obj->spi->IRQ_ENABLE = irqs;
|
||||
obj->spi->IRQ_DISABLE = ~irqs;
|
||||
obj->spi->SPI_ENABLE |= SPI_ENABLE_SPIE;
|
||||
}
|
||||
|
||||
void spi_free(spi_t *obj) {
|
||||
}
|
||||
|
||||
void spi_format(spi_t *obj, int bits, int mode, int slave) {
|
||||
private_spi_t *private_spi = get_spi_private(obj);
|
||||
|
||||
obj->spi->SPI_ENABLE &= ~SPI_ENABLE_SPIE;
|
||||
|
||||
/*
|
||||
* The mbed API specifies 'bits' as being 4-16 per frame. This
|
||||
* controller supports only 8 or 16 bit frames. Therefore we will
|
||||
* assume 8 bits and, if anything larger is specified, we will use
|
||||
* 16 bits.
|
||||
*/
|
||||
obj->spi->CONFIG &= ~CONFIG_TWS; /* 00 = 8 bit frame */
|
||||
private_spi->size = 8;
|
||||
|
||||
if (bits > 8) {
|
||||
switch (bits) {
|
||||
case 16:
|
||||
private_spi->size = 16;
|
||||
break;
|
||||
default:
|
||||
obj->spi->CONFIG |= CONFIG_TWS_1; /* 01 = 16 bit frame */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
default:
|
||||
case 0:
|
||||
obj->spi->CONFIG &= ~CONFIG_CPOL;
|
||||
obj->spi->CONFIG &= ~CONFIG_CPHA;
|
||||
break;
|
||||
case 1:
|
||||
obj->spi->CONFIG &= ~CONFIG_CPOL;
|
||||
obj->spi->CONFIG |= CONFIG_CPHA;
|
||||
break;
|
||||
case 2:
|
||||
obj->spi->CONFIG |= CONFIG_CPOL;
|
||||
obj->spi->CONFIG &= ~CONFIG_CPHA;
|
||||
break;
|
||||
case 3:
|
||||
obj->spi->CONFIG |= CONFIG_CPOL;
|
||||
obj->spi->CONFIG |= CONFIG_CPHA;
|
||||
break;
|
||||
}
|
||||
|
||||
obj->spi->SPI_ENABLE |= SPI_ENABLE_SPIE;
|
||||
}
|
||||
|
||||
void spi_frequency(spi_t *obj, int hz) {
|
||||
/*
|
||||
* Valid frequencies are derived from a 25MHz peripheral clock.
|
||||
* Frequency | Divisor | MBRD Value | Hz
|
||||
* 12.0 MHz 2 000 12000000
|
||||
* 6.0 MHz 4 001 6000000
|
||||
* 3.0 MHz 8 010 3000000
|
||||
* 1.5 MHz 16 011 1500000
|
||||
* 750.0 KHz 32 100 750000
|
||||
* 375.0 KHz 64 101 375000
|
||||
* 187.500 KHz 128 110 187500
|
||||
* 93.750 KHz 256 111 93750
|
||||
*/
|
||||
int valid_frequencies[] = {12000000, 6000000, 3000000, 1500000,
|
||||
750000, 375000, 187500, 93750};
|
||||
uint16_t mbrd_value = 0;
|
||||
uint32_t config = (obj->spi->CONFIG & ~CONFIG_MBRD);
|
||||
|
||||
/* Store the index of the minimum supported frequency */
|
||||
uint32_t index = 7;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (hz >= valid_frequencies[i]) {
|
||||
/*
|
||||
* Store the index of the closest lower or equal supported
|
||||
* frequency.
|
||||
*/
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
mbrd_value++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the selected frequency. If the frequency is below the minimum
|
||||
* supported the driver sets the minumum.
|
||||
*/
|
||||
config |= index << CONFIG_MBRD_SHIFT;
|
||||
|
||||
/*
|
||||
* If the specified frequency didn't match any of the valid frequencies
|
||||
* then leave CONFIG_MBRD to the closest lower frequency supported.
|
||||
*/
|
||||
obj->spi->CONFIG = config;
|
||||
}
|
||||
|
||||
int spi_master_write(spi_t *obj, int value) {
|
||||
private_spi_t *private_spi = get_spi_private(obj);
|
||||
|
||||
int data = 0;
|
||||
if(private_spi->size == 16) {
|
||||
obj->spi->TX_DATA = (uint8_t)((value >> 8) & TX_DATA_TDATA);
|
||||
obj->spi->TX_DATA = (uint8_t)(value & TX_DATA_TDATA);
|
||||
|
||||
/* Manually trigger start */
|
||||
obj->spi->CONFIG |= CONFIG_MSC;
|
||||
|
||||
while(!(obj->spi->IRQ_STATUS & IRQ_STATUS_TNF))
|
||||
continue;
|
||||
|
||||
data = (obj->spi->RX_DATA & RX_DATA_RDATA) << 8;
|
||||
data = data | (obj->spi->RX_DATA & RX_DATA_RDATA);
|
||||
} else {
|
||||
|
||||
obj->spi->TX_DATA = (uint16_t)(value & TX_DATA_TDATA);
|
||||
|
||||
/* Manually trigger start */
|
||||
obj->spi->CONFIG |= CONFIG_MSC;
|
||||
|
||||
while(!(obj->spi->IRQ_STATUS & IRQ_STATUS_TNF))
|
||||
continue;
|
||||
|
||||
data = obj->spi->RX_DATA & RX_DATA_RDATA;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t spi_get_module(spi_t *obj) {
|
||||
return obj->spi->MID;
|
||||
}
|
||||
|
||||
int spi_busy(spi_t *obj) {
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* SSP interface Support
|
||||
* =====================
|
||||
*/
|
||||
|
||||
#ifndef MBED_SPI_DEF_H
|
||||
#define MBED_SPI_DEF_H
|
||||
|
||||
#include <stdint.h> /* standard types definitions */
|
||||
|
||||
#define Module_ID 0x00090108
|
||||
|
||||
typedef struct beetle_spi
|
||||
{
|
||||
__IO uint32_t CONFIG; /* 0x00 RW Configuration Register */
|
||||
__I uint32_t IRQ_STATUS; /* 0x04 RO Interrupt Status Register*/
|
||||
__O uint32_t IRQ_ENABLE; /* 0x08 WO Interrupt Enable Register*/
|
||||
__O uint32_t IRQ_DISABLE; /* 0x0C WO Interrupt Disable Register */
|
||||
__I uint32_t IRQ_MASK; /* 0x10 RO Interrupt Mask Register */
|
||||
__IO uint32_t SPI_ENABLE; /* 0x14 RW SPI Enable Register */
|
||||
__IO uint32_t DELAY; /* 0x18 RW Delay Register */
|
||||
__O uint32_t TX_DATA; /* 0x1C WO Transmit Data Register */
|
||||
__I uint32_t RX_DATA; /* 0x20 RO Receive Data Register */
|
||||
__IO uint32_t SLAVE_IDLE_COUNT; /* 0x24 RW Slave Idle Count Register */
|
||||
__IO uint32_t TX_THRESHOLD; /* 0x28 RW TX Threshold Register */
|
||||
__IO uint32_t RX_THRESHOLD; /* 0x2C RW RX Threshold Register */
|
||||
uint32_t reserved[208];
|
||||
__I uint32_t MID; /* 0xFC RO Module ID Register */
|
||||
}SPI_TypeDef;
|
||||
|
||||
|
||||
#define SPI0_BASE (0x4000C000ul) /* Shield Header SPI Base Address */
|
||||
#define SPI1_BASE (0x4000D000ul) /* ADC SPI Base Address */
|
||||
|
||||
#define SHIELD_SPI ((SPI_TypeDef *) SPI0_BASE )
|
||||
#define ADC_SPI ((SPI_TypeDef *) SPI1_BASE )
|
||||
|
||||
/* Configuration Register Bit Masks */
|
||||
#define CONFIG_MSEL 0x00001 // Bit [00] MSEL Mode Select
|
||||
#define CONFIG_CPOL 0x00002 // Bit [01] CPOL External Clock Edge
|
||||
#define CONFIG_CPHA 0x00004 // Bit [02] CPHA Clock Phase
|
||||
#define CONFIG_MBRD 0x00038 // Bits [05:03] MBRD Master Baud Rate Divisor (2 to 256)
|
||||
#define CONFIG_MBRD_0 0x00008
|
||||
#define CONFIG_MBRD_1 0x00010
|
||||
#define CONFIG_MBRD_2 0x00020
|
||||
#define CONFIG_MBRD_SHIFT 3
|
||||
#define CONFIG_TWS 0x000C0 // Bits [07:06] TWS Transfer Word Size
|
||||
#define CONFIG_TWS_0 0x00000
|
||||
#define CONFIG_TWS_1 0x00040
|
||||
#define CONFIG_MRCS 0x00100 // Bit [08] MRCS Reference Clock Select
|
||||
#define CONFIG_PSD 0x00200 // Bit [09] PSD Peripheral Select Decode
|
||||
#define CONFIG_PCSL 0x03C00 // Bits [13:10] PCSL Peripheral Chip Select Lines (master mode only)
|
||||
#define CONFIG_MCSE 0x04000 // Bit [14] MCSE Manual Chip Select Enable
|
||||
#define CONFIG_MSE 0x08000 // Bit [15] MSE Manual Start Enable
|
||||
#define CONFIG_MSC 0x10000 // Bit [16] MSC Manual Start Command
|
||||
#define CONFIG_MFGE 0x20000 // Bit [17] MFGE Mode Fail Generation Enable
|
||||
#define CONFIG_SPSE 0x40000 // Bit [18] SPSE Sample Point Shift Enable
|
||||
|
||||
/* Interrupt Status Register Bit Masks */
|
||||
#define IRQ_STATUS_ROF 0x01 // Bit [00] ROF RX FIFO Overflow
|
||||
#define IRQ_STATUS_MF 0x02 // Bit [01] MF Mode Fail
|
||||
#define IRQ_STATUS_TNF 0x04 // Bit [02] TNF TX FIFO Not Full (current FIFO status)
|
||||
#define IRQ_STATUS_TF 0x08 // Bit [03] TF TX FIFO Full (current FIFO status)
|
||||
#define IRQ_STATUS_RNE 0x10 // Bit [04] RNE RX FIFO Not Empty (current FIFO status)
|
||||
#define IRQ_STATUS_RF 0x20 // Bit [05] RF RX FIFO Full (current FIFO status)
|
||||
#define IRQ_STATUS_TUF 0x40 // Bit [06] TUF TX FIFO Underflow
|
||||
|
||||
/* Interrupt Enable Register Bit Masks */
|
||||
#define IRQ_ENABLE_ROFE 0x01 // Bit [00] ROFE RX FIFO Overflow Enable
|
||||
#define IRQ_ENABLE_MFE 0x02 // Bit [01] MFE Mode Fail Enable
|
||||
#define IRQ_ENABLE_TNFE 0x04 // Bit [02] TNFE TX FIFO Not Full Enable
|
||||
#define IRQ_ENABLE_TFE 0x08 // Bit [03] TFE TX FIFO Full Enable
|
||||
#define IRQ_ENABLE_RNEE 0x10 // Bit [04] RNEE RX FIFO Not Empty Enable
|
||||
#define IRQ_ENABLE_RFE 0x20 // Bit [05] RFE RX FIFO Full Enable
|
||||
#define IRQ_ENABLE_TUFE 0x40 // Bit [06] TUFE TX FIFO Underflow Enable
|
||||
|
||||
/* Interrupt Disable Register Bit Masks */
|
||||
#define IRQ_DISABLE_ROFD 0x01 // Bit [00] ROFD RX FIFO Overflow Disable
|
||||
#define IRQ_DISABLE_MFD 0x02 // Bit [01] MFD Mode Fail Disable
|
||||
#define IRQ_DISABLE_TNFD 0x04 // Bit [02] TNFD TX FIFO Not Full Disable
|
||||
#define IRQ_DISABLE_TFD 0x08 // Bit [03] TFD TX FIFO Full Disable
|
||||
#define IRQ_DISABLE_RNED 0x10 // Bit [04] RNED RX FIFO Not Empty Disable
|
||||
#define IRQ_DISABLE_RFD 0x20 // Bit [05] RFD RX FIFO Full Disable
|
||||
#define IRQ_DISABLE_TUFD 0x40 // Bit [06] TUFD TX FIFO Underflow Disable
|
||||
|
||||
/* Interrupt Mask Register Bit Masks */
|
||||
#define IRQ_MASK_ROFM 0x01 // Bit [00] ROFM RX FIFO Overflow Mask
|
||||
#define IRQ_MASK_MFM 0x02 // Bit [01] MFM Mode Fail Mask
|
||||
#define IRQ_MASK_TNFM 0x04 // Bit [02] TNFM TX FIFO Not Full Mask
|
||||
#define IRQ_MASK_TFM 0x08 // Bit [03] TFM TX FIFO Full Mask
|
||||
#define IRQ_MASK_RNEM 0x10 // Bit [04] RNEM RX FIFO Not Empty Mask
|
||||
#define IRQ_MASK_RFM 0x20 // Bit [05] RFM RX FIFO Full Mask
|
||||
#define IRQ_MASK_TUFM 0x40 // Bit [06] TUFM TX FIFO Underflow Mask
|
||||
|
||||
/* SPI Enable Register Bit Masks */
|
||||
#define SPI_ENABLE_SPIE 0x01 // Bit [00] SPIE SPI Enable
|
||||
|
||||
/* Delay Register Bit Masks */
|
||||
#define DELAY_D_INIT 0x000000FF // Bits [07:00] D_INIT Delay Init
|
||||
#define DELAY_D_AFTER 0x0000FF00 // Bits [15:08] D_AFTER Delay After
|
||||
#define DELAY_D_BTWN 0x00FF0000 // Bits [23:16] D_BTWN Delay Between
|
||||
#define DELAY_D_NSS 0xFF000000 // Bits [31:24] D_NSS Delay NSS
|
||||
|
||||
/* Transmit Data Register Bit Masks */
|
||||
#define TX_DATA_TDATA 0xFF
|
||||
|
||||
/* Receive Data Register Bit Masks */
|
||||
#define RX_DATA_RDATA 0xFF
|
||||
|
||||
/* Slave Idle Count Register Bit Masks */
|
||||
#define SLAVE_IDLE_COUNT_SICNT 0xFF // Bits [07:00] SICNT Slave Idle Count
|
||||
|
||||
/* TX Threshold Register Bit Masks */
|
||||
#define TX_THRESHOLD_TTRSH 0x07 // Bits [N:00] TTRSH TX Threshold
|
||||
|
||||
/* RX Threshold Register Bit Masks */
|
||||
#define RX_THRESHOLD_RTRSH 0x07 // Bits [N:00] RTRSH RX Threshold
|
||||
|
||||
#endif
|
|
@ -0,0 +1,94 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 <stddef.h>
|
||||
#include "cmsis.h"
|
||||
#include "us_ticker_api.h"
|
||||
#include "PeripheralNames.h"
|
||||
/* Private data */
|
||||
/* us_ticker reload value */
|
||||
static uint32_t us_ticker_reload = 0x0; /* Max Value */
|
||||
/* us ticker initialized */
|
||||
static uint32_t us_ticker_inited = 0;
|
||||
/* us ticker overflow */
|
||||
static uint32_t us_ticker_overflow = 0;
|
||||
|
||||
void __us_ticker_irq_handler(void) {
|
||||
Timer_ClearInterrupt(TIMER1);
|
||||
us_ticker_overflow++;
|
||||
}
|
||||
|
||||
void us_ticker_init(void) {
|
||||
uint32_t us_ticker_irqn0 = 0;
|
||||
uint32_t us_ticker_irqn1 = 0;
|
||||
|
||||
if (us_ticker_inited)
|
||||
return;
|
||||
us_ticker_inited = 1;
|
||||
|
||||
/* Initialize Timer 0 */
|
||||
Timer_Initialize(TIMER0, us_ticker_reload);
|
||||
/* Enable Timer 0 */
|
||||
Timer_Enable(TIMER0);
|
||||
|
||||
/* Initialize Timer 1 */
|
||||
Timer_Initialize(TIMER1, us_ticker_reload);
|
||||
/* Enable Timer 1 */
|
||||
Timer_Enable(TIMER1);
|
||||
|
||||
/* Timer 0 get IRQn */
|
||||
us_ticker_irqn0 = Timer_GetIRQn(TIMER0);
|
||||
NVIC_SetVector((IRQn_Type)us_ticker_irqn0, (uint32_t)us_ticker_irq_handler);
|
||||
NVIC_EnableIRQ((IRQn_Type)us_ticker_irqn0);
|
||||
|
||||
/* Timer 1 get IRQn */
|
||||
us_ticker_irqn1 = Timer_GetIRQn(TIMER1);
|
||||
NVIC_SetVector((IRQn_Type)us_ticker_irqn1, (uint32_t)__us_ticker_irq_handler);
|
||||
NVIC_EnableIRQ((IRQn_Type)us_ticker_irqn1);
|
||||
}
|
||||
|
||||
uint32_t us_ticker_read() {
|
||||
uint32_t return_value = 0;
|
||||
|
||||
if (!us_ticker_inited)
|
||||
us_ticker_init();
|
||||
return_value = Timer_Read(TIMER1);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void us_ticker_set_interrupt(timestamp_t timestamp) {
|
||||
int32_t delta = 0;
|
||||
|
||||
if (!us_ticker_inited)
|
||||
us_ticker_init();
|
||||
delta = (int32_t)(timestamp - us_ticker_read());
|
||||
/* Check if the event was in the past */
|
||||
if (delta <= 0) {
|
||||
/* This event was in the past */
|
||||
Timer_SetInterrupt(TIMER0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the event was not in the past enable interrupt */
|
||||
Timer_SetInterrupt(TIMER0, delta);
|
||||
}
|
||||
|
||||
void us_ticker_disable_interrupt(void) {
|
||||
Timer_DisableInterrupt(TIMER0);
|
||||
}
|
||||
|
||||
void us_ticker_clear_interrupt(void) {
|
||||
Timer_ClearInterrupt(TIMER0);
|
||||
}
|
Loading…
Reference in New Issue