AnalogIn, Interrupts, and I2C are added.

pull/159/head
tkuyucu 2013-12-18 15:04:16 +01:00
parent 3faaff74ee
commit 3c2258956b
6 changed files with 516 additions and 43 deletions

View File

@ -44,32 +44,15 @@ typedef enum {
PWM_4
} PWMName;
/*
typedef enum {
I2C_0 = (int)I2C0_BASE,
I2C_1 = (int)I2C1_BASE,
I2C_0 = (int)NRF_TWI0_BASE,
I2C_1 = (int)NRF_TWI1_BASE
} I2CName;
#define CHANNELS_A_SHIFT 5
typedef enum {
ADC0_SE0 = 0,
ADC0_SE3 = 3,
ADC0_SE4a = (1 << CHANNELS_A_SHIFT) | (4),
ADC0_SE4b = 4,
ADC0_SE5b = 5,
ADC0_SE6b = 6,
ADC0_SE7a = (1 << CHANNELS_A_SHIFT) | (7),
ADC0_SE7b = 7,
ADC0_SE8 = 8,
ADC0_SE9 = 9,
ADC0_SE11 = 11,
ADC0_SE12 = 12,
ADC0_SE13 = 13,
ADC0_SE14 = 14,
ADC0_SE15 = 15,
ADC0_SE23 = 23
ADC0_0 = (int)NRF_ADC_BASE
} ADCName;
/*
typedef enum {
DAC_0 = 0

View File

@ -0,0 +1,79 @@
/* 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.
*/
#include "analogin_api.h"
#include "cmsis.h"
#include "pinmap.h"
#include "error.h"
#define ANALOGIN_MEDIAN_FILTER 1
#define ADC_10BIT_RANGE 0x3FF
static inline int div_round_up(int x, int y) {
return (x + (y - 1)) / y;
}
static const PinMap PinMap_ADC[] = {
// {p26, ADC0_0, 1},
// {p27, ADC0_0, 2},
{p1, ADC0_0, 4},
{p2, ADC0_0, 8},
{p3, ADC0_0, 16},
{p4, ADC0_0, 32},
{p5, ADC0_0, 64},
{p6, ADC0_0, 128},
{NC , NC , 0}
};
#define ADC_RANGE ADC_10BIT_RANGE
void analogin_init(analogin_t *obj, PinName pin) {
obj->adc = (NRF_ADC_Type *) ((ADCName)pinmap_peripheral(pin, PinMap_ADC));
if (obj->adc == (ADCName)NC) {
error("ADC pin mapping failed");
}
int analogInputPin=0;
PinMap *map = PinMap_ADC;
while (map->pin != NC) {
if (map->pin == pin){
analogInputPin = map->function;
break;
}
map++;
}
NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
NRF_ADC->CONFIG = (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) |
(ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling<< ADC_CONFIG_INPSEL_Pos) |
(ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling << ADC_CONFIG_REFSEL_Pos) |
(analogInputPin << ADC_CONFIG_PSEL_Pos) |
(ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
}
uint16_t analogin_read_u16(analogin_t *obj) {
NRF_ADC->TASKS_START = 1;
while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy)
{
}
return (uint16_t)NRF_ADC->RESULT; // 10 bit
}
float analogin_read(analogin_t *obj) {
uint16_t value = analogin_read_u16(obj);
return (float)value * (1.0f / (float)ADC_RANGE);
}

View File

@ -20,14 +20,14 @@
#define DEVICE_PORTOUT 1
#define DEVICE_PORTINOUT 1
#define DEVICE_INTERRUPTIN 0
#define DEVICE_INTERRUPTIN 1
#define DEVICE_ANALOGIN 0
#define DEVICE_ANALOGIN 1
#define DEVICE_ANALOGOUT 0
#define DEVICE_SERIAL 1
#define DEVICE_I2C 0
#define DEVICE_I2C 1
#define DEVICE_I2CSLAVE 0
#define DEVICE_SPI 1

View File

