Skip to content

Commit

Permalink
Merge pull request #174 from thomaseichinger/ADC
Browse files Browse the repository at this point in the history
ADC module of the mc1322x MCU
  • Loading branch information
OlegHahm committed Sep 23, 2013
2 parents da9965f + 040fb15 commit bfbd765
Show file tree
Hide file tree
Showing 6 changed files with 567 additions and 0 deletions.
3 changes: 3 additions & 0 deletions cpu/mc1322x/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
MODULE =cpu

DIRS =
ifneq (,$(findstring mc1322x_adc,$(USEMODULE)))
DIRS += adc
endif

all: $(BINDIR)$(MODULE).a
@for i in $(DIRS) ; do $(MAKE) -C $$i ; done ;
Expand Down
5 changes: 5 additions & 0 deletions cpu/mc1322x/adc/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
INCLUDES = -I$(RIOTBASE)/cpu/mc1322x/adc/include

MODULE =mc1322x_adc

include $(MAKEBASE)/Makefile.base
192 changes: 192 additions & 0 deletions cpu/mc1322x/adc/adc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*
* adc.c - implementation of the Analog to Digital Converter module of the mc1322x MCU
* Copyright (C) 2013 Thomas Eichinger <thomas.eichinger@fu-berlin.de>
*
* This source code is licensed under the GNU Lesser General Public License,
* Version 2. See the file LICENSE for more details.
*
* This file is part of RIOT.
*/

#include "adc.h"
#include "gpio.h"

#define ADC_CLOCK_DIVIDER_300kHz 0x50

#ifndef REF_OSC
#define REF_OSC 24000000UL /* reference osc. frequency */
#endif

#define ADC_PRESCALE_CLK 1000000 /* targeted prescale clk */
#define ADC_PRESCALE_VALUE ((REF_OSC / ADC_PRESCALE_CLK)-1)

#define ADC_CONVERT_TIME 23 /* function of prescale clk. has to be >= 20us */

#define ADC_NUM_CHANS 8

/**
* Initializes the ADC module.
*
* Analog Clk set to 300kHz
* Prescale Clk set to 1MHz
* Convert Time set to 23us
* Not using timers or IRQs
*/
void adc_init(void)
{
/* configure frequencies */
ADC->CLOCK_DIVIDER = ADC_CLOCK_DIVIDER_300kHz;
ADC->PRESCALE = ADC_PRESCALE_VALUE;

/* power on */
ADC->CONTROLbits.ON = 0x1;

/* ON-TIME must be >= 10us */
ADC->ON_TIME = 0xa;

/* should be >= 20us (6 ADC clks) */
ADC->CONVERT_TIME = ADC_CONVERT_TIME;

/* automated mode */
ADC->MODE = 0x0;

/* don't use IRQs */
ADC->FIFO_CONTROL = 0x0;

/* disable all input channels */
ADC->SEQ_1 = 0x0;
/* sequence using convert time */
ADC->SEQ_1bits.SEQ_MODE = 0x0;
/* enable battery reference voltage channel */
ADC->SEQ_1bits.BATT = 0x1;

/* disable all input channels */
ADC->SEQ_2 = 0x0;
/* sequence using convert time */
ADC->SEQ_2bits.SEQ_MODE = 0x0;
}

