Added the 'E' class, with getAnalogVRef and getTemperature (fix #60)

Deprecated Math.clip (not in spec) and introduced E.clip
            Fixed bug in common.py that meant that ifndefs in JSON were sometimes not obeyed (better mem usage on small chips)
This commit is contained in:
Gordon Williams 2014-01-29 18:04:51 +00:00
parent 998abaadb8
commit 491a49eb32
9 changed files with 255 additions and 140 deletions

View File

@ -2,6 +2,9 @@
We now loop without a seek to position inside the string (much faster if loop is not near the start of a fn) (fix #53)
Faster string iteration which doesn't involve incrementing it->index
Swapped to jumptable to lexer (should be a bit faster)
Added the 'E' class, with getAnalogVRef and getTemperature (fix #60)
Deprecated Math.clip (not in spec) and introduced E.clip
Fixed bug in common.py that meant that ifndefs in JSON were sometimes not obeyed (better mem usage on small chips)
1v47 : Fix issue with dump() and input_pullup not being quoted
Fix regression that broke OneWire in Espruino Board (#197)

View File

@ -317,6 +317,7 @@ endif
WRAPPERFILE=gen/jswrapper.c
WRAPPERSOURCES = \
src/jswrap_pin.c \
src/jswrap_espruino.c \
src/jswrap_functions.c \
src/jswrap_modules.c \
src/jswrap_process.c \

View File

@ -204,7 +204,7 @@ double jswrap_math_pow(double x, double y)
/*JSON{ "type":"staticmethod", "ifndef" : "SAVE_ON_FLASH",
"class" : "Math", "name" : "clip",
"generate" : "jswrap_math_clip",
"description" : "Clip a number to be between min and max (inclusive)",
"description" : "DEPRECATED - Please use `E.clip()` instead. Clip a number to be between min and max (inclusive)",
"params" : [ [ "x", "float", "A floating point value to clip"],
[ "min", "float", "The smallest the value should be"],
[ "max", "float", "The largest the value should be"] ],

View File

@ -108,7 +108,7 @@ def get_jsondata(is_for_document, parseArgs = True):
jsondata["include"] = jswrap[:-2]+".h"
if ("ifndef" in jsondata) and (jsondata["ifndef"] in defines):
print "Dropped because of #ifndef "+jsondata["ifndef"]
if ("ifdef" in jsondata) and not (jsondata["ifdef"] in defines):
elif ("ifdef" in jsondata) and not (jsondata["ifdef"] in defines):
print "Dropped because of #ifdef "+jsondata["ifdef"]
else:
jsondatas.append(jsondata)

View File

@ -220,4 +220,11 @@ void jshKickUSBWatchdog();
#endif // ARM
#ifdef STM32F1
// the temperature from the internal temperature sensor
JsVarFloat jshReadTemperature();
// The voltage that a reading of 1 from `analogRead` actually represents
JsVarFloat jshReadVRef();
#endif
#endif /* JSHARDWARE_H_ */

View File

@ -97,6 +97,7 @@ typedef enum {
JSH_ANALOG_CH14,
JSH_ANALOG_CH15,
JSH_ANALOG_CH16,
JSH_ANALOG_CH17,
JSH_MASK_ANALOG_CH = 31,
JSH_MASK_ANALOG_ADC = JSH_ANALOG1|JSH_ANALOG2|JSH_ANALOG3|JSH_ANALOG4,

52
src/jswrap_espruino.c Normal file
View File

@ -0,0 +1,52 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* JavaScript methods for Espruino utility functions
* ----------------------------------------------------------------------------
*/
#include "jswrap_espruino.h"
/*JSON{ "type":"class",
"class" : "E",
"description" : ["This is the built-in JavaScript class for Espruino utility functions." ]
}*/
/*JSON{ "type":"staticmethod", "ifdef" : "STM32F1", "ifndef" : "SAVE_ON_FLASH",
"class": "E", "name" : "getTemperature",
"generate_full" : "jshReadTemperature()",
"description" : ["Use the STM32's internal thermistor to work out the temperature.",
"NOTE: This is very inaccurate (+/- 20 degrees C) and varies from chip to chip. It can be used to work out when temperature rises or falls, but don't expect absolute temperature readings to be useful."],
"return" : ["float", "The temperature in degrees C"]
}*/
/*JSON{ "type":"staticmethod", "ifdef" : "STM32F1", "ifndef" : "SAVE_ON_FLASH",
"class": "E", "name" : "getAnalogVRef",
"generate_full" : "jshReadVRef()",
"description" : "Check the internal voltage reference. To work out an actual voltage of an input pin, you can use `analogRead(pin)*E.getAnalogVRef()` ",
"return" : ["float", "The voltage (in Volts) that a reading of 1 from `analogRead` actually represents"]
}*/
/*JSON{ "type":"staticmethod", "ifndef" : "SAVE_ON_FLASH",
"class" : "E", "name" : "clip",
"generate" : "jswrap_espruino_clip",
"description" : "Clip a number to be between min and max (inclusive)",
"params" : [ [ "x", "float", "A floating point value to clip"],
[ "min", "float", "The smallest the value should be"],
[ "max", "float", "The largest the value should be"] ],
"return" : ["float", "The value of x, clipped so as not to be below min or above max."]
}*/
JsVarFloat jswrap_espruino_clip(JsVarFloat x, JsVarFloat min, JsVarFloat max) {
if (x<min) x=min;
if (x>max) x=max;
return x;
}

18
src/jswrap_espruino.h Normal file
View File

@ -0,0 +1,18 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* JavaScript methods for Espruino utility functions
* ----------------------------------------------------------------------------
*/
#include "jsvar.h"
#include "jshardware.h"
JsVarFloat jswrap_espruino_clip(JsVarFloat x, JsVarFloat min, JsVarFloat max);

View File

@ -227,19 +227,19 @@ static inline uint8_t stmPortSource(Pin pin) {
#endif*/
}
static inline ADC_TypeDef *stmADC(Pin pin) {
if (pinInfo[pin].analog & JSH_ANALOG1) return ADC1;
if (pinInfo[pin].analog & JSH_ANALOG2) return ADC2;
if (pinInfo[pin].analog & JSH_ANALOG3) return ADC3;
static inline ADC_TypeDef *stmADC(JsvPinInfoAnalog analog) {
if (analog & JSH_ANALOG1) return ADC1;
if (analog & JSH_ANALOG2) return ADC2;
if (analog & JSH_ANALOG3) return ADC3;
#if ADCS>3
if (pinInfo[pin].analog & JSH_ANALOG4) return ADC4;
if (analog & JSH_ANALOG4) return ADC4;
#endif
jsErrorInternal("stmADC");
return ADC1;
}
static inline uint8_t stmADCChannel(Pin pin) {
switch (pinInfo[pin].analog & JSH_MASK_ANALOG_CH) {
static inline uint8_t stmADCChannel(JsvPinInfoAnalog analog) {
switch (analog & JSH_MASK_ANALOG_CH) {
#ifndef STM32F3XX
case JSH_ANALOG_CH0 : return ADC_Channel_0;
#endif
@ -259,6 +259,7 @@ static inline uint8_t stmADCChannel(Pin pin) {
case JSH_ANALOG_CH14 : return ADC_Channel_14;
case JSH_ANALOG_CH15 : return ADC_Channel_15;
case JSH_ANALOG_CH16 : return ADC_Channel_16;
case JSH_ANALOG_CH17 : return ADC_Channel_17;
default: jsErrorInternal("stmADCChannel"); return 0;
}
}
@ -1200,148 +1201,180 @@ bool jshPinInput(Pin pin) {
return value;
}
static NO_INLINE JsVarFloat jshAnalogRead(JsvPinInfoAnalog analog) {
ADC_TypeDef *ADCx = stmADC(analog);
bool needs_init = false;
if (ADCx == ADC1) {
static bool inited = false;
if (!inited) {
inited = true;
needs_init = true;
#if defined(STM32F3)
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC12, ENABLE);
#elif defined(STM32F4)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
#else
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
#endif
}
} else if (ADCx == ADC2) {
static bool inited = false;
if (!inited) {
inited = true;
needs_init = true;
#if defined(STM32F3)
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC12, ENABLE);
#elif defined(STM32F4)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
#else
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
#endif
}
} else if (ADCx == ADC3) {
static bool inited = false;
if (!inited) {
inited = true;
needs_init = true;
#if defined(STM32F3)
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC34, ENABLE);
#elif defined(STM32F4)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
#else
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
#endif
}
#if ADCS>3
} else if (ADCx == ADC4) {
static bool inited = false;
if (!inited) {
inited = true;
needs_init = true;
#if defined(STM32F3)
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC34, ENABLE);
#elif defined(STM32F4)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC4, ENABLE);
#else
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC4, ENABLE);
#endif
}
#endif
} else {
jsErrorInternal("couldn't find ADC!");
return -1;
}
if (needs_init) {
#ifdef STM32F3
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_CommonStructInit(&ADC_CommonInitStructure);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Clock = ADC_Clock_SynClkModeDiv2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_SampleTime_1Cycles5;
ADC_CommonInit(ADCx, &ADC_CommonInitStructure);
#endif
// ADC Structure Initialization
ADC_InitTypeDef ADC_InitStructure;
ADC_StructInit(&ADC_InitStructure);
// Preinit
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
#ifndef STM32F3
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
#if defined(STM32F2) || defined(STM32F4)
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
#else
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_NbrOfChannel = 1;
#endif
#endif
ADC_Init(ADCx, &ADC_InitStructure);
// Enable the ADC
ADC_Cmd(ADCx, ENABLE);
#ifdef STM32API2
// No calibration??
#else
// Calibrate
ADC_ResetCalibration(ADCx);
while(ADC_GetResetCalibrationStatus(ADCx));
ADC_StartCalibration(ADCx);
while(ADC_GetCalibrationStatus(ADCx));
#endif
}
// Configure channel
#if defined(STM32F2) || defined(STM32F4)
uint8_t sampleTime = ADC_SampleTime_480Cycles;
#elif defined(STM32F3)
uint8_t sampleTime = ADC_SampleTime_601Cycles5;
#else
uint8_t sampleTime = ADC_SampleTime_239Cycles5/*ADC_SampleTime_55Cycles5*/;
#endif
ADC_RegularChannelConfig(ADCx, stmADCChannel(analog), 1, sampleTime);
// Start the conversion
#if defined(STM32F2) || defined(STM32F4)
ADC_SoftwareStartConv(ADCx);
#elif defined(STM32F3)
ADC_StartConversion(ADCx);
#else
ADC_SoftwareStartConvCmd(ADCx, ENABLE);
#endif
// Wait until conversion completion
WAIT_UNTIL(ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) != RESET, "ADC");
// Get the conversion value
return ADC_GetConversionValue(ADCx) / (JsVarFloat)65535;
}
JsVarFloat jshPinAnalog(Pin pin) {
JsVarFloat value = 0;
if (pin >= JSH_PIN_COUNT /* inc PIN_UNDEFINED */ || pinInfo[pin].analog==JSH_ANALOG_NONE) {
jshPrintCapablePins(pin, "Analog Input", 0,0,0,0, true);
return 0;
}
ADC_TypeDef *ADCx = stmADC(pin);
bool needs_init = false;
if (pinInfo[pin].analog & JSH_ANALOG1) {
static bool inited = false;
if (!inited) {
inited = true;
needs_init = true;
#if defined(STM32F3)
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC12, ENABLE);
#elif defined(STM32F4)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
#else
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
#endif
}
} else if (pinInfo[pin].analog & JSH_ANALOG2) {
static bool inited = false;
if (!inited) {
inited = true;
needs_init = true;
#if defined(STM32F3)
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC12, ENABLE);
#elif defined(STM32F4)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
#else
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
#endif
}
} else if (pinInfo[pin].analog & JSH_ANALOG3) {
static bool inited = false;
if (!inited) {
inited = true;
needs_init = true;
#if defined(STM32F3)
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC34, ENABLE);
#elif defined(STM32F4)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
#else
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
#endif
}
#if ADCS>3
} else if (pinInfo[pin].analog & JSH_ANALOG4) {
static bool inited = false;
if (!inited) {
inited = true;
needs_init = true;
#if defined(STM32F3)
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC34, ENABLE);
#elif defined(STM32F4)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC4, ENABLE);
#else
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC4, ENABLE);
#endif
}
#endif
} else {
jsErrorInternal("couldn't find ADC!");
return -1;
}
if (needs_init) {
#ifdef STM32F3
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_CommonStructInit(&ADC_CommonInitStructure);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Clock = ADC_Clock_SynClkModeDiv2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_SampleTime_1Cycles5;
ADC_CommonInit(ADCx, &ADC_CommonInitStructure);
#endif
// ADC Structure Initialization
ADC_InitTypeDef ADC_InitStructure;
ADC_StructInit(&ADC_InitStructure);
// Preinit
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
#ifndef STM32F3
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
#if defined(STM32F2) || defined(STM32F4)
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
#else
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_NbrOfChannel = 1;
#endif
#endif
ADC_Init(ADCx, &ADC_InitStructure);
// Enable the ADC
ADC_Cmd(ADCx, ENABLE);
#ifdef STM32API2
// No calibration??
#else
// Calibrate
ADC_ResetCalibration(ADCx);
while(ADC_GetResetCalibrationStatus(ADCx));
ADC_StartCalibration(ADCx);
while(ADC_GetCalibrationStatus(ADCx));
#endif
}
jshSetPinStateIsManual(pin, false);
jshPinSetState(pin, JSHPINSTATE_ADC_IN);
// Configure channel
#if defined(STM32F2) || defined(STM32F4)
uint8_t sampleTime = ADC_SampleTime_480Cycles;
#elif defined(STM32F3)
uint8_t sampleTime = ADC_SampleTime_601Cycles5;
#else
uint8_t sampleTime = ADC_SampleTime_239Cycles5/*ADC_SampleTime_55Cycles5*/;
#endif
ADC_RegularChannelConfig(ADCx, stmADCChannel(pin), 1, sampleTime);
// Start the conversion
#if defined(STM32F2) || defined(STM32F4)
ADC_SoftwareStartConv(ADCx);
#elif defined(STM32F3)
ADC_StartConversion(ADCx);
#else
ADC_SoftwareStartConvCmd(ADCx, ENABLE);
#endif
// Wait until conversion completion
WAIT_UNTIL(ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) != RESET, "ADC");
// Get the conversion value
value = ADC_GetConversionValue(ADCx) / (JsVarFloat)65535;
return value;
return jshAnalogRead(pinInfo[pin].analog);
}
#ifdef STM32F1
// the temperature from the internal temperature sensor
JsVarFloat jshReadTemperature() {
// enable sensor
ADC1->CR2 |= ADC_CR2_TSVREFE;
jshDelayMicroseconds(10);
// read
JsVarFloat varVolts = jshAnalogRead(JSH_ANALOG1 | JSH_ANALOG_CH17);
JsVarFloat valTemp = jshAnalogRead(JSH_ANALOG1 | JSH_ANALOG_CH16);
JsVarFloat vSense = valTemp * 1.2 / varVolts;
// disable sensor
ADC1->CR2 &= ~ADC_CR2_TSVREFE;
return ((1.43/*V25*/ - vSense) / 0.0043/*Avg_Slope*/) + 25;
}
// The voltage that a reading of 1 from `analogRead` actually represents
JsVarFloat jshReadVRef() {
// enable sensor
ADC1->CR2 |= ADC_CR2_TSVREFE;
jshDelayMicroseconds(10);
// read
JsVarFloat r = jshAnalogRead(JSH_ANALOG1 | JSH_ANALOG_CH17);
// disable sensor
ADC1->CR2 &= ~ADC_CR2_TSVREFE;
return 1.20 / r;
}
#endif
void jshPinOutput(Pin pin, bool value) {
if (jshIsPinValid(pin)) {
if (!jshGetPinStateIsManual(pin))