KL05 clock removal, I2C API

- spi - bus clock clock correction
  - i2c driver
pull/11/head
0xc0170 2013-06-25 21:53:06 +02:00
parent 3884f1ba3c
commit bf4746897f
5 changed files with 391 additions and 92 deletions

View File

@ -8,12 +8,6 @@
0 ... Multipurpose Clock Generator (MCG) in FLL Engaged Internal (FEI) mode 0 ... Multipurpose Clock Generator (MCG) in FLL Engaged Internal (FEI) mode
Reference clock source for MCG module is the slow internal clock source 32.768kHz Reference clock source for MCG module is the slow internal clock source 32.768kHz
Core clock = 47.97MHz, BusClock = 23.48MHz Core clock = 47.97MHz, BusClock = 23.48MHz
1 ... Multipurpose Clock Generator (MCG) in FLL Engaged External (FEE) mode
Reference clock source for MCG module is an external crystal 8MHz
Core clock = 40MHz, BusClock = 20MHz
2 ... Multipurpose Clock Generator (MCG) in Bypassed Low Power External (BLPE) mode
Core clock/Bus clock derived directly from an external crystal 8MHz with no multiplication
Core clock = 8MHz, BusClock = 8MHz
*/ */
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -24,17 +18,7 @@
#define CPU_INT_SLOW_CLK_HZ 32768u /* Value of the slow internal oscillator clock frequency in Hz */ #define CPU_INT_SLOW_CLK_HZ 32768u /* Value of the slow internal oscillator clock frequency in Hz */
#define CPU_INT_FAST_CLK_HZ 4000000u /* Value of the fast internal oscillator clock frequency in Hz */ #define CPU_INT_FAST_CLK_HZ 4000000u /* Value of the fast internal oscillator clock frequency in Hz */
#define DEFAULT_SYSTEM_CLOCK 47972352u /* Default System clock value */ #define DEFAULT_SYSTEM_CLOCK 47972352u /* Default System clock value */
#elif (CLOCK_SETUP == 1) #endif /* (CLOCK_SETUP == 0) */
#define CPU_XTAL_CLK_HZ 8000000u /* Value of the external crystal or oscillator clock frequency in Hz */
#define CPU_INT_SLOW_CLK_HZ 32768u /* Value of the slow internal oscillator clock frequency in Hz */
#define CPU_INT_FAST_CLK_HZ 4000000u /* Value of the fast internal oscillator clock frequency in Hz */
#define DEFAULT_SYSTEM_CLOCK 40000000u /* Default System clock value */
#elif (CLOCK_SETUP == 2)
#define CPU_XTAL_CLK_HZ 8000000u /* Value of the external crystal or oscillator clock frequency in Hz */
#define CPU_INT_SLOW_CLK_HZ 32768u /* Value of the slow internal oscillator clock frequency in Hz */
#define CPU_INT_FAST_CLK_HZ 4000000u /* Value of the fast internal oscillator clock frequency in Hz */
#define DEFAULT_SYSTEM_CLOCK 8000000u /* Default System clock value */
#endif /* (CLOCK_SETUP == 2) */
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
@ -47,13 +31,13 @@ uint32_t SystemCoreClock = DEFAULT_SYSTEM_CLOCK;
-- SystemInit() -- SystemInit()
---------------------------------------------------------------------------- */ ---------------------------------------------------------------------------- */
void SystemInit (void) { void SystemInit(void) {
#if (DISABLE_WDOG) #if (DISABLE_WDOG)
/* Disable the WDOG module */ /* Disable the WDOG module */
/* SIM_COPC: COPT=0,COPCLKS=0,COPW=0 */ /* SIM_COPC: COPT=0,COPCLKS=0,COPW=0 */
SIM->COPC = (uint32_t)0x00u; SIM->COPC = (uint32_t)0x00u;
#endif /* (DISABLE_WDOG) */ #endif /* (DISABLE_WDOG) */
#if (CLOCK_SETUP == 0)
SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTA_MASK); /* Enable clock gate for ports to enable pin routing */ SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTA_MASK); /* Enable clock gate for ports to enable pin routing */
/* SIM_CLKDIV1: OUTDIV1=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,OUTDIV4=1,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0 */ /* SIM_CLKDIV1: OUTDIV1=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,OUTDIV4=1,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0 */
SIM->CLKDIV1 = (SIM_CLKDIV1_OUTDIV1(0x00) | SIM_CLKDIV1_OUTDIV4(0x01)); /* Update system prescalers */ SIM->CLKDIV1 = (SIM_CLKDIV1_OUTDIV1(0x00) | SIM_CLKDIV1_OUTDIV4(0x01)); /* Update system prescalers */
@ -90,75 +74,6 @@ void SystemInit (void) {
} }
while((MCG->S & 0x0CU) != 0x00U) { /* Wait until output of the FLL is selected */ while((MCG->S & 0x0CU) != 0x00U) { /* Wait until output of the FLL is selected */
} }
#elif (CLOCK_SETUP == 1)
SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTA_MASK); /* Enable clock gate for ports to enable pin routing */
/* SIM_CLKDIV1: OUTDIV1=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,OUTDIV4=1,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0 */
SIM->CLKDIV1 = (SIM_CLKDIV1_OUTDIV1(0x00) | SIM_CLKDIV1_OUTDIV4(0x01)); /* Update system prescalers */
/* SIM_SOPT1: OSC32KSEL=3 */
SIM->SOPT1 |= SIM_SOPT1_OSC32KSEL(0x03); /* LPO 1kHz oscillator drives 32 kHz clock for various peripherals */
/* SIM_SOPT2: TPMSRC=1 */
SIM->SOPT2 = (uint32_t)((SIM->SOPT2 & (uint32_t)~(uint32_t)(
SIM_SOPT2_TPMSRC(0x02)
)) | (uint32_t)(
SIM_SOPT2_TPMSRC(0x01)
)); /* Set the TPM clock */
/* PORTA_PCR3: ISF=0,MUX=0 */
PORTA->PCR[3] &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
/* PORTA_PCR4: ISF=0,MUX=0 */
PORTA->PCR[4] &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
/* Switch to FEE Mode */
/* MCG_C2: LOCRE0=0,??=0,RANGE0=2,HGO0=0,EREFS0=1,LP=0,IRCS=0 */
MCG->C2 = (MCG_C2_RANGE0(0x02) | MCG_C2_EREFS0_MASK);
/* OSC0_CR: ERCLKEN=1,??=0,EREFSTEN=0,??=0,SC2P=0,SC4P=0,SC8P=0,SC16P=0 */
OSC0->CR = OSC_CR_ERCLKEN_MASK;
/* MCG_C1: CLKS=0,FRDIV=3,IREFS=0,IRCLKEN=1,IREFSTEN=0 */
MCG->C1 = (MCG_C1_CLKS(0x00) | MCG_C1_FRDIV(0x03) | MCG_C1_IRCLKEN_MASK);
/* MCG_C4: DMX32=0,DRST_DRS=1 */
MCG->C4 = (uint8_t)((MCG->C4 & (uint8_t)~(uint8_t)(
MCG_C4_DMX32_MASK |
MCG_C4_DRST_DRS(0x02)
)) | (uint8_t)(
MCG_C4_DRST_DRS(0x01)
));
while((MCG->S & MCG_S_IREFST_MASK) != 0x00U) { /* Check that the source of the FLL reference clock is the external reference clock. */
}
while((MCG->S & 0x0CU) != 0x00U) { /* Wait until output of the FLL is selected */
}
#elif (CLOCK_SETUP == 2)
SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTA_MASK); /* Enable clock gate for ports to enable pin routing */
/* SIM_CLKDIV1: OUTDIV1=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,OUTDIV4=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0 */
SIM->CLKDIV1 = (SIM_CLKDIV1_OUTDIV1(0x00) | SIM_CLKDIV1_OUTDIV4(0x00)); /* Update system prescalers */
/* SIM_SOPT1: OSC32KSEL=3 */
SIM->SOPT1 |= SIM_SOPT1_OSC32KSEL(0x03); /* LPO 1kHz oscillator drives 32 kHz clock for various peripherals */
/* SIM_SOPT2: TPMSRC=2 */
SIM->SOPT2 = (uint32_t)((SIM->SOPT2 & (uint32_t)~(uint32_t)(
SIM_SOPT2_TPMSRC(0x01)
)) | (uint32_t)(
SIM_SOPT2_TPMSRC(0x02)
)); /* Set the TPM clock */
/* PORTA_PCR3: ISF=0,MUX=0 */
PORTA->PCR[3] &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
/* PORTA_PCR4: ISF=0,MUX=0 */
PORTA->PCR[4] &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
/* Switch to FBE Mode */
/* MCG_C2: LOCRE0=0,??=0,RANGE0=2,HGO0=0,EREFS0=1,LP=0,IRCS=0 */
MCG->C2 = (MCG_C2_RANGE0(0x02) | MCG_C2_EREFS0_MASK);
/* OSC0_CR: ERCLKEN=1,??=0,EREFSTEN=0,??=0,SC2P=0,SC4P=0,SC8P=0,SC16P=0 */
OSC0->CR = OSC_CR_ERCLKEN_MASK;
/* MCG_C1: CLKS=2,FRDIV=3,IREFS=0,IRCLKEN=1,IREFSTEN=0 */
MCG->C1 = (MCG_C1_CLKS(0x02) | MCG_C1_FRDIV(0x03) | MCG_C1_IRCLKEN_MASK);
/* MCG_C4: DMX32=0,DRST_DRS=0 */
MCG->C4 &= (uint8_t)~(uint8_t)((MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0x03)));
while((MCG->S & MCG_S_IREFST_MASK) != 0x00U) { /* Check that the source of the FLL reference clock is the external reference clock. */
}
while((MCG->S & 0x0CU) != 0x08U) { /* Wait until external reference clock is selected as MCG output */
}
/* Switch to BLPE Mode */
/* MCG_C2: LOCRE0=0,??=0,RANGE0=2,HGO0=0,EREFS0=1,LP=1,IRCS=0 */
MCG->C2 = (MCG_C2_RANGE0(0x02) | MCG_C2_EREFS0_MASK | MCG_C2_LP_MASK);
while((MCG->S & 0x0CU) != 0x08U) { /* Wait until external reference clock is selected as MCG output */
}
#endif /* (CLOCK_SETUP == 2) */
} }
// Make sure we are pulling in the retargeting module at link time // Make sure we are pulling in the retargeting module at link time
@ -168,6 +83,6 @@ extern int stdio_retargeting_module;
-- SystemCoreClockUpdate() -- SystemCoreClockUpdate()
---------------------------------------------------------------------------- */ ---------------------------------------------------------------------------- */
void SystemCoreClockUpdate (void) { void SystemCoreClockUpdate(void) {
/* TODO */ /* TODO */
} }