/**
* Set up a given channel 0...7 for ADC usage.
*
* \param channel The channel to set up
*/
void adc_setup_channel(uint8_t channel)
{
switch (channel) {
case 0:
ADC->SEQ_1bits.CH0 = 0x1;
GPIO->FUNC_SEL.ADC0 = 0x1;
GPIO->PAD_DIR.ADC0 = 0x0;
GPIO->PAD_KEEP.ADC0 = 0x0;
GPIO->PAD_PU_EN.ADC0 = 0;
break;

case 1:
ADC->SEQ_1bits.CH1 = 0x1;
GPIO->FUNC_SEL.ADC1 = 0x1;
GPIO->PAD_DIR.ADC1 = 0x0;
GPIO->PAD_KEEP.ADC1 = 0x0;
GPIO->PAD_PU_EN.ADC1 = 0;
break;

case 2:
ADC->SEQ_1bits.CH2 = 0x1;
GPIO->FUNC_SEL.ADC2 = 0x1;
GPIO->PAD_DIR.ADC2 = 0x0;
GPIO->PAD_KEEP.ADC2 = 0x0;
GPIO->PAD_PU_EN.ADC2 = 0;
break;

case 3:
ADC->SEQ_1bits.CH3 = 0x1;
GPIO->FUNC_SEL.ADC3 = 0x1;
GPIO->PAD_DIR.ADC3 = 0x0;
GPIO->PAD_KEEP.ADC3 = 0x0;
GPIO->PAD_PU_EN.ADC3 = 0;
break;

case 4:
ADC->SEQ_1bits.CH4 = 0x1;
GPIO->FUNC_SEL.ADC4 = 0x1;
GPIO->PAD_DIR.ADC4 = 0x0;
GPIO->PAD_KEEP.ADC4 = 0x0;
GPIO->PAD_PU_EN.ADC4 = 0;
break;

case 5:
ADC->SEQ_1bits.CH5 = 0x1;
GPIO->FUNC_SEL.ADC5 = 0x1;
GPIO->PAD_DIR.ADC5 = 0x0;
GPIO->PAD_KEEP.ADC5 = 0x0;
GPIO->PAD_PU_EN.ADC5 = 0;
break;

case 6:
ADC->SEQ_1bits.CH6 = 0x1;
GPIO->FUNC_SEL.ADC6 = 0x1;
GPIO->PAD_DIR.ADC6 = 0x0;
GPIO->PAD_KEEP.ADC6 = 0x0;
GPIO->PAD_PU_EN.ADC6 = 0;
break;

case 7:
ADC->SEQ_1bits.CH7 = 0x1;
GPIO->FUNC_SEL.ADC7 = 0x1;
GPIO->PAD_DIR.ADC7 = 0x0;
GPIO->PAD_KEEP.ADC7 = 0x0;
GPIO->PAD_PU_EN.ADC7 = 0;
break;
}
}

/**
* Read from the ADC FIFO
* Reads a 16 bit value from the ADC FIFO.
* Bits 15:12 contain the channel the value origin.
* Bits 11:0 contain the actual measured value.
*
* \return 16 Bits containing the channel and the measurement.
*/
uint16_t adc_read(void)
{
/* wait for ADC result */
while (ADC->FIFO_STATUSbits.EMPTY) {
continue;
}

/* upper 4 bits contain channel number */
return ADC->FIFO_READ;
}

/**
* Flushes any measured values from the ADC FIFO until FIFO is empty.
*/
void adc_flush(void)
{
while (!ADC->FIFO_STATUSbits.EMPTY) {
ADC->FIFO_READ;
}
}

/**
* When using several channels simultaniously this function can read
* values from the ADC FIFO and store them in an array sorted by the
* channel number.
*
* \param channels_read An array of 8 uint16_t the measured values get
* stored into. The user could use ADC_NUM_CHANS
* to asure compliancy.
*/
void adc_service(uint16_t *channels_read)
{
uint16_t tmp;

while (!ADC->FIFO_STATUSbits.EMPTY) {
tmp = ADC->FIFO_READ;

if ((tmp >> 12) < ADC_NUM_CHANS) {
channels_read[tmp >> 12] = tmp & 0x0fff;
}
}
}
132 changes: 132 additions & 0 deletions cpu/mc1322x/adc/include/adc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* adc.h - Structure definition for registers of the
* Analog to Digital Converter module of the mc1322x MCU
* Copyright (C) 2013 Thomas Eichinger <thomas.eichinger@fu-berlin.de>
*
* This source code is licensed under the GNU Lesser General Public License,
* Version 2. See the file LICENSE for more details.
*
* This file is part of RIOT.
*/

