mirror of https://github.com/ARMmbed/mbed-os.git
Freescale: Remove K20XX files
Mbed OS 6 does not support K20XX targetspull/13945/head
parent
f2278567d0
commit
942f62c148
|
@ -1,47 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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_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[];
|
|
||||||
|
|
||||||
/************UART***************/
|
|
||||||
extern const PinMap PinMap_UART_TX[];
|
|
||||||
extern const PinMap PinMap_UART_RX[];
|
|
||||||
|
|
||||||
/************SPI***************/
|
|
||||||
extern const PinMap PinMap_SPI_SCLK[];
|
|
||||||
extern const PinMap PinMap_SPI_MOSI[];
|
|
||||||
extern const PinMap PinMap_SPI_MISO[];
|
|
||||||
extern const PinMap PinMap_SPI_SSEL[];
|
|
||||||
|
|
||||||
/************PWM***************/
|
|
||||||
extern const PinMap PinMap_PWM[];
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,36 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 {
|
|
||||||
PortA = 0,
|
|
||||||
PortB = 1,
|
|
||||||
PortC = 2,
|
|
||||||
PortD = 3,
|
|
||||||
PortE = 4
|
|
||||||
} PortName;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,84 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "analogin_api.h"
|
|
||||||
|
|
||||||
#include "cmsis.h"
|
|
||||||
#include "pinmap.h"
|
|
||||||
#include "clk_freqs.h"
|
|
||||||
#include "PeripheralPins.h"
|
|
||||||
|
|
||||||
#define MAX_FADC 6000000
|
|
||||||
|
|
||||||
void analogin_init(analogin_t *obj, PinName pin) {
|
|
||||||
obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
|
|
||||||
MBED_ASSERT(obj->adc != (ADCName)NC);
|
|
||||||
|
|
||||||
SIM->SCGC6 |= SIM_SCGC6_ADC0_MASK;
|
|
||||||
|
|
||||||
uint32_t port = (uint32_t)pin >> PORT_SHIFT;
|
|
||||||
SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port);
|
|
||||||
|
|
||||||
// bus clk
|
|
||||||
uint32_t PCLK = bus_frequency();
|
|
||||||
uint32_t clkdiv;
|
|
||||||
for (clkdiv = 0; clkdiv < 4; clkdiv++) {
|
|
||||||
if ((PCLK >> clkdiv) <= MAX_FADC)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (clkdiv == 4) //Set max div
|
|
||||||
clkdiv = 0x7;
|
|
||||||
|
|
||||||
ADC0->SC1[1] = ADC_SC1_ADCH(obj->adc);
|
|
||||||
|
|
||||||
ADC0->CFG1 = ADC_CFG1_ADLPC_MASK // Low-Power Configuration
|
|
||||||
| ADC_CFG1_ADIV(clkdiv & 0x3) // Clock Divide Select
|
|
||||||
| ADC_CFG1_ADLSMP_MASK // Long Sample Time
|
|
||||||
| ADC_CFG1_MODE(3) // (16)bits Resolution
|
|
||||||
| ADC_CFG1_ADICLK(clkdiv >> 2); // Input Clock
|
|
||||||
|
|
||||||
ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK // ADxxb or ADxxa channels
|
|
||||||
| ADC_CFG2_ADHSC_MASK // High-Speed Configuration
|
|
||||||
| ADC_CFG2_ADLSTS(0); // Long Sample Time Select
|
|
||||||
|
|
||||||
ADC0->SC2 = ADC_SC2_REFSEL(0); // Default Voltage Reference
|
|
||||||
|
|
||||||
ADC0->SC3 = ADC_SC3_AVGE_MASK // Hardware Average Enable
|
|
||||||
| ADC_SC3_AVGS(0); // 4 Samples Averaged
|
|
||||||
|
|
||||||
pinmap_pinout(pin, PinMap_ADC);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t analogin_read_u16(analogin_t *obj) {
|
|
||||||
// start conversion
|
|
||||||
ADC0->SC1[0] = ADC_SC1_ADCH(obj->adc);
|
|
||||||
|
|
||||||
// Wait Conversion Complete
|
|
||||||
while ((ADC0->SC1[0] & ADC_SC1_COCO_MASK) != ADC_SC1_COCO_MASK);
|
|
||||||
|
|
||||||
return (uint16_t)ADC0->R[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
float analogin_read(analogin_t *obj) {
|
|
||||||
uint16_t value = analogin_read_u16(obj);
|
|
||||||
return (float)value * (1.0f / (float)0xFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *analogin_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_ADC;
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "analogout_api.h"
|
|
||||||
|
|
||||||
#if DEVICE_ANALOGOUT
|
|
||||||
|
|
||||||
#include "cmsis.h"
|
|
||||||
#include "pinmap.h"
|
|
||||||
#include "PeripheralPins.h"
|
|
||||||
|
|
||||||
#define RANGE_12BIT 0xFFF
|
|
||||||
|
|
||||||
void analogout_init(dac_t *obj, PinName pin) {
|
|
||||||
obj->dac = (DACName)pinmap_peripheral(pin, PinMap_DAC);
|
|
||||||
MBED_ASSERT(obj->dac != (DACName)NC);
|
|
||||||
|
|
||||||
SIM->SCGC2 |= SIM_SCGC2_DAC0_MASK;
|
|
||||||
|
|
||||||
uint32_t port = (uint32_t)pin >> PORT_SHIFT;
|
|
||||||
SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port);
|
|
||||||
|
|
||||||
DAC0->DAT[obj->dac].DATH = 0;
|
|
||||||
DAC0->DAT[obj->dac].DATL = 0;
|
|
||||||
|
|
||||||
DAC0->C1 = DAC_C1_DACBFMD_MASK; // One-Time Scan Mode
|
|
||||||
|
|
||||||
DAC0->C0 = DAC_C0_DACEN_MASK // Enable
|
|
||||||
| DAC_C0_DACSWTRG_MASK // Software Trigger
|
|
||||||
| DAC_C0_DACRFS_MASK; // VDDA selected
|
|
||||||
|
|
||||||
analogout_write_u16(obj, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void analogout_free(dac_t *obj) {}
|
|
||||||
|
|
||||||
static inline void dac_write(dac_t *obj, int value) {
|
|
||||||
DAC0->DAT[obj->dac].DATL = (uint8_t)( value & 0xFF);
|
|
||||||
DAC0->DAT[obj->dac].DATH = (uint8_t)((value >> 8) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int dac_read(dac_t *obj) {
|
|
||||||
return ((DAC0->DAT[obj->dac].DATH << 8) | DAC0->DAT[obj->dac].DATL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void analogout_write(dac_t *obj, float value) {
|
|
||||||
if (value < 0.0) {
|
|
||||||
dac_write(obj, 0);
|
|
||||||
} else if (value > 1.0) {
|
|
||||||
dac_write(obj, RANGE_12BIT);
|
|
||||||
} else {
|
|
||||||
dac_write(obj, value * (float)RANGE_12BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void analogout_write_u16(dac_t *obj, uint16_t value) {
|
|
||||||
dac_write(obj, value >> 4); // 12-bit
|
|
||||||
}
|
|
||||||
|
|
||||||
float analogout_read(dac_t *obj) {
|
|
||||||
uint32_t value = dac_read(obj);
|
|
||||||
return (float)value * (1.0f / (float)RANGE_12BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t analogout_read_u16(dac_t *obj) {
|
|
||||||
uint32_t value = dac_read(obj); // 12-bit
|
|
||||||
return (value << 4) | ((value >> 8) & 0x003F);
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *analogout_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_DAC;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,116 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 CLK_FREQS_H
|
|
||||||
#define CLK_FREQS_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Get the peripheral bus clock frequency
|
|
||||||
* \return Bus frequency
|
|
||||||
*/
|
|
||||||
static inline uint32_t bus_frequency(void) {
|
|
||||||
return SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Get external oscillator (crystal) frequency
|
|
||||||
* \return External osc frequency
|
|
||||||
*/
|
|
||||||
static uint32_t extosc_frequency(void) {
|
|
||||||
uint32_t MCGClock = SystemCoreClock * (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT));
|
|
||||||
|
|
||||||
if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(2)) //MCG clock = external reference clock
|
|
||||||
return MCGClock;
|
|
||||||
|
|
||||||
if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0)) { //PLL/FLL is selected
|
|
||||||
uint32_t divider, multiplier;
|
|
||||||
if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u) { //FLL is selected
|
|
||||||
if ((MCG->S & MCG_S_IREFST_MASK) == 0x0u) { //FLL uses external reference
|
|
||||||
divider = (uint8_t)(1u << ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT));
|
|
||||||
if ((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x0u)
|
|
||||||
divider <<= 5u;
|
|
||||||
/* Select correct multiplier to calculate the MCG output clock */
|
|
||||||
switch (MCG->C4 & (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) {
|
|
||||||
case 0x0u:
|
|
||||||
multiplier = 640u;
|
|
||||||
break;
|
|
||||||
case 0x20u:
|
|
||||||
multiplier = 1280u;
|
|
||||||
break;
|
|
||||||
case 0x40u:
|
|
||||||
multiplier = 1920u;
|
|
||||||
break;
|
|
||||||
case 0x60u:
|
|
||||||
multiplier = 2560u;
|
|
||||||
break;
|
|
||||||
case 0x80u:
|
|
||||||
multiplier = 732u;
|
|
||||||
break;
|
|
||||||
case 0xA0u:
|
|
||||||
multiplier = 1464u;
|
|
||||||
break;
|
|
||||||
case 0xC0u:
|
|
||||||
multiplier = 2197u;
|
|
||||||
break;
|
|
||||||
case 0xE0u:
|
|
||||||
default:
|
|
||||||
multiplier = 2929u;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MCGClock * divider / multiplier;
|
|
||||||
}
|
|
||||||
} else { //PLL is selected
|
|
||||||
divider = (1u + (MCG->C5 & MCG_C5_PRDIV0_MASK));
|
|
||||||
multiplier = ((MCG->C6 & MCG_C6_VDIV0_MASK) + 24u);
|
|
||||||
return MCGClock * divider / multiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//In all other cases either there is no crystal or we cannot determine it
|
|
||||||
//For example when the FLL is running on the internal reference, and there is also an
|
|
||||||
//external crystal. However these are unlikely situations
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get MCG PLL/2 or FLL frequency, depending on which one is active, sets PLLFLLSEL bit
|
|
||||||
static uint32_t mcgpllfll_frequency(void) {
|
|
||||||
if ((MCG->C1 & MCG_C1_CLKS_MASK) != MCG_C1_CLKS(0)) //PLL/FLL is not selected
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint32_t MCGClock = SystemCoreClock * (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT));
|
|
||||||
if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u) { //FLL is selected
|
|
||||||
SIM->SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK; //MCG peripheral clock is FLL output
|
|
||||||
return MCGClock;
|
|
||||||
} else { //PLL is selected
|
|
||||||
SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK; //MCG peripheral clock is PLL output
|
|
||||||
return MCGClock;
|
|
||||||
}
|
|
||||||
|
|
||||||
//It is possible the SystemCoreClock isn't running on the PLL, and the PLL is still active
|
|
||||||
//for the peripherals, this is however an unlikely setup
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,57 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "gpio_api.h"
|
|
||||||
#include "pinmap.h"
|
|
||||||
|
|
||||||
uint32_t gpio_set(PinName pin) {
|
|
||||||
MBED_ASSERT(pin != (PinName)NC);
|
|
||||||
pin_function(pin, 1);
|
|
||||||
return 1 << ((pin & 0x7F) >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_init(gpio_t *obj, PinName pin) {
|
|
||||||
obj->pin = pin;
|
|
||||||
if (pin == (PinName)NC)
|
|
||||||
return;
|
|
||||||
|
|
||||||
obj->mask = gpio_set(pin);
|
|
||||||
|
|
||||||
unsigned int port = (unsigned int)pin >> PORT_SHIFT;
|
|
||||||
|
|
||||||
GPIO_Type *reg = (GPIO_Type *)(PTA_BASE + port * 0x40);
|
|
||||||
obj->reg_set = ®->PSOR;
|
|
||||||
obj->reg_clr = ®->PCOR;
|
|
||||||
obj->reg_in = ®->PDIR;
|
|
||||||
obj->reg_dir = ®->PDDR;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
switch (direction) {
|
|
||||||
case PIN_INPUT :
|
|
||||||
*obj->reg_dir &= ~obj->mask;
|
|
||||||
break;
|
|
||||||
case PIN_OUTPUT:
|
|
||||||
*obj->reg_dir |= obj->mask;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,226 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 160
|
|
||||||
|
|
||||||
static uint32_t channel_ids[CHANNEL_NUM] = {0};
|
|
||||||
static gpio_irq_handler irq_handler;
|
|
||||||
|
|
||||||
#define IRQ_DISABLED (0)
|
|
||||||
#define IRQ_RAISING_EDGE PORT_PCR_IRQC(9)
|
|
||||||
#define IRQ_FALLING_EDGE PORT_PCR_IRQC(10)
|
|
||||||
#define IRQ_EITHER_EDGE PORT_PCR_IRQC(11)
|
|
||||||
|
|
||||||
static void handle_interrupt_in(PORT_Type *port, int ch_base) {
|
|
||||||
uint32_t isfr;
|
|
||||||
uint32_t pin;
|
|
||||||
|
|
||||||
while ((isfr = port->ISFR) != 0) {
|
|
||||||
pin = 31 - __CLZ(isfr);
|
|
||||||
uint32_t id = channel_ids[ch_base + pin];
|
|
||||||
if (id == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPIO_Type *gpio = PTA;
|
|
||||||
gpio_irq_event event = IRQ_NONE;
|
|
||||||
uint32_t port_num = (port - PORTA) >> 12;
|
|
||||||
|
|
||||||
switch (port->PCR[pin] & PORT_PCR_IRQC_MASK) {
|
|
||||||
case IRQ_RAISING_EDGE:
|
|
||||||
event = IRQ_RISE;
|
|
||||||
break;
|
|
||||||
case IRQ_FALLING_EDGE:
|
|
||||||
event = IRQ_FALL;
|
|
||||||
break;
|
|
||||||
case IRQ_EITHER_EDGE:
|
|
||||||
gpio += (port_num * 0x40);
|
|
||||||
event = (gpio->PDIR & (1 << pin)) ? (IRQ_RISE) : (IRQ_FALL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (event != IRQ_NONE) {
|
|
||||||
irq_handler(id, event);
|
|
||||||
}
|
|
||||||
port->ISFR = 1 << pin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_irqA(void) {
|
|
||||||
handle_interrupt_in(PORTA, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_irqB(void)
|
|
||||||
{
|
|
||||||
handle_interrupt_in(PORTB, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_irqC(void)
|
|
||||||
{
|
|
||||||
handle_interrupt_in(PORTC, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_irqD(void)
|
|
||||||
{
|
|
||||||
handle_interrupt_in(PORTD, 96);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_irqE(void)
|
|
||||||
{
|
|
||||||
handle_interrupt_in(PORTE, 128);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) {
|
|
||||||
if (pin == NC)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
irq_handler = handler;
|
|
||||||
|
|
||||||
obj->port = pin >> PORT_SHIFT;
|
|
||||||
obj->pin = (pin & 0x7F) >> 2;
|
|
||||||
|
|
||||||
uint32_t ch_base, vector;
|
|
||||||
IRQn_Type irq_n;
|
|
||||||
switch (obj->port) {
|
|
||||||
case PortA:
|
|
||||||
ch_base = 0;
|
|
||||||
irq_n = PORTA_IRQn;
|
|
||||||
vector = (uint32_t)gpio_irqA;
|
|
||||||
break;
|
|
||||||
case PortB:
|
|
||||||
ch_base = 32;
|
|
||||||
irq_n = PORTB_IRQn;
|
|
||||||
vector = (uint32_t)gpio_irqB;
|
|
||||||
break;
|
|
||||||
case PortC:
|
|
||||||
ch_base = 64;
|
|
||||||
irq_n = PORTC_IRQn;
|
|
||||||
vector = (uint32_t)gpio_irqC;
|
|
||||||
break;
|
|
||||||
case PortD:
|
|
||||||
ch_base = 96;
|
|
||||||
irq_n = PORTD_IRQn; vector = (uint32_t)gpio_irqD;
|
|
||||||
break;
|
|
||||||
case PortE:
|
|
||||||
ch_base = 128;
|
|
||||||
irq_n = PORTE_IRQn;
|
|
||||||
vector = (uint32_t)gpio_irqE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
error("gpio_irq only supported on port A-E.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
NVIC_SetVector(irq_n, vector);
|
|
||||||
NVIC_EnableIRQ(irq_n);
|
|
||||||
|
|
||||||
obj->ch = ch_base + obj->pin;
|
|
||||||
channel_ids[obj->ch] = id;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_irq_free(gpio_irq_t *obj) {
|
|
||||||
channel_ids[obj->ch] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|
||||||
PORT_Type *port = (PORT_Type *)(PORTA_BASE + 0x1000 * obj->port);
|
|
||||||
|
|
||||||
uint32_t irq_settings = IRQ_DISABLED;
|
|
||||||
|
|
||||||
switch (port->PCR[obj->pin] & PORT_PCR_IRQC_MASK) {
|
|
||||||
case IRQ_DISABLED:
|
|
||||||
if (enable)
|
|
||||||
irq_settings = (event == IRQ_RISE) ? (IRQ_RAISING_EDGE) : (IRQ_FALLING_EDGE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IRQ_RAISING_EDGE:
|
|
||||||
if (enable) {
|
|
||||||
irq_settings = (event == IRQ_RISE) ? (IRQ_RAISING_EDGE) : (IRQ_EITHER_EDGE);
|
|
||||||
} else {
|
|
||||||
if (event == IRQ_FALL)
|
|
||||||
irq_settings = IRQ_RAISING_EDGE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IRQ_FALLING_EDGE:
|
|
||||||
if (enable) {
|
|
||||||
irq_settings = (event == IRQ_FALL) ? (IRQ_FALLING_EDGE) : (IRQ_EITHER_EDGE);
|
|
||||||
} else {
|
|
||||||
if (event == IRQ_RISE)
|
|
||||||
irq_settings = IRQ_FALLING_EDGE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IRQ_EITHER_EDGE:
|
|
||||||
if (enable) {
|
|
||||||
irq_settings = IRQ_EITHER_EDGE;
|
|
||||||
} else {
|
|
||||||
irq_settings = (event == IRQ_RISE) ? (IRQ_FALLING_EDGE) : (IRQ_RAISING_EDGE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interrupt configuration and clear interrupt
|
|
||||||
port->PCR[obj->pin] = (port->PCR[obj->pin] & ~PORT_PCR_IRQC_MASK) | irq_settings | PORT_PCR_ISF_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
|
||||||
switch (obj->port) {
|
|
||||||
case PortA:
|
|
||||||
NVIC_EnableIRQ(PORTA_IRQn);
|
|
||||||
break;
|
|
||||||
case PortB:
|
|
||||||
NVIC_EnableIRQ(PORTB_IRQn);
|
|
||||||
break;
|
|
||||||
case PortC:
|
|
||||||
NVIC_EnableIRQ(PORTC_IRQn);
|
|
||||||
break;
|
|
||||||
case PortD:
|
|
||||||
NVIC_EnableIRQ(PORTD_IRQn);
|
|
||||||
break;
|
|
||||||
case PortE:
|
|
||||||
NVIC_EnableIRQ(PORTE_IRQn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
|
||||||
switch (obj->port) {
|
|
||||||
case PortA:
|
|
||||||
NVIC_DisableIRQ(PORTA_IRQn);
|
|
||||||
break;
|
|
||||||
case PortB:
|
|
||||||
NVIC_DisableIRQ(PORTB_IRQn);
|
|
||||||
break;
|
|
||||||
case PortC:
|
|
||||||
NVIC_DisableIRQ(PORTC_IRQn);
|
|
||||||
break;
|
|
||||||
case PortD:
|
|
||||||
NVIC_DisableIRQ(PORTD_IRQn);
|
|
||||||
break;
|
|
||||||
case PortE:
|
|
||||||
NVIC_DisableIRQ(PORTE_IRQn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "mbed_assert.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PinName pin;
|
|
||||||
uint32_t mask;
|
|
||||||
__IO uint32_t *reg_dir;
|
|
||||||
__IO uint32_t *reg_set;
|
|
||||||
__IO uint32_t *reg_clr;
|
|
||||||
__I uint32_t *reg_in;
|
|
||||||
} 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
|
|
|
@ -1,397 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "i2c_api.h"
|
|
||||||
|
|
||||||
#if DEVICE_I2C
|
|
||||||
|
|
||||||
#include "cmsis.h"
|
|
||||||
#include "pinmap.h"
|
|
||||||
#include "clk_freqs.h"
|
|
||||||
#include "PeripheralPins.h"
|
|
||||||
|
|
||||||
static const uint16_t ICR[0x40] = {
|
|
||||||
20, 22, 24, 26, 28,
|
|
||||||
30, 34, 40, 28, 32,
|
|
||||||
36, 40, 44, 48, 56,
|
|
||||||
68, 48, 56, 64, 72,
|
|
||||||
80, 88, 104, 128, 80,
|
|
||||||
96, 112, 128, 144, 160,
|
|
||||||
192, 240, 160, 192, 224,
|
|
||||||
256, 288, 320, 384, 480,
|
|
||||||
320, 384, 448, 512, 576,
|
|
||||||
640, 768, 960, 640, 768,
|
|
||||||
896, 1024, 1152, 1280, 1536,
|
|
||||||
1920, 1280, 1536, 1792, 2048,
|
|
||||||
2304, 2560, 3072, 3840
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
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_Type*)pinmap_merge(i2c_sda, i2c_scl);
|
|
||||||
MBED_ASSERT((int)obj->i2c != NC);
|
|
||||||
|
|
||||||
#if defined(TARGET_K20DX256)
|
|
||||||
switch ((int)obj->i2c) {
|
|
||||||
case I2C_0: SIM->SCGC4 |= SIM_SCGC4_I2C0_MASK;
|
|
||||||
case I2C_1: SIM->SCGC4 |= SIM_SCGC4_I2C1_MASK;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
SIM->SCGC4 |= SIM_SCGC4_I2C0_MASK;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// set default frequency at 100k
|
|
||||||
i2c_frequency(obj, 100000);
|
|
||||||
|
|
||||||
// enable I2C interface
|
|
||||||
obj->i2c->C1 |= 0x80;
|
|
||||||
|
|
||||||
pinmap_pinout(sda, PinMap_I2C_SDA);
|
|
||||||
pinmap_pinout(scl, PinMap_I2C_SCL);
|
|
||||||
/* enable open drain for I2C pins, only port b available */
|
|
||||||
uint32_t pin_n = (uint32_t)(sda & 0x7C) >> 2;
|
|
||||||
PORTB->PCR[pin_n] |= PORT_PCR_ODE_MASK;
|
|
||||||
pin_n = (uint32_t)(scl & 0x7C) >> 2;
|
|
||||||
PORTB->PCR[pin_n] |= PORT_PCR_ODE_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i2c_start(i2c_t *obj) {
|
|
||||||
// if we are in the middle of a transaction
|
|
||||||
// activate the repeat_start flag
|
|
||||||
if (obj->i2c->S & I2C_S_BUSY_MASK) {
|
|
||||||
obj->i2c->C1 |= 0x04;
|
|
||||||
} else {
|
|
||||||
obj->i2c->C1 |= I2C_C1_MST_MASK;
|
|
||||||
obj->i2c->C1 |= I2C_C1_TX_MASK;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i2c_stop(i2c_t *obj) {
|
|
||||||
volatile uint32_t n = 0;
|
|
||||||
obj->i2c->C1 &= ~I2C_C1_MST_MASK;
|
|
||||||
obj->i2c->C1 &= ~I2C_C1_TX_MASK;
|
|
||||||
while(obj->i2c->S & I2C_S_BUSY_MASK);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timeout_status_poll(i2c_t *obj, uint32_t mask) {
|
|
||||||
uint32_t i, timeout = 100000;
|
|
||||||
|
|
||||||
for (i = 0; i < timeout; i++) {
|
|
||||||
if (obj->i2c->S & mask)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this function waits the end of a tx transfer and return the status of the transaction:
|
|
||||||
// 0: OK ack received
|
|
||||||
// 1: OK ack not received
|
|
||||||
// 2: failure
|
|
||||||
static int i2c_wait_end_tx_transfer(i2c_t *obj) {
|
|
||||||
|
|
||||||
// wait for the interrupt flag
|
|
||||||
if (timeout_status_poll(obj, I2C_S_IICIF_MASK)) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->i2c->S |= I2C_S_IICIF_MASK;
|
|
||||||
|
|
||||||
// wait transfer complete
|
|
||||||
if (timeout_status_poll(obj, I2C_S_TCF_MASK)) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we received the ACK or not
|
|
||||||
return obj->i2c->S & I2C_S_RXAK_MASK ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this function waits the end of a rx transfer and return the status of the transaction:
|
|
||||||
// 0: OK
|
|
||||||
// 1: failure
|
|
||||||
static int i2c_wait_end_rx_transfer(i2c_t *obj) {
|
|
||||||
// wait for the end of the rx transfer
|
|
||||||
if (timeout_status_poll(obj, I2C_S_IICIF_MASK)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->i2c->S |= I2C_S_IICIF_MASK;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i2c_send_nack(i2c_t *obj) {
|
|
||||||
obj->i2c->C1 |= I2C_C1_TXAK_MASK; // NACK
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i2c_send_ack(i2c_t *obj) {
|
|
||||||
obj->i2c->C1 &= ~I2C_C1_TXAK_MASK; // ACK
|
|
||||||
}
|
|
||||||
|
|
||||||
static int i2c_do_write(i2c_t *obj, int value) {
|
|
||||||
// write the data
|
|
||||||
obj->i2c->D = value;
|
|
||||||
|
|
||||||
// init and wait the end of the transfer
|
|
||||||
return i2c_wait_end_tx_transfer(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int i2c_do_read(i2c_t *obj, char * data, int last) {
|
|
||||||
if (last) {
|
|
||||||
i2c_send_nack(obj);
|
|
||||||
} else {
|
|
||||||
i2c_send_ack(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
*data = (obj->i2c->D & 0xFF);
|
|
||||||
|
|
||||||
// start rx transfer and wait the end of the transfer
|
|
||||||
return i2c_wait_end_rx_transfer(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void i2c_frequency(i2c_t *obj, int hz) {
|
|
||||||
uint8_t icr = 0;
|
|
||||||
uint8_t mult = 0;
|
|
||||||
uint32_t error = 0;
|
|
||||||
uint32_t p_error = 0xffffffff;
|
|
||||||
uint32_t ref = 0;
|
|
||||||
uint8_t i, j;
|
|
||||||
// bus clk
|
|
||||||
uint32_t PCLK = bus_frequency();
|
|
||||||
uint32_t pulse = PCLK / (hz * 2);
|
|
||||||
|
|
||||||
// we look for the values that minimize the error
|
|
||||||
|
|
||||||
// test all the MULT values
|
|
||||||
for (i = 1; i < 5; i*=2) {
|
|
||||||
for (j = 0; j < 0x40; j++) {
|
|
||||||
ref = PCLK / (i*ICR[j]);
|
|
||||||
if (ref > (uint32_t)hz)
|
|
||||||
continue;
|
|
||||||
error = hz - ref;
|
|
||||||
if (error < p_error) {
|
|
||||||
icr = j;
|
|
||||||
mult = i/2;
|
|
||||||
p_error = error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pulse = icr | (mult << 6);
|
|
||||||
|
|
||||||
// I2C Rate
|
|
||||||
obj->i2c->F = pulse;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
|
|
||||||
int count;
|
|
||||||
char dummy_read, *ptr;
|
|
||||||
|
|
||||||
if (i2c_start(obj)) {
|
|
||||||
i2c_stop(obj);
|
|
||||||
return I2C_ERROR_BUS_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i2c_do_write(obj, (address | 0x01))) {
|
|
||||||
i2c_stop(obj);
|
|
||||||
return I2C_ERROR_NO_SLAVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set rx mode
|
|
||||||
obj->i2c->C1 &= ~I2C_C1_TX_MASK;
|
|
||||||
|
|
||||||
// Read in bytes
|
|
||||||
for (count = 0; count < (length); count++) {
|
|
||||||
ptr = (count == 0) ? &dummy_read : &data[count - 1];
|
|
||||||
uint8_t stop_ = (count == (length - 1)) ? 1 : 0;
|
|
||||||
if (i2c_do_read(obj, ptr, stop_)) {
|
|
||||||
i2c_stop(obj);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not repeated start, send stop.
|
|
||||||
if (stop)
|
|
||||||
i2c_stop(obj);
|
|
||||||
|
|
||||||
// last read
|
|
||||||
data[count-1] = obj->i2c->D;
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (i2c_start(obj)) {
|
|
||||||
i2c_stop(obj);
|
|
||||||
return I2C_ERROR_BUS_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i2c_do_write(obj, (address & 0xFE))) {
|
|
||||||
i2c_stop(obj);
|
|
||||||
return I2C_ERROR_NO_SLAVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < length; i++) {
|
|
||||||
if(i2c_do_write(obj, data[i])) {
|
|
||||||
i2c_stop(obj);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stop)
|
|
||||||
i2c_stop(obj);
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void i2c_reset(i2c_t *obj) {
|
|
||||||
i2c_stop(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
int i2c_byte_read(i2c_t *obj, int last) {
|
|
||||||
char data;
|
|
||||||
|
|
||||||
// set rx mode
|
|
||||||
obj->i2c->C1 &= ~I2C_C1_TX_MASK;
|
|
||||||
|
|
||||||
// Setup read
|
|
||||||
i2c_do_read(obj, &data, last);
|
|
||||||
|
|
||||||
// set tx mode
|
|
||||||
obj->i2c->C1 |= I2C_C1_TX_MASK;
|
|
||||||
return obj->i2c->D;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i2c_byte_write(i2c_t *obj, int data) {
|
|
||||||
// set tx mode
|
|
||||||
obj->i2c->C1 |= I2C_C1_TX_MASK;
|
|
||||||
|
|
||||||
return !i2c_do_write(obj, (data & 0xFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *i2c_master_sda_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_I2C_SDA;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *i2c_master_scl_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_I2C_SCL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *i2c_slave_sda_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_I2C_SDA;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *i2c_slave_scl_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_I2C_SCL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
void i2c_slave_mode(i2c_t *obj, int enable_slave) {
|
|
||||||
if (enable_slave) {
|
|
||||||
// set slave mode
|
|
||||||
obj->i2c->C1 &= ~I2C_C1_MST_MASK;
|
|
||||||
obj->i2c->C1 |= I2C_C1_IICIE_MASK;
|
|
||||||
} else {
|
|
||||||
// set master mode
|
|
||||||
obj->i2c->C1 |= I2C_C1_MST_MASK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int i2c_slave_receive(i2c_t *obj) {
|
|
||||||
switch(obj->i2c->S) {
|
|
||||||
// read addressed
|
|
||||||
case 0xE6:
|
|
||||||
return 1;
|
|
||||||
// write addressed
|
|
||||||
case 0xE2:
|
|
||||||
return 3;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int i2c_slave_read(i2c_t *obj, char *data, int length) {
|
|
||||||
uint8_t dummy_read;
|
|
||||||
uint8_t * ptr;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
// set rx mode
|
|
||||||
obj->i2c->C1 &= ~I2C_C1_TX_MASK;
|
|
||||||
|
|
||||||
// first dummy read
|
|
||||||
dummy_read = obj->i2c->D;
|
|
||||||
if (i2c_wait_end_rx_transfer(obj))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// read address
|
|
||||||
dummy_read = obj->i2c->D;
|
|
||||||
if (i2c_wait_end_rx_transfer(obj))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// read (length - 1) bytes
|
|
||||||
for (count = 0; count < (length - 1); count++) {
|
|
||||||
data[count] = obj->i2c->D;
|
|
||||||
if (i2c_wait_end_rx_transfer(obj))
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read last byte
|
|
||||||
ptr = (length == 0) ? &dummy_read : (uint8_t *)&data[count];
|
|
||||||
*ptr = obj->i2c->D;
|
|
||||||
|
|
||||||
return (length) ? (count + 1) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i2c_slave_write(i2c_t *obj, const char *data, int length) {
|
|
||||||
int i, count = 0;
|
|
||||||
|
|
||||||
// set tx mode
|
|
||||||
obj->i2c->C1 |= I2C_C1_TX_MASK;
|
|
||||||
|
|
||||||
for (i = 0; i < length; i++) {
|
|
||||||
if (i2c_do_write(obj, data[count++]) == 2)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set rx mode
|
|
||||||
obj->i2c->C1 &= ~I2C_C1_TX_MASK;
|
|
||||||
|
|
||||||
// dummy rx transfer needed
|
|
||||||
// otherwise the master cannot generate a stop bit
|
|
||||||
obj->i2c->D;
|
|
||||||
if (i2c_wait_end_rx_transfer(obj) == 2)
|
|
||||||
return count;
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
|
|
||||||
obj->i2c->A1 = address & 0xfe;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // #if DEVICE_I2C
|
|
|
@ -1,78 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct gpio_irq_s {
|
|
||||||
uint32_t port;
|
|
||||||
uint32_t pin;
|
|
||||||
uint32_t ch;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct port_s {
|
|
||||||
__IO uint32_t *reg_dir;
|
|
||||||
__IO uint32_t *reg_out;
|
|
||||||
__I uint32_t *reg_in;
|
|
||||||
PortName port;
|
|
||||||
uint32_t mask;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct pwmout_s {
|
|
||||||
__IO uint32_t *MOD;
|
|
||||||
__IO uint32_t *SYNC;
|
|
||||||
__IO uint32_t *CnV;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct serial_s {
|
|
||||||
UART_Type *uart;
|
|
||||||
int index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct analogin_s {
|
|
||||||
ADCName adc;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if DEVICE_ANALOGOUT
|
|
||||||
struct dac_s {
|
|
||||||
DACName dac;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
I2C_Type *i2c;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct spi_s {
|
|
||||||
SPI_Type *spi;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "gpio_object.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,39 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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"
|
|
||||||
|
|
||||||
void pin_function(PinName pin, int function) {
|
|
||||||
MBED_ASSERT(pin != (PinName)NC);
|
|
||||||
|
|
||||||
uint32_t port_n = (uint32_t)pin >> PORT_SHIFT;
|
|
||||||
uint32_t pin_n = (uint32_t)(pin & 0x7C) >> 2;
|
|
||||||
|
|
||||||
SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port_n);
|
|
||||||
__IO uint32_t* pin_pcr = &(((PORT_Type *)(PORTA_BASE + 0x1000 * port_n)))->PCR[pin_n];
|
|
||||||
|
|
||||||
// pin mux bits: [10:8] -> 11100000000 = (0x700)
|
|
||||||
*pin_pcr = (*pin_pcr & ~0x700) | (function << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pin_mode(PinName pin, PinMode mode) {
|
|
||||||
MBED_ASSERT(pin != (PinName)NC);
|
|
||||||
__IO uint32_t* pin_pcr = (__IO uint32_t*)(PORTA_BASE + pin);
|
|
||||||
|
|
||||||
// pin pullup bits: [1:0] -> 11 = (0x3)
|
|
||||||
*pin_pcr = (*pin_pcr & ~0x3) | mode;
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 << 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void port_init(port_t *obj, PortName port, int mask, PinDirection dir) {
|
|
||||||
obj->port = port;
|
|
||||||
obj->mask = mask;
|
|
||||||
|
|
||||||
GPIO_Type *reg = (GPIO_Type *)(PTA_BASE + port * 0x40);
|
|
||||||
|
|
||||||
obj->reg_out = ®->PDOR;
|
|
||||||
obj->reg_in = ®->PDIR;
|
|
||||||
obj->reg_dir = ®->PDDR;
|
|
||||||
|
|
||||||
uint32_t i;
|
|
||||||
// The function is set per pin: reuse gpio logic
|
|
||||||
for (i=0; i<32; 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_out = (*obj->reg_in & ~obj->mask) | (value & obj->mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
int port_read(port_t *obj) {
|
|
||||||
return (*obj->reg_in & obj->mask);
|
|
||||||
}
|
|
|
@ -1,153 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "pwmout_api.h"
|
|
||||||
|
|
||||||
#include "cmsis.h"
|
|
||||||
#include "pinmap.h"
|
|
||||||
#include "PeripheralPins.h"
|
|
||||||
|
|
||||||
static float pwm_clock = 0;
|
|
||||||
|
|
||||||
void pwmout_init(pwmout_t *obj, PinName pin)
|
|
||||||
{
|
|
||||||
// determine the channel
|
|
||||||
PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
|
|
||||||
MBED_ASSERT(pwm != (PWMName)NC);
|
|
||||||
|
|
||||||
uint32_t MGCOUTClock = SystemCoreClock * (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT));
|
|
||||||
uint32_t BusClock = MGCOUTClock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT));
|
|
||||||
|
|
||||||
uint32_t clkdiv = 0;
|
|
||||||
float clkval = BusClock / 1000000.0f;
|
|
||||||
|
|
||||||
while (clkval > 1) {
|
|
||||||
clkdiv++;
|
|
||||||
clkval /= 2.0;
|
|
||||||
if (clkdiv == 7) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pwm_clock = clkval;
|
|
||||||
unsigned int ftm_n = (pwm >> TPM_SHIFT);
|
|
||||||
unsigned int ch_n = (pwm & 0xFF);
|
|
||||||
|
|
||||||
SIM->SCGC6 |= 1 << (SIM_SCGC6_FTM0_SHIFT + ftm_n);
|
|
||||||
|
|
||||||
FTM_Type *ftm = (FTM_Type *)(FTM0_BASE + 0x1000 * ftm_n);
|
|
||||||
ftm->CONF |= FTM_CONF_BDMMODE(3);
|
|
||||||
ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(clkdiv); // (clock)MHz / clkdiv ~= (0.75)MHz
|
|
||||||
ftm->CONTROLS[ch_n].CnSC = (FTM_CnSC_MSB_MASK | FTM_CnSC_ELSB_MASK); /* No Interrupts; High True pulses on Edge Aligned PWM */
|
|
||||||
ftm->MODE = FTM_MODE_FTMEN_MASK;
|
|
||||||
ftm->SYNC = FTM_SYNC_CNTMIN_MASK;
|
|
||||||
ftm->SYNCONF = FTM_SYNCONF_SYNCMODE_MASK | FTM_SYNCONF_SWSOC_MASK | FTM_SYNCONF_SWWRBUF_MASK;
|
|
||||||
|
|
||||||
//Without SYNCEN set CnV does not seem to update
|
|
||||||
ftm->COMBINE = FTM_COMBINE_SYNCEN0_MASK | FTM_COMBINE_SYNCEN1_MASK | FTM_COMBINE_SYNCEN2_MASK | FTM_COMBINE_SYNCEN3_MASK;
|
|
||||||
|
|
||||||
obj->CnV = &ftm->CONTROLS[ch_n].CnV;
|
|
||||||
obj->MOD = &ftm->MOD;
|
|
||||||
obj->SYNC = &ftm->SYNC;
|
|
||||||
|
|
||||||
// default to 20ms: standard for servos, and fine for e.g. brightness control
|
|
||||||
pwmout_period_ms(obj, 20);
|
|
||||||
pwmout_write(obj, 0.0);
|
|
||||||
|
|
||||||
// Wire pinout
|
|
||||||
pinmap_pinout(pin, PinMap_PWM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pwmout_free(pwmout_t *obj) {}
|
|
||||||
|
|
||||||
void pwmout_write(pwmout_t *obj, float value)
|
|
||||||
{
|
|
||||||
if (value < 0.0) {
|
|
||||||
value = 0.0;
|
|
||||||
} else if (value > 1.0) {
|
|
||||||
value = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*obj->SYNC & FTM_SYNC_SWSYNC_MASK);
|
|
||||||
*obj->CnV = (uint32_t)((float)(*obj->MOD + 1) * value);
|
|
||||||
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
float pwmout_read(pwmout_t *obj)
|
|
||||||
{
|
|
||||||
while (*obj->SYNC & FTM_SYNC_SWSYNC_MASK);
|
|
||||||
float v = (float)(*obj->CnV) / (float)(*obj->MOD + 1);
|
|
||||||
return (v > 1.0) ? (1.0) : (v);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the PWM period, keeping the duty cycle the same.
|
|
||||||
void pwmout_period_us(pwmout_t *obj, int us)
|
|
||||||
{
|
|
||||||
float dc = pwmout_read(obj);
|
|
||||||
*obj->MOD = (uint32_t)(pwm_clock * (float)us) - 1;
|
|
||||||
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
|
|
||||||
pwmout_write(obj, dc);
|
|
||||||
}
|
|
||||||
|
|
||||||
int pwmout_read_period_us(pwmout_t *obj)
|
|
||||||
{
|
|
||||||
uint32_t pwm_period = 0;
|
|
||||||
if (pwm_clock > 0) {
|
|
||||||
pwm_period = ((*obj->MOD) + 1) / pwm_clock;
|
|
||||||
}
|
|
||||||
return pwm_period;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
*obj->CnV = (uint32_t)(pwm_clock * (float)us);
|
|
||||||
*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pwmout_read_pulsewidth_us(pwmout_t *obj)
|
|
||||||
{
|
|
||||||
uint32_t pwm_pulsewidth = 0;
|
|
||||||
if (pwm_clock > 0) {
|
|
||||||
pwm_pulsewidth = (*obj->CnV) / pwm_clock;
|
|
||||||
}
|
|
||||||
return pwm_pulsewidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *pwmout_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_PWM;
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "rtc_api.h"
|
|
||||||
|
|
||||||
static void init(void) {
|
|
||||||
// enable PORTC clock
|
|
||||||
SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK;
|
|
||||||
|
|
||||||
// enable RTC clock
|
|
||||||
SIM->SCGC6 |= SIM_SCGC6_RTC_MASK;
|
|
||||||
|
|
||||||
// OSC32 as source
|
|
||||||
SIM->SOPT1 &= ~SIM_SOPT1_OSC32KSEL_MASK;
|
|
||||||
SIM->SOPT1 |= SIM_SOPT1_OSC32KSEL(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_init(void) {
|
|
||||||
init();
|
|
||||||
|
|
||||||
// Enable the oscillator
|
|
||||||
// Teensy3.1 requires 20pF MCU loading capacitors for 32KHz RTC oscillator
|
|
||||||
/* RTC->CR: SC2P=0,SC4P=1,SC8P=0,SC16P=1,CLKO=0,OSCE=1,UM=0,SUP=0,SPE=0,SWR=0 */
|
|
||||||
RTC->CR |= RTC_CR_OSCE_MASK |RTC_CR_SC16P_MASK | RTC_CR_SC4P_MASK;
|
|
||||||
|
|
||||||
//Configure the TSR. default value: 1
|
|
||||||
RTC->TSR = 1;
|
|
||||||
|
|
||||||
// enable counter
|
|
||||||
RTC->SR |= RTC_SR_TCE_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_free(void) {
|
|
||||||
// [TODO]
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Little check routine to see if the RTC has been enabled
|
|
||||||
* 0 = Disabled, 1 = Enabled
|
|
||||||
*/
|
|
||||||
int rtc_isenabled(void) {
|
|
||||||
// even if the RTC module is enabled,
|
|
||||||
// as we use RTC_CLKIN and an external clock,
|
|
||||||
// we need to reconfigure the pins. That is why we
|
|
||||||
// call init() if the rtc is enabled
|
|
||||||
|
|
||||||
// if RTC not enabled return 0
|
|
||||||
SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK;
|
|
||||||
SIM->SCGC6 |= SIM_SCGC6_RTC_MASK;
|
|
||||||
if ((RTC->SR & RTC_SR_TCE_MASK) == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
init();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t rtc_read(void) {
|
|
||||||
return RTC->TSR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_write(time_t t) {
|
|
||||||
// disable counter
|
|
||||||
RTC->SR &= ~RTC_SR_TCE_MASK;
|
|
||||||
|
|
||||||
// write seconds
|
|
||||||
RTC->TSR = t;
|
|
||||||
|
|
||||||
// re-enable counter
|
|
||||||
RTC->SR |= RTC_SR_TCE_MASK;
|
|
||||||
}
|
|
|
@ -1,334 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "serial_api.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "cmsis.h"
|
|
||||||
#include "pinmap.h"
|
|
||||||
#include "clk_freqs.h"
|
|
||||||
#include "PeripheralPins.h"
|
|
||||||
|
|
||||||
#define UART_NUM 3
|
|
||||||
|
|
||||||
static uint32_t serial_irq_ids[UART_NUM] = {0};
|
|
||||||
static uart_irq_handler irq_handler;
|
|
||||||
|
|
||||||
int stdio_uart_inited = 0;
|
|
||||||
serial_t stdio_uart;
|
|
||||||
|
|
||||||
void serial_init(serial_t *obj, PinName tx, PinName rx) {
|
|
||||||
// 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);
|
|
||||||
MBED_ASSERT((int)uart != NC);
|
|
||||||
|
|
||||||
obj->uart = (UART_Type *)uart;
|
|
||||||
// enable clk
|
|
||||||
switch (uart) {
|
|
||||||
case UART_0:
|
|
||||||
mcgpllfll_frequency();
|
|
||||||
SIM->SCGC4 |= SIM_SCGC4_UART0_MASK;
|
|
||||||
break;
|
|
||||||
case UART_1:
|
|
||||||
mcgpllfll_frequency();
|
|
||||||
SIM->SCGC4 |= SIM_SCGC4_UART1_MASK;
|
|
||||||
break;
|
|
||||||
case UART_2:
|
|
||||||
SIM->SCGC4 |= SIM_SCGC4_UART2_MASK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Disable UART before changing registers
|
|
||||||
obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
|
|
||||||
|
|
||||||
switch (uart) {
|
|
||||||
case UART_0:
|
|
||||||
obj->index = 0;
|
|
||||||
break;
|
|
||||||
case UART_1:
|
|
||||||
obj->index = 1;
|
|
||||||
break;
|
|
||||||
case UART_2:
|
|
||||||
obj->index = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set default baud rate and format
|
|
||||||
serial_baud (obj, 9600);
|
|
||||||
serial_format(obj, 8, ParityNone, 1);
|
|
||||||
|
|
||||||
// pinout the chosen uart
|
|
||||||
pinmap_pinout(tx, PinMap_UART_TX);
|
|
||||||
pinmap_pinout(rx, PinMap_UART_RX);
|
|
||||||
|
|
||||||
// set rx/tx pins in PullUp mode
|
|
||||||
if (tx != NC) {
|
|
||||||
pin_mode(tx, PullUp);
|
|
||||||
}
|
|
||||||
if (rx != NC) {
|
|
||||||
pin_mode(rx, PullUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->uart->C2 |= (UART_C2_RE_MASK | UART_C2_TE_MASK);
|
|
||||||
|
|
||||||
if (uart == STDIO_UART) {
|
|
||||||
stdio_uart_inited = 1;
|
|
||||||
memcpy(&stdio_uart, obj, sizeof(serial_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void serial_free(serial_t *obj) {
|
|
||||||
serial_irq_ids[obj->index] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void serial_baud(serial_t *obj, int baudrate) {
|
|
||||||
// save C2 state
|
|
||||||
uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
|
|
||||||
|
|
||||||
// Disable UART before changing registers
|
|
||||||
obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
|
|
||||||
|
|
||||||
uint32_t PCLK;
|
|
||||||
if (obj->uart != UART2) {
|
|
||||||
PCLK = mcgpllfll_frequency();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PCLK = bus_frequency();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t DL = PCLK / (16 * baudrate);
|
|
||||||
uint32_t BRFA = (2 * PCLK) / baudrate - 32 * DL;
|
|
||||||
|
|
||||||
// set BDH and BDL
|
|
||||||
obj->uart->BDH = (obj->uart->BDH & ~(0x1f)) | ((DL >> 8) & 0x1f);
|
|
||||||
obj->uart->BDL = (obj->uart->BDL & ~(0xff)) | ((DL >> 0) & 0xff);
|
|
||||||
|
|
||||||
obj->uart->C4 &= ~0x1F;
|
|
||||||
obj->uart->C4 |= BRFA & 0x1F;
|
|
||||||
|
|
||||||
// restore C2 state
|
|
||||||
obj->uart->C2 |= c2_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
|
|
||||||
MBED_ASSERT((stop_bits == 1) || (stop_bits == 2));
|
|
||||||
MBED_ASSERT((parity == ParityNone) || (parity == ParityOdd) || (parity == ParityEven));
|
|
||||||
MBED_ASSERT((data_bits == 8) || (data_bits == 9));
|
|
||||||
|
|
||||||
// save C2 state
|
|
||||||
uint32_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
|
|
||||||
|
|
||||||
// Disable UART before changing registers
|
|
||||||
obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
|
|
||||||
|
|
||||||
// 8 data bits = 0 ... 9 data bits = 1
|
|
||||||
data_bits -= 8;
|
|
||||||
|
|
||||||
uint32_t parity_enable, parity_select;
|
|
||||||
switch (parity) {
|
|
||||||
case ParityNone:
|
|
||||||
parity_enable = 0;
|
|
||||||
parity_select = 0;
|
|
||||||
break;
|
|
||||||
case ParityOdd :
|
|
||||||
parity_enable = 1;
|
|
||||||
parity_select = 1;
|
|
||||||
data_bits++;
|
|
||||||
break;
|
|
||||||
case ParityEven:
|
|
||||||
parity_enable = 1;
|
|
||||||
parity_select = 0;
|
|
||||||
data_bits++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_bits -= 1;
|
|
||||||
|
|
||||||
uint32_t m10 = 0;
|
|
||||||
|
|
||||||
// 9 data bits + parity - only uart0 support
|
|
||||||
if (data_bits == 2) {
|
|
||||||
MBED_ASSERT(obj->index == 0);
|
|
||||||
data_bits = 0;
|
|
||||||
m10 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// data bits, parity and parity mode
|
|
||||||
obj->uart->C1 = ((data_bits << 4)
|
|
||||||
| (parity_enable << 1)
|
|
||||||
| (parity_select << 0));
|
|
||||||
|
|
||||||
//enable 10bit mode if needed
|
|
||||||
if (obj->index == 0) {
|
|
||||||
obj->uart->C4 &= ~UART_C4_M10_MASK;
|
|
||||||
obj->uart->C4 |= (m10 << UART_C4_M10_SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop bits
|
|
||||||
obj->uart->BDH &= ~UART_BDH_SBR_MASK;
|
|
||||||
obj->uart->BDH |= (stop_bits << UART_BDH_SBR_SHIFT);
|
|
||||||
|
|
||||||
// restore C2 state
|
|
||||||
obj->uart->C2 |= c2_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* INTERRUPTS HANDLING
|
|
||||||
******************************************************************************/
|
|
||||||
static inline void uart_irq(uint8_t status, uint32_t index) {
|
|
||||||
if (serial_irq_ids[index] != 0) {
|
|
||||||
if (status & UART_S1_TDRE_MASK)
|
|
||||||
irq_handler(serial_irq_ids[index], TxIrq);
|
|
||||||
|
|
||||||
if (status & UART_S1_RDRF_MASK)
|
|
||||||
irq_handler(serial_irq_ids[index], RxIrq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart0_irq() {uart_irq(UART0->S1, 0);}
|
|
||||||
void uart1_irq() {uart_irq(UART1->S1, 1);}
|
|
||||||
void uart2_irq() {uart_irq(UART2->S1, 2);}
|
|
||||||
|
|
||||||
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;
|
|
||||||
switch ((int)obj->uart) {
|
|
||||||
case UART_0:
|
|
||||||
irq_n=UART0_RX_TX_IRQn;
|
|
||||||
vector = (uint32_t)&uart0_irq;
|
|
||||||
break;
|
|
||||||
case UART_1:
|
|
||||||
irq_n=UART1_RX_TX_IRQn;
|
|
||||||
vector = (uint32_t)&uart1_irq;
|
|
||||||
break;
|
|
||||||
case UART_2:
|
|
||||||
irq_n=UART2_RX_TX_IRQn;
|
|
||||||
vector = (uint32_t)&uart2_irq;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enable) {
|
|
||||||
switch (irq) {
|
|
||||||
case RxIrq:
|
|
||||||
obj->uart->C2 |= (UART_C2_RIE_MASK);
|
|
||||||
break;
|
|
||||||
case TxIrq:
|
|
||||||
obj->uart->C2 |= (UART_C2_TIE_MASK);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
NVIC_SetVector(irq_n, vector);
|
|
||||||
NVIC_EnableIRQ(irq_n);
|
|
||||||
|
|
||||||
} else { // disable
|
|
||||||
int all_disabled = 0;
|
|
||||||
SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
|
|
||||||
switch (irq) {
|
|
||||||
case RxIrq:
|
|
||||||
obj->uart->C2 &= ~(UART_C2_RIE_MASK);
|
|
||||||
break;
|
|
||||||
case TxIrq:
|
|
||||||
obj->uart->C2 &= ~(UART_C2_TIE_MASK);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (other_irq) {
|
|
||||||
case RxIrq:
|
|
||||||
all_disabled = (obj->uart->C2 & (UART_C2_RIE_MASK)) == 0;
|
|
||||||
break;
|
|
||||||
case TxIrq:
|
|
||||||
all_disabled = (obj->uart->C2 & (UART_C2_TIE_MASK)) == 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (all_disabled)
|
|
||||||
NVIC_DisableIRQ(irq_n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int serial_getc(serial_t *obj) {
|
|
||||||
while (!serial_readable(obj));
|
|
||||||
return obj->uart->D;
|
|
||||||
}
|
|
||||||
|
|
||||||
void serial_putc(serial_t *obj, int c) {
|
|
||||||
while (!serial_writable(obj));
|
|
||||||
obj->uart->D = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
int serial_readable(serial_t *obj) {
|
|
||||||
|
|
||||||
return (obj->uart->S1 & UART_S1_RDRF_MASK);
|
|
||||||
}
|
|
||||||
|
|
||||||
int serial_writable(serial_t *obj) {
|
|
||||||
|
|
||||||
return (obj->uart->S1 & UART_S1_TDRE_MASK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void serial_clear(serial_t *obj) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void serial_pinout_tx(PinName tx) {
|
|
||||||
pinmap_pinout(tx, PinMap_UART_TX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void serial_break_set(serial_t *obj) {
|
|
||||||
obj->uart->C2 |= UART_C2_SBK_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void serial_break_clear(serial_t *obj) {
|
|
||||||
obj->uart->C2 &= ~UART_C2_SBK_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *serial_tx_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_UART_TX;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *serial_rx_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_UART_RX;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *serial_cts_pinmap()
|
|
||||||
{
|
|
||||||
#if !DEVICE_SERIAL_FC
|
|
||||||
static const PinMap PinMap_UART_CTS[] = {
|
|
||||||
{NC, NC, 0}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return PinMap_UART_CTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *serial_rts_pinmap()
|
|
||||||
{
|
|
||||||
#if !DEVICE_SERIAL_FC
|
|
||||||
static const PinMap PinMap_UART_RTS[] = {
|
|
||||||
{NC, NC, 0}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return PinMap_UART_RTS;
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "sleep_api.h"
|
|
||||||
#include "cmsis.h"
|
|
||||||
|
|
||||||
//Normal wait mode
|
|
||||||
void hal_sleep(void)
|
|
||||||
{
|
|
||||||
SMC->PMPROT = SMC_PMPROT_AVLLS_MASK | SMC_PMPROT_ALLS_MASK | SMC_PMPROT_AVLP_MASK;
|
|
||||||
|
|
||||||
//Normal sleep mode for ARM core:
|
|
||||||
SCB->SCR = 0;
|
|
||||||
__WFI();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Very low-power stop mode
|
|
||||||
void hal_deepsleep(void)
|
|
||||||
{
|
|
||||||
//Check if ADC is enabled and HS mode is set, if yes disable it (lowers power consumption by 60uA)
|
|
||||||
uint8_t ADC_HSC = 0;
|
|
||||||
if (SIM->SCGC6 & SIM_SCGC6_ADC0_MASK) {
|
|
||||||
if (ADC0->CFG2 & ADC_CFG2_ADHSC_MASK) {
|
|
||||||
ADC_HSC = 1;
|
|
||||||
ADC0->CFG2 &= ~(ADC_CFG2_ADHSC_MASK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if PLL/FLL is enabled:
|
|
||||||
uint32_t PLL_FLL_en = (MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0);
|
|
||||||
|
|
||||||
SMC->PMPROT = SMC_PMPROT_AVLLS_MASK | SMC_PMPROT_ALLS_MASK | SMC_PMPROT_AVLP_MASK;
|
|
||||||
SMC->PMCTRL = SMC_PMCTRL_STOPM(2);
|
|
||||||
|
|
||||||
//Deep sleep for ARM core:
|
|
||||||
SCB->SCR = 1<<SCB_SCR_SLEEPDEEP_Pos;
|
|
||||||
|
|
||||||
__WFI();
|
|
||||||
//Switch back to PLL as clock source if needed
|
|
||||||
//The interrupt that woke up the device will run at reduced speed
|
|
||||||
if (PLL_FLL_en) {
|
|
||||||
|
|
||||||
// MCG->C1: CLKS=2,FRDIV=3,IREFS=0,IRCLKEN=1,IREFSTEN=0
|
|
||||||
MCG->C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3) | MCG_C1_IRCLKEN_MASK;
|
|
||||||
// MCG->C6: LOLIE=0,PLLS=0,CME=0,VDIV0=0
|
|
||||||
MCG->C6 = MCG_C6_VDIV0(0);
|
|
||||||
while((MCG->S & MCG_S_OSCINIT0_MASK) == 0u) { } // Check that the oscillator is running
|
|
||||||
while((MCG->S & 0x0Cu) != 0x08u) { } // Wait until external reference clock is selected as MCG output
|
|
||||||
// MCG->C5: PLLCLKEN=0,PLLSTEN=0,PRDIV0=3
|
|
||||||
MCG->C5 = MCG_C5_PRDIV0(5);
|
|
||||||
// MCG->C6: LOLIE=0,PLLS=1,CME=0,VDIV0=3
|
|
||||||
MCG->C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV0(3);
|
|
||||||
while((MCG->S & 0x0Cu) != 0x08u) { } // Wait until external reference clock is selected as MCG output
|
|
||||||
while((MCG->S & MCG_S_PLLST_MASK) == 0u) { } // Wait until the source of the PLLS clock has switched to the PLL
|
|
||||||
while((MCG->S & MCG_S_LOCK0_MASK) == 0u) { } // Wait until locked
|
|
||||||
// MCG->C1: CLKS=0,FRDIV=2,IREFS=0,IRCLKEN=1,IREFSTEN=0
|
|
||||||
MCG->C1 = MCG_C1_FRDIV(2) | MCG_C1_IRCLKEN_MASK;;
|
|
||||||
while((MCG->S & 0x0Cu) != 0x0Cu) { } // Wait until output of the PLL is selected
|
|
||||||
while((MCG->S & MCG_S_LOCK0_MASK) == 0u) { } // Wait until locked
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ADC_HSC) {
|
|
||||||
ADC0->CFG2 |= (ADC_CFG2_ADHSC_MASK);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,210 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2015 ARM Limited
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* 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 "spi_api.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "cmsis.h"
|
|
||||||
#include "pinmap.h"
|
|
||||||
#include "clk_freqs.h"
|
|
||||||
#include "PeripheralPins.h"
|
|
||||||
|
|
||||||
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_Type*)pinmap_merge(spi_data, spi_cntl);
|
|
||||||
MBED_ASSERT((int)obj->spi != NC);
|
|
||||||
|
|
||||||
SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK;
|
|
||||||
SIM->SCGC6 |= SIM_SCGC6_SPI0_MASK;
|
|
||||||
|
|
||||||
obj->spi->MCR &= ~(SPI_MCR_MDIS_MASK | SPI_MCR_HALT_MASK);
|
|
||||||
//obj->spi->MCR |= SPI_MCR_DIS_RXF_MASK | SPI_MCR_DIS_TXF_MASK;
|
|
||||||
|
|
||||||
// not halt in the debug mode
|
|
||||||
obj->spi->SR |= SPI_SR_EOQF_MASK;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void spi_free(spi_t *obj) {
|
|
||||||
// [TODO]
|
|
||||||
}
|
|
||||||
void spi_format(spi_t *obj, int bits, int mode, int slave) {
|
|
||||||
MBED_ASSERT((bits > 4) || (bits < 16));
|
|
||||||
MBED_ASSERT((mode >= 0) && (mode <= 3));
|
|
||||||
|
|
||||||
uint8_t polarity = (mode & 0x2) ? 1 : 0;
|
|
||||||
uint8_t phase = (mode & 0x1) ? 1 : 0;
|
|
||||||
uint8_t old_polarity = (obj->spi->CTAR[0] & SPI_CTAR_CPOL_MASK) != 0;
|
|
||||||
|
|
||||||
// set master/slave
|
|
||||||
if (slave) {
|
|
||||||
obj->spi->MCR &= ~SPI_MCR_MSTR_MASK;
|
|
||||||
} else {
|
|
||||||
obj->spi->MCR |= (1UL << SPI_MCR_MSTR_SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CTAR0 is used
|
|
||||||
obj->spi->CTAR[0] &= ~(SPI_CTAR_CPHA_MASK | SPI_CTAR_CPOL_MASK | SPI_CTAR_FMSZ_MASK);
|
|
||||||
obj->spi->CTAR[0] |= (polarity << SPI_CTAR_CPOL_SHIFT) | (phase << SPI_CTAR_CPHA_SHIFT) | ((bits - 1) << SPI_CTAR_FMSZ_SHIFT);
|
|
||||||
|
|
||||||
//If clk idle state was changed, start a dummy transmission
|
|
||||||
//This is a 'feature' in DSPI: https://community.freescale.com/thread/105526
|
|
||||||
if ((old_polarity != polarity) && (slave == 0)) {
|
|
||||||
//Start transfer (CS should be high, so shouldn't matter)
|
|
||||||
spi_master_write(obj, 0xFFFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const uint8_t baudrate_prescaler[] = {2,3,5,7};
|
|
||||||
static const uint16_t baudrate_scaler[] = {2,4,6,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
|
|
||||||
|
|
||||||
void spi_frequency(spi_t *obj, int hz) {
|
|
||||||
uint32_t f_error = 0;
|
|
||||||
uint32_t p_error = 0xffffffff;
|
|
||||||
uint32_t ref = 0;
|
|
||||||
uint32_t br = 0;
|
|
||||||
uint32_t ref_spr = 0;
|
|
||||||
uint32_t ref_prescaler = 0;
|
|
||||||
uint32_t ref_dr = 0;
|
|
||||||
|
|
||||||
// bus clk
|
|
||||||
uint32_t PCLK = bus_frequency();
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 4; i++) {
|
|
||||||
for (br = 0; br <= 15; br++) {
|
|
||||||
for (uint32_t dr = 0; dr < 2; dr++) {
|
|
||||||
ref = (PCLK * (1U + dr) / baudrate_prescaler[i]) / baudrate_scaler[br];
|
|
||||||
if (ref > (uint32_t)hz)
|
|
||||||
continue;
|
|
||||||
f_error = hz - ref;
|
|
||||||
if (f_error < p_error) {
|
|
||||||
ref_spr = br;
|
|
||||||
ref_prescaler = i;
|
|
||||||
ref_dr = dr;
|
|
||||||
p_error = f_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set PBR and BR
|
|
||||||
obj->spi->CTAR[0] &= ~(SPI_CTAR_PBR_MASK | SPI_CTAR_BR_MASK | SPI_CTAR_DBR_MASK);
|
|
||||||
obj->spi->CTAR[0] |= (ref_prescaler << SPI_CTAR_PBR_SHIFT) | (ref_spr << SPI_CTAR_BR_SHIFT) | (ref_dr << SPI_CTAR_DBR_SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int spi_writeable(spi_t *obj) {
|
|
||||||
return (obj->spi->SR & SPI_SR_TFFF_MASK) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int spi_readable(spi_t *obj) {
|
|
||||||
return (obj->spi->SR & SPI_SR_RFDF_MASK) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int spi_master_write(spi_t *obj, int value) {
|
|
||||||
//clear RX buffer flag
|
|
||||||
obj->spi->SR |= SPI_SR_RFDF_MASK;
|
|
||||||
// wait tx buffer empty
|
|
||||||
while(!spi_writeable(obj));
|
|
||||||
obj->spi->PUSHR = SPI_PUSHR_TXDATA(value & 0xffff) /*| SPI_PUSHR_EOQ_MASK*/;
|
|
||||||
|
|
||||||
// wait rx buffer full
|
|
||||||
while (!spi_readable(obj));
|
|
||||||
return obj->spi->POPR;
|
|
||||||
}
|
|
||||||
|
|
||||||
int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
|
|
||||||
char *rx_buffer, int rx_length, char write_fill) {
|
|
||||||
int total = (tx_length > rx_length) ? tx_length : rx_length;
|
|
||||||
|
|
||||||
for (int i = 0; i < total; i++) {
|
|
||||||
char out = (i < tx_length) ? tx_buffer[i] : write_fill;
|
|
||||||
char in = spi_master_write(obj, out);
|
|
||||||
if (i < rx_length) {
|
|
||||||
rx_buffer[i] = in;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
int spi_slave_receive(spi_t *obj) {
|
|
||||||
return spi_readable(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
int spi_slave_read(spi_t *obj) {
|
|
||||||
obj->spi->SR |= SPI_SR_RFDF_MASK;
|
|
||||||
return obj->spi->POPR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spi_slave_write(spi_t *obj, int value) {
|
|
||||||
while (!spi_writeable(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *spi_master_mosi_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_SPI_MOSI;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *spi_master_miso_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_SPI_MISO;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *spi_master_clk_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_SPI_SCLK;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *spi_master_cs_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_SPI_SSEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *spi_slave_mosi_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_SPI_MOSI;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *spi_slave_miso_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_SPI_MISO;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *spi_slave_clk_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_SPI_SCLK;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PinMap *spi_slave_cs_pinmap()
|
|
||||||
{
|
|
||||||
return PinMap_SPI_SSEL;
|
|
||||||
}
|
|
Loading…
Reference in New Issue