Hello Particle community,
I’m working in a project similar to the open energy monitor (https://openenergymonitor.org) in order to measure voltage and current to get readings of instant, active and reactive power.
I would like to take advantage of the advanced ADC implemented in the STM32F205 of my electron. As far as I know, it is possible to set the MCU in Dual regular simultaneous Mode where two analog signals could
be sampled and converted at the same time ( http://www.st.com/content/ccc/resource/technical/document/application_note/c4/63/a9/f4/ae/f2/48/5d/CD00258017.pdf/files/CD00258017.pdf/jcr:content/translations/en.CD00258017.pdf Section 2.1.2) .
I found a source where the MCU mode is configured to this mode: https://github.com/g4lvanix/STM32F1-workarea/tree/master/Project/STM32F10x_StdPeriph_Examples/ADC/RegSimul_DualMode.
After reading some posts I can conclude that the MCU default mode is slow-interleaved mode ( Interesting results from various ADC sample times, Why dual slow interleaved?, https://github.com/spark/firmware/pull/258)
Based on the first code and the @nottheoilrig post I write a code that changes the mode. However when I tried to build the source code locally (using the instructions of https://github.com/spark/firmware/blob/master/docs/build.md) including the libraries in the user space I got a lot of errors.
This is the code I’m trying to compile:
#include "application.h"
#define ADC1_DR_Address ((uint32_t) 0x4001244c)
uint16_t ADC_ConvertedValue[20];
void setup()
{
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_ADCCLKConfig(RCC_PCLK2_Div4);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &ADC_ConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 10;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_InitStructure.ADC_Mode = ADC_Mode_SlowInterl;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_7Cycles5);
ADC_InitStructure.ADC_Mode = ADC_Mode_SlowInterl;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC2, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC2, ADC_Channel_0, 1, ADC_SampleTime_7Cycles5);
ADC_ExternalTrigConvCmd(ADC2, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
ADC_Cmd(ADC2, ENABLE);
ADC_ResetCalibration(ADC2);
while (ADC_GetResetCalibrationStatus(ADC2));
ADC_StartCalibration(ADC2);
while (ADC_GetCalibrationStatus(ADC2));
long start = micros();
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while (!DMA_GetFlagStatus(DMA1_FLAG_TC1));
DMA_ClearFlag(DMA1_FLAG_TC1);
}
, this is my make command:
luballe@MacBook-Pro:~/spark/firmware/main$ make all APP=ADCdualMode program-dfu PARTICLE_SERIAL_DEV=/dev/cu.usbmodem641 PLATFORM=electron
And this is the output:
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C ../modules/electron/user-part all program-dfu
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C ../../../user
Building file: applications/ADCdualMode/main.cpp
Invoking: ARM GCC CPP Compiler
mkdir -p ../build/target/user/platform-10-m/applications/ADCdualMode/applications/ADCdualMode/
arm-none-eabi-gcc -DSTM32_DEVICE -DSTM32F2XX -DPLATFORM_THREADING=1 -DPLATFORM_ID=10 -DPLATFORM_NAME=electron -DUSBD_VID_SPARK=0x2B04 -DUSBD_PID_DFU=0xD00A -DUSBD_PID_CDC=0xC00A -DSPARK_PLATFORM -g3 -gdwarf-2 -Os -mcpu=cortex-m3 -mthumb -DINCLUDE_PLATFORM=1 -DPRODUCT_ID=10 -DPRODUCT_FIRMWARE_VERSION=65535 -DUSE_STDPERIPH_DRIVER -DDFU_BUILD_ENABLE -DSYSTEM_VERSION_STRING=0.5.1 -DRELEASE_BUILD -I./inc -I../wiring/inc -I../system/inc -I../services/inc -I../communication/src -I../hal/inc -I../hal/shared -I/rtos/FreeRTOSv8.2.2/FreeRTOS/Source/include -I/rtos/FreeRTOSv8.2.2/FreeRTOS/Source/portable/GCC/ARM_CM3 -I../hal/src/electron -I../hal/src/stm32f2xx -I../hal/src/stm32 -I../platform/shared/inc -I../platform/MCU/STM32F2xx/CMSIS/Include -I../platform/MCU/STM32F2xx/CMSIS/Device/ST/Include -I../platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc -I../platform/MCU/shared/STM32/inc -I../platform/MCU/STM32F2xx/STM32_StdPeriph_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_Host_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/inc -I../dynalib/inc -I./applications/ADCdualMode -I./libraries -I. -MD -MP -MF ../build/target/user/platform-10-m/applications/ADCdualMode/applications/ADCdualMode/main.o.d -ffunction-sections -fdata-sections -Wall -Wno-switch -Wno-error=deprecated-declarations -fmessage-length=0 -fno-strict-aliasing -DSPARK=1 -DPARTICLE=1 -DSTART_DFU_FLASHER_SERIAL_SPEED=14400 -DSTART_YMODEM_FLASHER_SERIAL_SPEED=28800 -DSPARK_PLATFORM_NET=UBLOXSARA -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc -DUSER_FIRMWARE_IMAGE_SIZE=0x20000 -DUSER_FIRMWARE_IMAGE_LOCATION=0x8080000 -DMODULAR_FIRMWARE=1 -DMODULE_VERSION=4 -DMODULE_FUNCTION=5 -DMODULE_INDEX=1 -DMODULE_DEPENDENCY=4,2,15 -D_GNU_SOURCE -D_WINSOCK_H -fno-exceptions -fno-rtti -fcheck-new -std=gnu++11 -c -o ../build/target/user/platform-10-m/applications/ADCdualMode4/applications/ADCdualMode/main.o applications/ADCdualMode/main.cpp
applications/ADCdualMode/main.cpp: In function 'void setup()':
applications/ADCdualMode/main.cpp:15:22: error: 'RCC_PCLK2_Div4' was not declared in this scope
RCC_ADCCLKConfig(RCC_PCLK2_Div4);
^
applications/ADCdualMode/main.cpp:15:36: error: 'RCC_ADCCLKConfig' was not declared in this scope
RCC_ADCCLKConfig(RCC_PCLK2_Div4);
^
applications/ADCdualMode/main.cpp:17:27: error: 'RCC_AHBPeriph_DMA1' was not declared in this scope
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
^
applications/ADCdualMode/main.cpp:17:53: error: 'RCC_AHBPeriphClockCmd' was not declared in this scope
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
^
applications/ADCdualMode/main.cpp:19:28: error: 'RCC_APB2Periph_GPIOA' was not declared in this scope
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
^
applications/ADCdualMode/main.cpp:25:16: error: 'DMA1_Channel1' was not declared in this scope
DMA_DeInit(DMA1_Channel1);
^
applications/ADCdualMode/main.cpp:27:23: error: 'struct DMA_InitTypeDef' has no member named 'DMA_MemoryBaseAddr'
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &ADC_ConvertedValue;
^
applications/ADCdualMode/main.cpp:28:33: error: 'DMA_DIR_PeripheralSRC' was not declared in this scope
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
^
applications/ADCdualMode/main.cpp:36:23: error: 'struct DMA_InitTypeDef' has no member named 'DMA_M2M'
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
^
applications/ADCdualMode/main.cpp:36:33: error: 'DMA_M2M_Disable' was not declared in this scope
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
^
applications/ADCdualMode/main.cpp:41:23: error: 'struct ADC_InitTypeDef' has no member named 'ADC_Mode'
ADC_InitStructure.ADC_Mode = ADC_Mode_SlowInterl;
^
applications/ADCdualMode/main.cpp:41:34: error: 'ADC_Mode_SlowInterl' was not declared in this scope
ADC_InitStructure.ADC_Mode = ADC_Mode_SlowInterl;
^
applications/ADCdualMode/main.cpp:44:46: error: 'ADC_ExternalTrigConv_None' was not declared in this scope
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
^
applications/ADCdualMode/main.cpp:46:23: error: 'struct ADC_InitTypeDef' has no member named 'ADC_NbrOfChannel'
ADC_InitStructure.ADC_NbrOfChannel = 1;
^
applications/ADCdualMode/main.cpp:49:54: error: 'ADC_SampleTime_7Cycles5' was not declared in this scope
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_7Cycles5);
^
applications/ADCdualMode/main.cpp:51:23: error: 'struct ADC_InitTypeDef' has no member named 'ADC_Mode'
ADC_InitStructure.ADC_Mode = ADC_Mode_SlowInterl;
^
applications/ADCdualMode/main.cpp:56:23: error: 'struct ADC_InitTypeDef' has no member named 'ADC_NbrOfChannel'
ADC_InitStructure.ADC_NbrOfChannel = 1;
^
applications/ADCdualMode/main.cpp:61:41: error: 'ADC_ExternalTrigConvCmd' was not declared in this scope
ADC_ExternalTrigConvCmd(ADC2, ENABLE);
^
applications/ADCdualMode4/main.cpp:67:30: error: 'ADC_ResetCalibration' was not declared in this scope
ADC_ResetCalibration(ADC1);
^
applications/ADCdualMode/main.cpp:68:46: error: 'ADC_GetResetCalibrationStatus' was not declared in this scope
while (ADC_GetResetCalibrationStatus(ADC1));
^
applications/ADCdualMode/main.cpp:70:30: error: 'ADC_StartCalibration' was not declared in this scope
ADC_StartCalibration(ADC1);
^
applications/ADCdualMode/main.cpp:71:41: error: 'ADC_GetCalibrationStatus' was not declared in this scope
while (ADC_GetCalibrationStatus(ADC1));
^
applications/ADCdualMode/main.cpp:76:46: error: 'ADC_GetResetCalibrationStatus' was not declared in this scope
while (ADC_GetResetCalibrationStatus(ADC2));
^
applications/ADCdualMode/main.cpp:79:41: error: 'ADC_GetCalibrationStatus' was not declared in this scope
while (ADC_GetCalibrationStatus(ADC2));
^
applications/ADCdualMode/main.cpp:85:42: error: 'ADC_SoftwareStartConvCmd' was not declared in this scope
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
^
applications/ADCdualMode/main.cpp:87:31: error: 'DMA1_FLAG_TC1' was not declared in this scope
while (!DMA_GetFlagStatus(DMA1_FLAG_TC1));
^
applications/ADCdualMode/main.cpp:88:19: error: 'DMA1_FLAG_TC1' was not declared in this scope
DMA_ClearFlag(DMA1_FLAG_TC1);
^
make[2]: *** [../build/target/user/platform-10-m/applications/ADCdualMode/applications/ADCdualMode/main.o] Error 1
make[1]: *** [user] Error 2
make: *** [modules/electron/user-part] Error 2
My question is: What am I doing wrong? Is there anything I’m missing?
I do really appreciate any help with this issue.
Luis Ballesteros