#ifndef ADC_H
#define ADC_H

#include <stdint.h>

#define ADC_BASE (0x8000D000)

/* Structure-based register definitions */
/* ADC registers are all 16-bit wide with 16-bit access only */
struct ADC_struct {
union {
uint16_t COMP[8];
struct {
uint16_t COMP_0;
uint16_t COMP_1;
uint16_t COMP_2;
uint16_t COMP_3;
uint16_t COMP_4;
uint16_t COMP_5;
uint16_t COMP_6;
uint16_t COMP_7;
};
};
uint16_t BAT_COMP_OVER;
uint16_t BAT_COMP_UNDER;
union {
uint16_t SEQ_1;
struct ADC_SEQ_1 {
uint16_t CH0: 1;
uint16_t CH1: 1;
uint16_t CH2: 1;
uint16_t CH3: 1;
uint16_t CH4: 1;
uint16_t CH5: 1;
uint16_t CH6: 1;
uint16_t CH7: 1;
uint16_t BATT: 1;
uint16_t : 6;
uint16_t SEQ_MODE: 1;
} SEQ_1bits;
};
union {
uint16_t SEQ_2;
struct ADC_SEQ_2 {
uint16_t CH0: 1;
uint16_t CH1: 1;
uint16_t CH2: 1;
uint16_t CH3: 1;
uint16_t CH4: 1;
uint16_t CH5: 1;
uint16_t CH6: 1;
uint16_t CH7: 1;
uint16_t : 7;
uint16_t SEQ_MODE: 1;
} SEQ_2bits;
};
union {
uint16_t CONTROL;
struct ADC_CONTROL {
uint16_t ON: 1;
uint16_t TIMER1_ON: 1;
uint16_t TIMER2_ON: 1;
uint16_t SOFT_RESET: 1;
uint16_t AD1_VREFHL_EN: 1;
uint16_t AD2_VREFHL_EN: 1;
uint16_t : 6;
uint16_t COMPARE_IRQ_MASK: 1;
uint16_t SEQ1_IRQ_MASK: 1;
uint16_t SEQ2_IRQ_MASK: 1;
uint16_t FIFO_IRQ_MASK: 1;
} CONTROLbits;
};
uint16_t TRIGGERS;
uint16_t PRESCALE;
uint16_t reserved1;
uint16_t FIFO_READ;
uint16_t FIFO_CONTROL;
union {
uint16_t FIFO_STATUS;
struct ADC_FIFO_STATUS {
uint16_t LEVEL: 4;
uint16_t FULL: 1;
uint16_t EMPTY: 1;
uint16_t : 10;
} FIFO_STATUSbits;
};
uint16_t reserved2[5];
uint16_t SR_1_HIGH;
uint16_t SR_1_LOW;
uint16_t SR_2_HIGH;
uint16_t SR_2_LOW;
uint16_t ON_TIME;
uint16_t CONVERT_TIME;
uint16_t CLOCK_DIVIDER;
uint16_t reserved3;
union {
uint16_t OVERRIDE;
struct ADC_OVERRIDE {
uint16_t MUX1: 4;
uint16_t MUX2: 4;
uint16_t AD1_ON: 1;
uint16_t AD2_ON: 1;
uint16_t : 6;
} OVERRIDEbits;
};
uint16_t IRQ;
uint16_t MODE;
uint16_t RESULT_1;
uint16_t RESULT_2;
};

static volatile struct ADC_struct *const ADC = (void *)(ADC_BASE);

/* function prototypes */
void adc_init(void);
void adc_setup_channel(uint8_t channel);
uint16_t adc_read(void);
void adc_flush(void);
void adc_service(uint16_t *channels_read);

#endif /* ADC_H */
Loading

0 comments on commit bfbd765

Please # to comment.