@ -0,0 +1,118 @@
/* 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.
*/
#include <stddef.h>
#include "cmsis.h"
#include "gpio_irq_api.h"
#include "error.h"
#define CHANNEL_NUM 31
static uint32_t channel_ids[CHANNEL_NUM] = {0}; //each pin will be given an id, if id is 0 the pin can be ignored.
static uint8_t channel_enabled[CHANNEL_NUM] = {0};
static uint32_t portRISE= 0;
static uint32_t portFALL= 0;
static gpio_irq_handler irq_handler;
volatile uint32_t oldPortValue;
static int test=0;
void GPIOTE_IRQHandler(void)
{
volatile uint32_t newVal = NRF_GPIO->IN;
if ((NRF_GPIOTE->EVENTS_PORT != 0) && ((NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_PORT_Msk) != 0)){
//NRF_GPIOTE->INTENSET &= ~(GPIOTE_INTENSET_PORT_Enabled<<GPIOTE_INTENSET_PORT_Pos);
NRF_GPIOTE->EVENTS_PORT = 0;
for(uint8_t i=0;i<31;i++)
{
if(channel_ids[i]>0){
if((portRISE>>i)&1){
if(((newVal>>i)&1) && ((oldPortValue>>i)&1)==0 ){//
if(channel_enabled[i]){
irq_handler(channel_ids[i], IRQ_RISE);
}
NRF_GPIO->PIN_CNF[i] &= ~(GPIO_PIN_CNF_SENSE_Msk);
NRF_GPIO->PIN_CNF[i] |= (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos) ;
}
else if(((newVal>>i)&1)==0 && ((NRF_GPIO->PIN_CNF[i] >>GPIO_PIN_CNF_SENSE_Pos)&GPIO_PIN_CNF_SENSE_Low) == GPIO_PIN_CNF_SENSE_Low){
NRF_GPIO->PIN_CNF[i] &= ~(GPIO_PIN_CNF_SENSE_Msk);
NRF_GPIO->PIN_CNF[i] |= (GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos) ;
}
}
else if((portFALL>>i)&1){
if(((oldPortValue>>i)&1) && ((newVal>>i)&1)==0 ){
if(channel_enabled[i]){
irq_handler(channel_ids[i], IRQ_FALL);
}
NRF_GPIO->PIN_CNF[i] &= ~(GPIO_PIN_CNF_SENSE_Msk);
NRF_GPIO->PIN_CNF[i] |= (GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos) ;
}
else if(((newVal>>i)&1) && ((NRF_GPIO->PIN_CNF[i] >>GPIO_PIN_CNF_SENSE_Pos)&GPIO_PIN_CNF_SENSE_Low) != GPIO_PIN_CNF_SENSE_Low){
NRF_GPIO->PIN_CNF[i] &= ~(GPIO_PIN_CNF_SENSE_Msk);
NRF_GPIO->PIN_CNF[i] |= (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos) ;
}
}
}
}
oldPortValue = newVal;
//NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Enabled<<GPIOTE_INTENSET_PORT_Pos;
}
}
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->ch = pin;
oldPortValue = NRF_GPIO->IN;
//NVIC_DisableIRQ(GPIOTE_IRQn);
NRF_GPIOTE->EVENTS_PORT = 0;
NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Set<<GPIOTE_INTENSET_PORT_Pos;
NVIC_EnableIRQ(GPIOTE_IRQn);
channel_ids[pin]=id;
channel_enabled[pin]=1;
}
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) {
portRISE &=~(1<<obj->ch);
portFALL &=~(1<<obj->ch);
if(enable){
if(event == IRQ_RISE){
portRISE |=(1<<obj->ch);
NRF_GPIO->PIN_CNF[obj->ch] &= ~(GPIO_PIN_CNF_SENSE_Msk);// | GPIO_PIN_CNF_PULL_Msk);
NRF_GPIO->PIN_CNF[obj->ch] |= (GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos) ;//| (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos);
}
else if(event == IRQ_FALL){
portFALL |=(1<<obj->ch);
NRF_GPIO->PIN_CNF[obj->ch] &= ~(GPIO_PIN_CNF_SENSE_Msk );//| GPIO_PIN_CNF_PULL_Msk);
NRF_GPIO->PIN_CNF[obj->ch] |= (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos);// | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos);
}
}
oldPortValue = NRF_GPIO->IN;
}
void gpio_irq_enable(gpio_irq_t *obj) {
channel_enabled[obj->ch]=1;
}
void gpio_irq_disable(gpio_irq_t *obj) {
channel_enabled[obj->ch]=0;
}

View File

