diff --git a/Makefile-ARM b/Makefile-ARM index fff1b40..b851ec9 100644 --- a/Makefile-ARM +++ b/Makefile-ARM @@ -100,8 +100,9 @@ TARGET = $(PROGRAM).hex SOURCES = mendel.c cpu.c serial.c sermsg.c sersendf.c delay.c SOURCES += gcode_parse.c gcode_process.c pinio.c timer.c clock.c SOURCES += dda_queue.c dda_maths.c dda_kinematics.c dda.c dda_lookahead.c +SOURCES += analog.c # Sources left: -# analog.c home.c crc.c intercom.c debug.c spi.c usb_serial.c +# home.c crc.c intercom.c debug.c spi.c usb_serial.c # graycode.c pff.c temp.c watchdog.c heater.c pff_diskio.c ifeq ($(MCU), lpc1114) diff --git a/analog-arm.c b/analog-arm.c new file mode 100644 index 0000000..55c8fb7 --- /dev/null +++ b/analog-arm.c @@ -0,0 +1,80 @@ + +/** \file + \brief Analog subsystem, ARM specific part. + + Nice feature of the LPC11xx is, it features a hardware scan mode, which scans + a given set of ADC pins over and over again, without need for an interrupt + to switch between channels. Our code becomes pretty simple: set this + mechanism up at init time and be done for the time being. + + Unlike ATmegas, LPC1114 features no analog voltage reference selector, it + always compares against Vdd. This is the equivalent of REFERENCE_AVCC on AVR. +*/ + +#if defined TEACUP_C_INCLUDE && defined __ARMEL__ + +#include "cmsis-lpc11xx.h" +#include "arduino.h" +#include "temp.h" + + +/** Inititalise the analog subsystem. + + Initialise the ADC and start hardware scan loop for all used sensors. + + LPC111x User Manual recommends an ADC clock of 4.5 MHz ("typically"), still + we reduce this to 1 MHz, because we're not nearly as much in a hurry. A + conversion needs 11 ADC clocks per channel, so we still get many thousand + conversions/second; we need just 100/s. +*/ +void analog_init() { + + if (NUM_TEMP_SENSORS) { // At least one channel in use. + + LPC_SYSCON->PDRUNCFG &= ~(1 << 4); // Turn on ADC clock. + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 13); // Turn on ADC power. + + /** + Register name mapping from LPC111x User Manual to CMSIS headers: + + chap. 25.5 cmsis-lpc11xx.h description + + AD0CR LPC_ADC->CR A/D control register. + AD0GDR LPC_ADC->GDR A/D global data register. + AD0INTEN LPC_ADC->INTEN A/D interrupt enable register. + AD0DRn LPC_ADC->DR[n] A/D channel n data register. + AD0STAT LPC_ADC->STAT A/D status register. + */ + // TODO: enable only the channels we use. + LPC_ADC->CR = (0xFF << 0) // All pins on (for now). + | ((F_CPU / 1000000) << 8) // 1 MHz ADC clock. + | (1 << 16) // Hardware scan mode. + | (0x0 << 17) // Maximum accuracy. + | (0x0 << 24); // Clear START. + + LPC_ADC->INTEN = 0; // No interrupt generation. + + // TODO: set up the channels configured, not two arbitrary ones. + LPC_IOCON->PIO1_0_CMSIS = (0x2 << 0) // Function AD1. + | (0 << 3) // Pullup inactive. + | (0 << 7); // Analog input mode. + LPC_IOCON->PIO1_1_CMSIS = (0x2 << 0) // Function AD2. + | (0 << 3) // Pullup inactive. + | (0 << 7); // Analog input mode. + } +} + +/** Read analog value. + + \param channel Channel to be read. + + \return Analog reading, 10-bit right aligned. + + Hardware scan mode nicely saves all the converted values separately, so + there's no need to hold them in a copy. +*/ +uint16_t analog_read(uint8_t index) { + return (LPC_ADC->DR[index] & 0xFFC0) >> 6; +} + +#endif /* defined TEACUP_C_INCLUDE && defined __ARMEL__ */ diff --git a/analog.c b/analog.c index f5aa556..252c454 100644 --- a/analog.c +++ b/analog.c @@ -7,7 +7,7 @@ #define TEACUP_C_INCLUDE #include "analog-avr.c" -//#include "analog-arm.c" +#include "analog-arm.c" #undef TEACUP_C_INCLUDE // No common code so far. diff --git a/mendel.c b/mendel.c index 363f5e5..60f77c0 100644 --- a/mendel.c +++ b/mendel.c @@ -39,8 +39,8 @@ #include "watchdog.h" #include "debug.h" #include "heater.h" -#include "analog.h" #endif /* __ARMEL_NOTYET__ */ +#include "analog.h" #include "pinio.h" #include "clock.h" #ifndef __ARMEL_NOTYET__ @@ -105,11 +105,11 @@ void init(void) { // set up dda dda_init(); - #ifndef __ARMEL_NOTYET__ // start up analog read interrupt loop, // if any of the temp sensors in your config.h use analog interface analog_init(); + #ifndef __ARMEL_NOTYET__ // set up temperature inputs temp_init();