View File

@ -30,6 +30,10 @@ typedef enum {
#define STDIO_UART_RX USBRX #define STDIO_UART_RX USBRX
#define STDIO_UART UART_0 #define STDIO_UART UART_0
typedef enum {
I2C_0 = (int)I2C0_BASE
} I2CName;
typedef enum { typedef enum {
ADC0_SE2 = 2, ADC0_SE2 = 2,
ADC0_SE3 = 3, ADC0_SE3 = 3,

View File

@ -27,8 +27,8 @@
#define DEVICE_SERIAL 1 #define DEVICE_SERIAL 1
#define DEVICE_I2C 0 #define DEVICE_I2C 1
#define DEVICE_I2CSLAVE 0 #define DEVICE_I2CSLAVE 1
#define DEVICE_SPI 1 #define DEVICE_SPI 1
#define DEVICE_SPISLAVE 1 #define DEVICE_SPISLAVE 1

View File

@ -18,3 +18,383 @@
#include "cmsis.h" #include "cmsis.h"
#include "pinmap.h" #include "pinmap.h"
#include "error.h" #include "error.h"
static const PinMap PinMap_I2C_SDA[] = {
{PTB4, I2C_0, 2},
{NC , NC , 0}
};
static const PinMap PinMap_I2C_SCL[] = {
{PTB3, I2C_0, 2},
{NC , NC , 0}
};
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
};
static uint8_t first_read;
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);
if ((int)obj->i2c == NC) {
error("I2C pin mapping failed");
}
// enable power
switch ((int)obj->i2c) {
case I2C_0:
SIM->SCGC5 |= SIM_SCGC5_PORTB_MASK;
SIM->SCGC4 |= SIM_SCGC4_I2C0_MASK;
break;
}
// 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);
first_read = 1;
}
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;
}
first_read = 1;
return 0;
}
void i2c_stop(i2c_t *obj) {
volatile uint32_t n = 0;
obj->i2c->C1 &= ~I2C_C1_MST_MASK;
obj->i2c->C1 &= ~I2C_C1_TX_MASK;
// It seems that there are timing problems
// when there is no waiting time after a STOP.
// This wait is also included on the samples
// code provided with the freedom board
for (n = 0; n < 100; n++) __NOP();
first_read = 1;
}
static int timeout_status_poll(i2c_t *obj, uint32_t mask) {
uint32_t i, timeout = 1000;
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 = 23986176u;
// 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]);
error = (ref > hz) ? ref - hz : 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) {
uint8_t count;
char dummy_read, *ptr;
if (i2c_start(obj)) {
i2c_stop(obj);
return 1;
}
if (i2c_do_write(obj, (address | 0x01))) {
i2c_stop(obj);
return 1;
}
// 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 1;
}
}
// If not repeated start, send stop.
if (stop) {
i2c_stop(obj);
}
// last read
data[count-1] = obj->i2c->D;
return 0;
}
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 1;
}
if (i2c_do_write(obj, (address & 0xFE))) {
i2c_stop(obj);
return 1;
}
for (i = 0; i < length; i++) {
if(i2c_do_write(obj, data[i])) {
i2c_stop(obj);
return 1;
}
}
if (stop) {
i2c_stop(obj);
}
return 0;
}
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;
if(first_read) {
// first dummy read
i2c_do_read(obj, &data, 0);
first_read = 0;
}
if (last) {
// set tx mode
obj->i2c->C1 |= I2C_C1_TX_MASK;
return obj->i2c->D;
}
i2c_do_read(obj, &data, last);
return data;
}
int i2c_byte_write(i2c_t *obj, int data) {
first_read = 1;
// set tx mode
obj->i2c->C1 |= I2C_C1_TX_MASK;
return !i2c_do_write(obj, (data & 0xFF));
}
#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, count;
uint8_t *ptr;
// 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 0;
}
}
// 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) {
uint32_t 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 0;
}
}
// 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 0;
}
return count;
}
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
obj->i2c->A1 = address & 0xfe;
}
#endif

View File

@ -115,7 +115,7 @@ void spi_frequency(spi_t *obj, int hz) {
uint8_t ref_prescaler = 0; uint8_t ref_prescaler = 0;
// bus clk // bus clk
uint32_t PCLK = 48000000u; uint32_t PCLK = 23986176u;
uint8_t prescaler = 1; uint8_t prescaler = 1;
uint8_t divisor = 2; uint8_t divisor = 2;