-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #174 from thomaseichinger/ADC
ADC module of the mc1322x MCU
- Loading branch information
Showing
6 changed files
with
567 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 */ |
Oops, something went wrong.