Merge pull request #144 from 0xc0170/dev_k20d5m_testing

K20D50M target - pwm and clocks in HAL
pull/146/head
Bogdan Marinescu 2014-01-14 12:42:22 -08:00
commit cee9a71069
8 changed files with 230 additions and 63 deletions

View File

@ -18,6 +18,7 @@
#include "cmsis.h" #include "cmsis.h"
#include "pinmap.h" #include "pinmap.h"
#include "error.h" #include "error.h"
#include "clk_freqs.h"
static const PinMap PinMap_ADC[] = { static const PinMap PinMap_ADC[] = {
{PTC2, ADC0_SE4b, 0}, {PTC2, ADC0_SE4b, 0},
@ -33,6 +34,8 @@ static const PinMap PinMap_ADC[] = {
{NC, NC, 0} {NC, NC, 0}
}; };
#define MAX_FADC 6000000
void analogin_init(analogin_t *obj, PinName pin) { void analogin_init(analogin_t *obj, PinName pin) {
obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC); obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
if (obj->adc == (ADCName)NC) if (obj->adc == (ADCName)NC)
@ -43,13 +46,23 @@ void analogin_init(analogin_t *obj, PinName pin) {
uint32_t port = (uint32_t)pin >> PORT_SHIFT; uint32_t port = (uint32_t)pin >> PORT_SHIFT;
SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port); 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->SC1[1] = ADC_SC1_ADCH(obj->adc);
ADC0->CFG1 = ADC_CFG1_ADLPC_MASK // Low-Power Configuration ADC0->CFG1 = ADC_CFG1_ADLPC_MASK // Low-Power Configuration
| ADC_CFG1_ADIV(3) // Clock Divide Select: (Input Clock)/8 | ADC_CFG1_ADIV(clkdiv & 0x3) // Clock Divide Select
| ADC_CFG1_ADLSMP_MASK // Long Sample Time | ADC_CFG1_ADLSMP_MASK // Long Sample Time
| ADC_CFG1_MODE(3) // (16)bits Resolution | ADC_CFG1_MODE(3) // (16)bits Resolution
| ADC_CFG1_ADICLK(1); // Input Clock: (Bus Clock)/2 | ADC_CFG1_ADICLK(clkdiv >> 2); // Input Clock
ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK // ADxxb or ADxxa channels ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK // ADxxb or ADxxa channels
| ADC_CFG2_ADACKEN_MASK // Asynchronous Clock Output Enable | ADC_CFG2_ADACKEN_MASK // Asynchronous Clock Output Enable

View File

@ -0,0 +1,97 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 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 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_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_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;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -18,6 +18,7 @@
#include "cmsis.h" #include "cmsis.h"
#include "pinmap.h" #include "pinmap.h"
#include "error.h" #include "error.h"
#include "clk_freqs.h"
static const PinMap PinMap_I2C_SDA[] = { static const PinMap PinMap_I2C_SDA[] = {
{PTB1, I2C_0, 2}, {PTB1, I2C_0, 2},
@ -165,10 +166,11 @@ static int i2c_do_write(i2c_t *obj, int value) {
} }
static int i2c_do_read(i2c_t *obj, char * data, int last) { static int i2c_do_read(i2c_t *obj, char * data, int last) {
if (last) if (last) {
i2c_send_nack(obj); i2c_send_nack(obj);
else } else {
i2c_send_ack(obj); i2c_send_ack(obj);
}
*data = (obj->i2c->D & 0xFF); *data = (obj->i2c->D & 0xFF);
@ -184,7 +186,7 @@ void i2c_frequency(i2c_t *obj, int hz) {
uint32_t ref = 0; uint32_t ref = 0;
uint8_t i, j; uint8_t i, j;
// bus clk // bus clk
uint32_t PCLK = 24000000u; uint32_t PCLK = bus_frequency();
uint32_t pulse = PCLK / (hz * 2); uint32_t pulse = PCLK / (hz * 2);
// we look for the values that minimize the error // we look for the values that minimize the error
@ -237,9 +239,8 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
} }
// If not repeated start, send stop. // If not repeated start, send stop.
if (stop) { if (stop)
i2c_stop(obj); i2c_stop(obj);
}
// last read // last read
data[count-1] = obj->i2c->D; data[count-1] = obj->i2c->D;
@ -326,11 +327,9 @@ int i2c_slave_receive(i2c_t *obj) {
// read addressed // read addressed
case 0xE6: case 0xE6:
return 1; return 1;
// write addressed // write addressed
case 0xE2: case 0xE2:
return 3; return 3;
default: default:
return 0; return 0;
} }

View File

@ -43,7 +43,6 @@ struct pwmout_s {
__IO uint32_t *MOD; __IO uint32_t *MOD;
__IO uint32_t *CNT; __IO uint32_t *CNT;
__IO uint32_t *CnV; __IO uint32_t *CnV;
__IO uint32_t *SYNC;
}; };
struct serial_s { struct serial_s {

View File

@ -21,21 +21,34 @@
static const PinMap PinMap_PWM[] = { static const PinMap PinMap_PWM[] = {
// LEDs // LEDs
{LED_RED , PWM_3 , 3}, // PTC3, FTM0 CH2 {LED_RED , PWM_3 , 4}, // PTC3, FTM0 CH2
{LED_GREEN, PWM_5, 3}, // PTD4, FTM0 CH4 {LED_GREEN, PWM_5, 4}, // PTD4, FTM0 CH4
{LED_BLUE , PWM_9 , 3}, // PTA2 , FTM0 CH7 {LED_BLUE , PWM_8 , 3}, // PTA2, FTM0 CH7
// Arduino digital pinout // Arduino digital pinout
{D3, PWM_5 , 3}, // PTD4, FTM0 CH4 {D3, PWM_5 , 4}, // PTD4, FTM0 CH4
{D5, PWM_7 , 3}, // PTA1, FTM0 CH6 {D5, PWM_7 , 3}, // PTA1, FTM0 CH6
{D6, PWM_3 , 3}, // PTC3 , FTM0 CH2 {D6, PWM_3 , 4}, // PTC3, FTM0 CH2
{D9, PWM_8 , 4}, // PTD2 , FTM0 CH7 {D9, PWM_6 , 4}, // PTD5, FTM0 CH6
{D10, PWM_2 , 4}, // PTC2, FTM0 CH1 {D10, PWM_2 , 4}, // PTC2, FTM0 CH1
{PTA0, PWM_6 , 3}, // PTA0, FTM0 CH5
{PTA3, PWM_1 , 3}, // PTA3, FTM0 CH0
{PTA4, PWM_2 , 3}, // PTA4, FTM0 CH1
{PTA5, PWM_3 , 3}, // PTA5, FTM0 CH2
{PTA12, PWM_9 , 3}, // PTA12, FTM1 CH0
{PTA13, PWM_10, 3}, // PTA13, FTM1 CH1
{PTB0, PWM_9 , 3}, // PTB0, FTM1 CH0
{PTB1, PWM_10, 3}, // PTB1, FTM1 CH1
{PTC1, PWM_1 , 4}, // PTC1, FTM0 CH0
{PTD4, PWM_4 , 4}, // PTD4, FTM0 CH3
{PTD6, PWM_7 , 4}, // PTD6, FTM0 CH6
{PTD7, PWM_8 , 4}, // PTD7, FTM0 CH7
{NC , NC , 0} {NC , NC , 0}
}; };
#define PWM_CLOCK_MHZ (0.75) // (48)MHz / 64 = (0.75)MHz static float pwm_clock = 0;
void pwmout_init(pwmout_t* obj, PinName pin) { void pwmout_init(pwmout_t* obj, PinName pin) {
// determine the channel // determine the channel
@ -43,6 +56,17 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
if (pwm == (PWMName)NC) if (pwm == (PWMName)NC)
error("PwmOut pin mapping failed"); error("PwmOut pin mapping failed");
uint32_t clkdiv = 0;
float clkval = SystemCoreClock / 1000000.0f;
while (clkval > 1) {
clkdiv++;
clkval /= 2.0;
if (clkdiv == 7)
break;
}
pwm_clock = clkval;
unsigned int port = (unsigned int)pin >> PORT_SHIFT; unsigned int port = (unsigned int)pin >> PORT_SHIFT;
unsigned int ftm_n = (pwm >> TPM_SHIFT); unsigned int ftm_n = (pwm >> TPM_SHIFT);
unsigned int ch_n = (pwm & 0xFF); unsigned int ch_n = (pwm & 0xFF);
@ -51,18 +75,13 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
SIM->SCGC6 |= 1 << (SIM_SCGC6_FTM0_SHIFT + ftm_n); SIM->SCGC6 |= 1 << (SIM_SCGC6_FTM0_SHIFT + ftm_n);
FTM_Type *ftm = (FTM_Type *)(FTM0_BASE + 0x1000 * ftm_n); FTM_Type *ftm = (FTM_Type *)(FTM0_BASE + 0x1000 * ftm_n);
ftm->MODE |= FTM_MODE_WPDIS_MASK; //write protection disabled
ftm->CONF |= FTM_CONF_BDMMODE(3); ftm->CONF |= FTM_CONF_BDMMODE(3);
ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(6); // (48)MHz / 64 = (0.75)MHz 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->CONTROLS[ch_n].CnSC = (FTM_CnSC_MSB_MASK | FTM_CnSC_ELSB_MASK); /* No Interrupts; High True pulses on Edge Aligned PWM */
ftm->PWMLOAD |= FTM_PWMLOAD_LDOK_MASK; //loading updated values enabled
//ftm->SYNCONF |= FTM_SYNCONF_SWRSTCNT_MASK;
ftm->MODE |= FTM_MODE_INIT_MASK;
obj->CnV = &ftm->CONTROLS[ch_n].CnV; obj->CnV = &ftm->CONTROLS[ch_n].CnV;
obj->MOD = &ftm->MOD; obj->MOD = &ftm->MOD;
obj->CNT = &ftm->CNT; obj->CNT = &ftm->CNT;
obj->SYNC = &ftm->SYNC;
// default to 20ms: standard for servos, and fine for e.g. brightness control // default to 20ms: standard for servos, and fine for e.g. brightness control
pwmout_period_ms(obj, 20); pwmout_period_ms(obj, 20);
@ -82,8 +101,6 @@ void pwmout_write(pwmout_t* obj, float value) {
} }
*obj->CnV = (uint32_t)((float)(*obj->MOD) * value); *obj->CnV = (uint32_t)((float)(*obj->MOD) * value);
*obj->CNT = 0;
//*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
} }
float pwmout_read(pwmout_t* obj) { float pwmout_read(pwmout_t* obj) {
@ -102,7 +119,7 @@ void pwmout_period_ms(pwmout_t* obj, int ms) {
// Set the PWM period, keeping the duty cycle the same. // Set the PWM period, keeping the duty cycle the same.
void pwmout_period_us(pwmout_t* obj, int us) { void pwmout_period_us(pwmout_t* obj, int us) {
float dc = pwmout_read(obj); float dc = pwmout_read(obj);
*obj->MOD = PWM_CLOCK_MHZ * us; *obj->MOD = (uint32_t)(pwm_clock * (float)us);
pwmout_write(obj, dc); pwmout_write(obj, dc);
} }
@ -115,5 +132,5 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
} }
void pwmout_pulsewidth_us(pwmout_t* obj, int us) { void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
*obj->CnV = PWM_CLOCK_MHZ * us; *obj->CnV = (uint32_t)(pwm_clock * (float)us);
} }

View File

@ -53,7 +53,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
obj->uart = (UART_Type *)uart; obj->uart = (UART_Type *)uart;
// enable clk // enable clk
switch (uart) { switch (uart) {
case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<<SIM_SOPT5_UART0TXSRC_SHIFT); case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK;
SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break; SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break;
case UART_1: SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break; case UART_1: SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break;
case UART_2: SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break; case UART_2: SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break;
@ -98,8 +98,7 @@ void serial_baud(serial_t *obj, int baudrate) {
// Disable UART before changing registers // Disable UART before changing registers
obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK); obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
// [TODO] not hardcode this value uint32_t PCLK = (obj->uart == UART0) ? SystemCoreClock : SystemCoreClock/2;
uint32_t PCLK = (obj->uart == UART0) ? 48000000u : 24000000u;
// First we check to see if the basic divide with no DivAddVal/MulVal // First we check to see if the basic divide with no DivAddVal/MulVal
// ratio gives us an integer result. If it does, we set DivAddVal = 0, // ratio gives us an integer result. If it does, we set DivAddVal = 0,

View File

@ -20,6 +20,7 @@
#include "cmsis.h" #include "cmsis.h"
#include "pinmap.h" #include "pinmap.h"
#include "error.h" #include "error.h"
#include "clk_freqs.h"
static const PinMap PinMap_SPI_SCLK[] = { static const PinMap PinMap_SPI_SCLK[] = {
{PTC5, SPI_0, 2}, {PTC5, SPI_0, 2},
@ -59,11 +60,12 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
error("SPI pinout mapping failed"); error("SPI pinout mapping failed");
} }
SIM->SCGC5 |= (1 << 11) | (1 << 12); // PortC & D SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK;
SIM->SCGC6 |= 1 << 12; // spi clocks SIM->SCGC6 |= SIM_SCGC6_SPI0_MASK;
// halted state // halted state
obj->spi->MCR = SPI_MCR_HALT_MASK; obj->spi->MCR &= ~SPI_MCR_MDIS_MASK;
obj->spi->MCR |= SPI_MCR_HALT_MASK | SPI_MCR_DIS_RXF_MASK | SPI_MCR_DIS_TXF_MASK;
// set default format and frequency // set default format and frequency
if (ssel == NC) { if (ssel == NC) {
@ -111,50 +113,60 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) {
obj->spi->CTAR[0] |= (polarity << SPI_CTAR_CPOL_SHIFT) | (phase << SPI_CTAR_CPHA_SHIFT); obj->spi->CTAR[0] |= (polarity << SPI_CTAR_CPOL_SHIFT) | (phase << SPI_CTAR_CPHA_SHIFT);
} }
static const uint8_t baudrate_prescaler[] = {2,3,5,7};
static const uint32_t baudrate_scaler[] = {2, 4, 6, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768};
static const uint8_t delay_prescaler[] = {1, 3, 5, 7};
void spi_frequency(spi_t *obj, int hz) { void spi_frequency(spi_t *obj, int hz) {
uint32_t error = 0; uint32_t error = 0;
uint32_t p_error = 0xffffffff; uint32_t p_error = 0xffffffff;
uint32_t ref = 0; uint32_t ref = 0;
uint32_t spr = 0; uint32_t br = 0;
uint32_t ref_spr = 0; uint32_t ref_spr = 0;
uint32_t ref_prescaler = 0; uint32_t ref_prescaler = 0;
// bus clk // bus clk
uint32_t PCLK = 48000000u; uint32_t PCLK = bus_frequency();
uint32_t prescaler = 1;
uint32_t divisor = 2; uint32_t divisor = 2;
uint32_t prescaler;
for (prescaler = 1; prescaler <= 8; prescaler++) { /* TODO */
for (uint32_t i = 0; i < 4; i++) {
prescaler = baudrate_prescaler[i];
divisor = 2; divisor = 2;
for (spr = 0; spr <= 8; spr++, divisor *= 2) { for (br = 0; br <= 15; br++, divisor *= 2) {
ref = PCLK / (prescaler*divisor); for (uint32_t dr = 0; dr < 2; dr++) {
ref = (PCLK / prescaler) * ((1U + dr) / divisor);
if (ref > (uint32_t)hz) if (ref > (uint32_t)hz)
continue; continue;
error = hz - ref; error = hz - ref;
if (error < p_error) { if (error < p_error) {
ref_spr = spr; ref_spr = br;
ref_prescaler = prescaler - 1; ref_prescaler = i;
p_error = error; p_error = error;
} }
} }
} }
}
// set SPPR and SPR // set PBR and BR
obj->spi->CTAR[0] = ((ref_prescaler & 0x7) << 4) | (ref_spr & 0xf); obj->spi->CTAR[0] = ((ref_prescaler & 0x3) << SPI_CTAR_PBR_SHIFT) | (ref_spr & 0xf);
} }
static inline int spi_writeable(spi_t *obj) { static inline int spi_writeable(spi_t *obj) {
return (obj->spi->SR & SPI_SR_TCF_MASK) ? 1 : 0; return (obj->spi->SR & SPI_SR_TFFF_MASK) ? 1 : 0;
} }
static inline int spi_readable(spi_t *obj) { static inline int spi_readable(spi_t *obj) {
return (obj->spi->SR & SPI_SR_TFFF_MASK) ? 1 : 0; return (obj->spi->SR & SPI_SR_RFDF_MASK) ? 0 : 1;
} }
int spi_master_write(spi_t *obj, int value) { int spi_master_write(spi_t *obj, int value) {
// wait tx buffer empty // wait tx buffer empty
while(!spi_writeable(obj)); while(!spi_writeable(obj));
obj->spi->PUSHR = SPI_PUSHR_TXDATA(value & 0xff); obj->spi->PUSHR = SPI_PUSHR_TXDATA(value & 0xff) /*| SPI_PUSHR_EOQ_MASK*/;
while (!obj->spi->SR & SPI_SR_TCF_MASK); // wait for transfer to be complete
// wait rx buffer full // wait rx buffer full
while (!spi_readable(obj)); while (!spi_readable(obj));

View File

@ -16,11 +16,14 @@
#include <stddef.h> #include <stddef.h>
#include "us_ticker_api.h" #include "us_ticker_api.h"
#include "PeripheralNames.h" #include "PeripheralNames.h"
#include "clk_freqs.h"
static void pit_init(void); static void pit_init(void);
static void lptmr_init(void); static void lptmr_init(void);
static int us_ticker_inited = 0; static int us_ticker_inited = 0;
static uint32_t pit_ldval = 0;
void us_ticker_init(void) { void us_ticker_init(void) {
if (us_ticker_inited) if (us_ticker_inited)
@ -35,7 +38,7 @@ static uint32_t pit_us_ticker_counter = 0;
void pit0_isr(void) { void pit0_isr(void) {
pit_us_ticker_counter++; pit_us_ticker_counter++;
PIT->CHANNEL[0].LDVAL = 48; // 1us PIT->CHANNEL[0].LDVAL = pit_ldval; // 1us
PIT->CHANNEL[0].TFLG = 1; PIT->CHANNEL[0].TFLG = 1;
} }
@ -46,7 +49,9 @@ static void pit_init(void) {
SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT
PIT->MCR = 0; // Enable PIT PIT->MCR = 0; // Enable PIT
PIT->CHANNEL[0].LDVAL = 48; // 1us pit_ldval = bus_frequency() / 1000000;
PIT->CHANNEL[0].LDVAL = pit_ldval; // 1us
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK; PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK;
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1 PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1
@ -82,10 +87,36 @@ static void lptmr_init(void) {
NVIC_EnableIRQ(LPTimer_IRQn); NVIC_EnableIRQ(LPTimer_IRQn);
/* Clock at (1)MHz -> (1)tick/us */ /* Clock at (1)MHz -> (1)tick/us */
/* Check if the external oscillator can be divided to 1MHz */
uint32_t extosc = extosc_frequency();
if (extosc != 0) { //If external oscillator found
OSC0->CR |= OSC_CR_ERCLKEN_MASK; OSC0->CR |= OSC_CR_ERCLKEN_MASK;
LPTMR0->PSR = 0; if (extosc % 1000000u == 0) { //If it is a multiple if 1MHz
LPTMR0->PSR |= LPTMR_PSR_PCS(3); // OSCERCLK -> 8MHz extosc /= 1000000;
LPTMR0->PSR |= LPTMR_PSR_PRESCALE(2); // divide by 8 if (extosc == 1) { //1MHz, set timerprescaler in bypass mode
LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PBYP_MASK;
return;
} else { //See if we can divide it to 1MHz
uint32_t divider = 0;
extosc >>= 1;
while (1) {
if (extosc == 1) {
LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PRESCALE(divider);
return;
}
if (extosc % 2 != 0) //If we can't divide by two anymore
break;
divider++;
extosc >>= 1;
}
}
}
}
//No suitable external oscillator clock -> Use fast internal oscillator (4MHz)
MCG->C1 |= MCG_C1_IRCLKEN_MASK;
MCG->C2 |= MCG_C2_IRCS_MASK;
LPTMR0->PSR = LPTMR_PSR_PCS(0) | LPTMR_PSR_PRESCALE(1);
} }
void us_ticker_disable_interrupt(void) { void us_ticker_disable_interrupt(void) {