@ -0,0 +1,305 @@
/* 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.
*/
#include "i2c_api.h"
#include "cmsis.h"
#include "pinmap.h"
#include "error.h"
/*
static const PinMap PinMap_I2C_SDA[] = {
{p9, I2C_0, 1},
{NC , NC , 0}
};
static const PinMap PinMap_I2C_SCL[] = {
{p8, I2C_0, 1},
{NC , NC, 0}
};*/
uint8_t I2C_USED[] = {0,0};
uint8_t addrSet=0;
void i2c_interface_enable(i2c_t *obj)
{
obj->i2c->ENABLE = (TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos);
}
void twi_master_init(i2c_t *obj, PinName sda, PinName scl, int frequency) {
NRF_GPIO->PIN_CNF[scl] = ((GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos));
NRF_GPIO->PIN_CNF[sda] = ((GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos));
obj->i2c->PSELSCL = scl;
obj->i2c->PSELSDA = sda;
// set default frequency at 100k
i2c_frequency(obj, frequency);
i2c_interface_enable(obj);
}
void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
// determine the SPI to use
// I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
// I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
if(I2C_USED[0]){
if(I2C_USED[1]){
error("All TWI peripherals in use.");
}
else
obj->i2c = (NRF_TWI_Type *)I2C_1;
}
else{
obj->i2c = (NRF_TWI_Type *)I2C_0;
}
if ((int)obj->i2c == NC) {
error("I2C pin mapping failed");
}
obj->scl=scl;
obj->sda=sda;
obj->i2c->EVENTS_ERROR = 0;
obj->i2c->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
obj->i2c->POWER = 0;
for(int i=0;i<100;i++);
obj->i2c->POWER = 1;
twi_master_init(obj,sda,scl,100000);
}
void i2c_reset(i2c_t *obj) {
obj->i2c->EVENTS_ERROR = 0;
obj->i2c->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
obj->i2c->POWER = 0;
for(int i=0;i<100;i++);
obj->i2c->POWER = 1;
twi_master_init(obj,obj->sda,obj->scl,obj->freq);
}
inline int i2c_start(i2c_t *obj) {
int status = 0;
//obj->i2c->ADDRESS = 0;
i2c_reset(obj);
addrSet=0;
return status;
}
inline int i2c_stop(i2c_t *obj) {
// int timeout = 0;
obj->i2c->EVENTS_STOPPED = 0;
// write the stop bit
obj->i2c->TASKS_STOP=1;
while(!obj->i2c->EVENTS_STOPPED)
{
}
//obj->i2c->ADDRESS = 0;
addrSet=0;
i2c_reset(obj);
//obj->i2c->EVENTS_STOPPED = 0;
return 0;
}
int i2c_do_write(i2c_t *obj, int value) {
int timeOut=1000;
obj->i2c->TXD = value;
while(!obj->i2c->EVENTS_TXDSENT){
timeOut--;
if(timeOut<0)
return 1;
}
obj->i2c->EVENTS_TXDSENT = 0;
return 0;
}
int i2c_do_read(i2c_t *obj, char * data, int last) {
int timeOut=1000;
while(!obj->i2c->EVENTS_RXDREADY){
timeOut--;
if(timeOut<0)
return 1;
}
obj->i2c->EVENTS_RXDREADY = 0;
if (last)
obj->i2c->TASKS_STOP=1;
*data = obj->i2c->RXD;
for(int i=0;i<320;i++);
obj->i2c->TASKS_RESUME = 1;
return 0;
}
void i2c_frequency(i2c_t *obj, int hz) {
obj->freq=hz;
switch(hz){
case 100000:obj->i2c->FREQUENCY = (TWI_FREQUENCY_FREQUENCY_K100 << TWI_FREQUENCY_FREQUENCY_Pos);break;
case 250000:obj->i2c->FREQUENCY = (TWI_FREQUENCY_FREQUENCY_K250 << TWI_FREQUENCY_FREQUENCY_Pos);break;
case 400000:obj->i2c->FREQUENCY = (TWI_FREQUENCY_FREQUENCY_K400 << TWI_FREQUENCY_FREQUENCY_Pos);break;
default:error("I2C frequency requested is not supported"); break;
}
}
int checkError(i2c_t *obj)
{
if (obj->i2c->EVENTS_ERROR == 1)
{
if ((obj->i2c->ERRORSRC & TWI_ERRORSRC_ANACK_Msk) == (TWI_ERRORSRC_ANACK_Present << TWI_ERRORSRC_ANACK_Pos))
{
obj->i2c->EVENTS_ERROR = 0;
obj->i2c->TASKS_STOP = 1;
obj->i2c->ERRORSRC |= (TWI_ERRORSRC_ANACK_Present << TWI_ERRORSRC_ANACK_Pos);
return I2C_ERROR_BUS_BUSY;
}
}
if (obj->i2c->EVENTS_ERROR == 1)
{
obj->i2c->EVENTS_ERROR = 0;
obj->i2c->TASKS_STOP = 1;
if ((obj->i2c->ERRORSRC & TWI_ERRORSRC_DNACK_Msk) == (TWI_ERRORSRC_DNACK_Present << TWI_ERRORSRC_DNACK_Pos))
{
obj->i2c->ERRORSRC |= (TWI_ERRORSRC_DNACK_Present << TWI_ERRORSRC_DNACK_Pos);
return I2C_ERROR_NO_SLAVE;
}
}
return 0;
}
// The I2C does a read or a write as a whole operation
// There are two types of error conditions it can encounter
// 1) it can not obtain the bus
// 2) it gets error responses at part of the transmission
//
// We tackle them as follows:
// 1) we retry until we get the bus. we could have a "timeout" if we can not get it
// which basically turns it in to a 2)
// 2) on error, we use the standard error mechanisms to report/debug
//
// Therefore an I2C transaction should always complete. If it doesn't it is usually
// because something is setup wrong (e.g. wiring), and we don't need to programatically
// check for that
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
int status,count;
obj->i2c->ADDRESS = (address>>1);
obj->i2c->SHORTS = 0;
obj->i2c->EVENTS_RXDREADY = 0;
obj->i2c->TASKS_STARTRX = 1;
// Read in all except last byte
for (count = 0; count < (length - 1); count++) {
status = i2c_do_read(obj,&data[count], 0);
if (status) {
i2c_reset(obj);
int errorResult = checkError(obj);
if(errorResult<0)
return errorResult;
return count;
}
}
/*status = i2c_do_read(obj,&data[length-2], 1);
if (status) {
i2c_reset(obj);
return length - 2;
}*/
// read in last byte
status = i2c_do_read(obj,&data[length-1], 1);
if (status) {
i2c_reset(obj);
return length - 1;
}
// If not repeated start, send stop.
if (stop) {
while(!obj->i2c->EVENTS_STOPPED)
{
}
obj->i2c->EVENTS_STOPPED = 0;
}
return length;
}
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
int status;
obj->i2c->ADDRESS = (address>>1);
obj->i2c->SHORTS = 0;
//obj->i2c->EVENTS_STOPPED = 0;
obj->i2c->TASKS_STARTTX = 1;
for (int i=0; i<length; i++) {
status = i2c_do_write(obj, data[i]);
if(status) {
i2c_reset(obj);
int errorResult = checkError(obj);
if(errorResult<0)
return errorResult;
return i;
}
}
// clearing the serial interrupt here might cause an unintended rewrite of the last byte
// see also issue report https://mbed.org/users/mbed_official/code/mbed/issues/1
// i2c_clear_SI(obj);
// If not repeated start, send stop.
if (stop) {
i2c_stop(obj);
}
return length;
}
int i2c_byte_read(i2c_t *obj, int last) {
char data;
int status;
status = i2c_do_read(obj,&data, last);
if (status) {
i2c_reset(obj);
}
return data;
}
int i2c_byte_write(i2c_t *obj, int data) {
int status = 0;
if(!addrSet)//obj->i2c->ADDRESS==0)
{
addrSet=1;
obj->i2c->ADDRESS = (data>>1);
if(data&1)
{
obj->i2c->EVENTS_RXDREADY = 0;
obj->i2c->TASKS_STARTRX = 1;
}
else{
obj->i2c->TASKS_STARTTX = 1;
}
}
else{
status = i2c_do_write(obj, data);
if(status) {
i2c_reset(obj);
}
}
return (1-status);
}

View File

@ -48,33 +48,21 @@ struct pwmout_s {
PinName pin;
};
/*
struct gpio_irq_s {
uint32_t port;
uint32_t pin;
uint32_t ch;
struct i2c_s {
NRF_TWI_Type *i2c;
PinName sda;
PinName scl;
int freq;
};
struct pwmout_s {
__IO uint32_t *MOD;
__IO uint32_t *CNT;
__IO uint32_t *CnV;
};
struct analogin_s {
ADCName adc;
};
struct dac_s {
DACName dac;
struct gpio_irq_s {
uint32_t ch;
};
struct i2c_s {
I2C_Type *i2c;
};
*/
#include "gpio_object.h"
#ifdef __cplusplus