Run STM32F103 from internal oscillator with PlatformIO (Arduino)? - arduino

How can the STM32F103C8 be configured to run with internal RC oscillator / HSI & PLL, i.e. without external crystal oscillator (as present on the "blue pill" board) with the Arduino framework in PlatformIO?
https://docs.platformio.org/en/latest/boards/ststm32/bluepill_f103c8.html
https://docs.platformio.org/en/latest/boards/ststm32/genericSTM32F103C8.html
https://docs.platformio.org/en/latest/frameworks/arduino.html
platformio.ini:
[env:bluepill_f103c8]
platform = ststm32
board = bluepill_f103c8
#board = genericSTM32F103C8
#board_build.mcu = stm32f103c8t6
#board_build.f_cpu = 72000000L
framework = arduino
lib_deps = olikraus/U8g2 # ^2.28.7
upload_protocol = stlink

I dug around a bit in the PlatformIO directory.
The following paths are for "generic":
C:\Users\<user>\.platformio\platforms\ststm32\boards\genericSTM32F103C8.json
C:\Users\<user>\.platformio\packages\framework-arduinoststm32\variants\Generic_F103Cx\variant.cpp
Define your own system clock configuration in e.g. your main.cpp:
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
/* Initializes the CPU, AHB and APB busses clocks */
// RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
// RCC_OscInitStruct.HSEState = RCC_HSE_ON;
// RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
// RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
while (1);
}
/* Initializes the CPU, AHB and APB busses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
while (1);
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC ;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
while (1);
}
}
The ini then is:
[env:bluepill_f103c8]
platform = ststm32
board = genericSTM32F103C8
framework = arduino
upload_protocol = stlink
lib_deps = olikraus/U8g2 # ^2.28.7
I'd recommend renaming the env to avoid confusion.
I have not yet verified the actual clock speed.
It should run at 36 MHz (8 MHz/2*9). The ini then needs `board_build.f_cpu = 36000000L`

Related

how can i activate UART(rs-232) with register setting at PICC?

I know there is #use rs232 command to activate it,
but i want to know how to set registers individually to activate rs232
i'm using PIC18f13k22.
I did like this:
INTCON = 0xc2;
IPR1 = 0x7f;
PIE1 = 0x20;
PIR1 = 0x10;
BAUDCON = 0x48;
RCSTA = 0x90;
TXSTA = 0xA6;
SPBRG = 0x82;
SPBRGH = 0x06;
I looked up PIC18f13k22 datasheet, and found related registers, and set like that.
and didn't work.
need help!
thanks
Here is a complete code that builds with Microchip MPLABX and XC8 v2.30:
/*
* File: main.c
* Author: dan1138
* Compiler: XC8 v2.30
*
* Created on October 6, 2020, 1:41 PM
*/
#pragma config FOSC = IRC, PLLEN = OFF, PCLKEN = ON, FCMEN = OFF, IESO = OFF
#pragma config PWRTEN = OFF, BOREN = SBORDIS, BORV = 19, WDTEN = OFF
#pragma config WDTPS = 32768, HFOFST = ON, MCLRE = ON, STVREN = ON, LVP = OFF
#pragma config BBSIZ = OFF, XINST = OFF, DEBUG = OFF, CP0 = OFF, CP1 = OFF
#pragma config CPB = OFF, CPD = OFF, WRT0 = OFF, WRT1 = OFF, WRTC = OFF
#pragma config WRTB = OFF, WRTD = OFF, EBTR0 = OFF, EBTR1 = OFF, EBTRB = OFF
#include <xc.h>
#include <stdio.h>
void putch(char txData)
{
if(1 == RCSTAbits.OERR)
{
RCSTAbits.CREN = 0;
RCSTAbits.CREN = 1;
}
while(0 == PIR1bits.TXIF)
{
}
TXREG = txData;
}
void main(void)
{
OSCCON = 0x60;
OSCCON2 = 0x04;
OSCTUNE = 0x00;
LATA = 0x00;
LATB = 0x00;
LATC = 0x00;
TRISA = 0x37;
TRISB = 0x70;
TRISC = 0xFF;
ANSEL = 0xFF;
ANSELH = 0x07;
WPUB = 0x00;
WPUA = 0x00;
INTCON2bits.nRBPU = 1;
BAUDCON = 0x08;
RCSTA = 0x90;
TXSTA = 0x24;
SPBRG = 0xCF;
SPBRGH = 0x00;
PIR1bits.TXIF = 0;
printf("\r\nPIC18F13K22 UART demo\r\n");
while (1)
{
}
}
The solution to your problem lies in knowing what to set the configuration word values to, and how to comprehend what information can be found in the data sheet.
I know the data sheet is dense and only documents what can be selected, but not why specific values should be chosen.
With more experience you can learn how to read data sheets and what can be useful.
As you made no effort to comment in the code you posted my code is likewise missing anything close to a useful comment.

Divided and duplicated frame capture output for ADNS 9800 Arduino

I am trying to interface an ADNS 9800 mouse chip which I took from "Sharkoon SHARK ZONE M50" . The original PCB is still in place.
I am trying to obtain a framecapture, which should be 30 x 30 pixels. I have connected the ADNS 9800 with SPI to an Arduino UNO Rev 3 (i.e. 5V operating voltage). I.e. MISO, MOSI, SCLK, DGND, AGND, NCS. I did not connect any voltage, since I concluded from previous attempts that that did not yield a good frame capture.
The current problem is that I get a frame capture that is divided in 3 parts: square top left (with a good image of the surroundings), square bottom left (which is a duplicate of top left) and a rectangle on the right half of the screen of monotone grey colour (which does change depending on light conditions). See image. I want the full screen to be one image, not the divided mess it is now. Therefore, it may be a question of the resolution that is used, it may be that it is 15x15 instead of 30x30. However I do not know where this is determined/set.
Also, I find it strange that no input voltage seems to be needed to obtain an image from the camera.
See attachments for frame capture and code (arduino + processing).
Frame output
Arduino code
#include
#include
// Registers
#define REG_Product_ID 0x00
#define REG_Revision_ID 0x01
#define REG_Motion 0x02
#define REG_Delta_X_L 0x03
#define REG_Delta_X_H 0x04
#define REG_Delta_Y_L 0x05
#define REG_Delta_Y_H 0x06
#define REG_SQUAL 0x07
#define REG_Pixel_Sum 0x08
#define REG_Maximum_Pixel 0x09
#define REG_Minimum_Pixel 0x0a
#define REG_Shutter_Lower 0x0b
#define REG_Shutter_Upper 0x0c
#define REG_Frame_Period_Lower 0x0d
#define REG_Frame_Period_Upper 0x0e
#define REG_Configuration_I 0x0f
#define REG_Configuration_II 0x10
#define REG_Frame_Capture 0x12
#define REG_SROM_Enable 0x13
#define REG_Run_Downshift 0x14
#define REG_Rest1_Rate 0x15
#define REG_Rest1_Downshift 0x16
#define REG_Rest2_Rate 0x17
#define REG_Rest2_Downshift 0x18
#define REG_Rest3_Rate 0x19
#define REG_Frame_Period_Max_Bound_Lower 0x1a
#define REG_Frame_Period_Max_Bound_Upper 0x1b
#define REG_Frame_Period_Min_Bound_Lower 0x1c
#define REG_Frame_Period_Min_Bound_Upper 0x1d
#define REG_Shutter_Max_Bound_Lower 0x1e
#define REG_Shutter_Max_Bound_Upper 0x1f
#define REG_LASER_CTRL0 0x20
#define REG_Observation 0x24
#define REG_Data_Out_Lower 0x25
#define REG_Data_Out_Upper 0x26
#define REG_SROM_ID 0x2a
#define REG_Lift_Detection_Thr 0x2e
#define REG_Configuration_V 0x2f
#define REG_Configuration_IV 0x39
#define REG_Power_Up_Reset 0x3a
#define REG_Shutdown 0x3b
#define REG_Inverse_Product_ID 0x3f
#define REG_Snap_Angle 0x42
#define REG_Motion_Burst 0x50
#define REG_SROM_Load_Burst 0x62
#define REG_Pixel_Burst 0x64
byte initComplete=0;
byte testctr=0;
unsigned long currTime;
unsigned long timer;
volatile int xdat;
volatile int ydat;
volatile byte movementflag=0;
const int ncs = 10;
const int lsPin = 4;//ANALOG
const int linearActPin = 9;
extern const unsigned short firmware_length;
extern const unsigned char firmware_data[];
String parseChar = ".";
void setup() {
Serial.begin(115200);
//For first parse put LF and CR there
Serial.println("");
//pinMode(ls, INPUT);
//ADNS 9800 setup
pinMode (ncs, OUTPUT);
SPI.begin();
SPI.setDataMode(SPI_MODE3);
SPI.setBitOrder(MSBFIRST);
//Set clock to 2 MHz
SPI.setClockDivider(8);
performStartup();
dispRegisters();
delay(100);
//Pin modes
pinMode(linearActPin, OUTPUT);
Serial.print("Ready");
Serial.println(parseChar);
//Serial.println("Device is ready");
//FrameCapture();
}
/* DO NOT EDIT BELOW; NECESSARY FOR ADNS9800 */
void performStartup(void){
// reset the chip
adns_com_end(); // ensure that the serial port is reset
adns_com_begin(); // ensure that the serial port is reset
adns_com_end(); // ensure that the serial port is reset
adns_write_reg(REG_Power_Up_Reset, 0x5a); // force reset
delay(50); // wait for it to reboot
// read registers 0x02 to 0x06 (and discard the data)
adns_read_reg(REG_Delta_X_L);
adns_read_reg(REG_Delta_X_H);
adns_read_reg(REG_Delta_Y_L);
adns_read_reg(REG_Delta_Y_H);
// upload the firmware
adns_upload_firmware();
delay(10);
//enable laser(bit 0 = 0b), in normal mode (bits 3,2,1 = 000b)
// reading the actual value of the register is important because the real
// default value is different from what is said in the datasheet, and if you
// change the reserved bytes (like by writing 0x00...) it would not work.
byte laser_ctrl0 = adns_read_reg(REG_LASER_CTRL0);
adns_write_reg(REG_LASER_CTRL0, laser_ctrl0 & 0xf1 );
//0x08 = enable fixed framerate, leave rest standard
//0x10 = disable AGC, leave rest standard
adns_write_reg(REG_Configuration_II, 0x08);
//Set resolution; cpi = REG_value x50
//Min: 0x01 50 cpi
//Max: 0xA4 8200 cpi
adns_write_reg(REG_Configuration_I, 0xA4);
//Set fixed framerate: FR = clk_freq/REG_value = 2000 fps
adns_write_reg(REG_Frame_Period_Max_Bound_Lower, 0xa8);
adns_write_reg(REG_Frame_Period_Max_Bound_Upper, 0x61);
//Set shutter time
adns_write_reg(REG_Shutter_Max_Bound_Lower,0x00);
adns_write_reg(REG_Shutter_Max_Bound_Upper,0x08);
//adns_write_reg(REG_Snap_Angle, 0x80);
delay(1);
Serial.print("Initialized");
Serial.println(parseChar);
}
void adns_com_begin(){
digitalWrite(ncs, LOW);
}
void adns_com_end(){
digitalWrite(ncs, HIGH);
}
byte adns_read_reg(byte reg_addr){
adns_com_begin();
// send adress of the register, with MSBit = 0 to indicate it's a read
SPI.transfer(reg_addr & 0x7f );
delayMicroseconds(100); // tSRAD
// read data
byte data = SPI.transfer(0);
delayMicroseconds(1); // tSCLK-NCS for read operation is 120ns
adns_com_end();
delayMicroseconds(19); // tSRW/tSRR (=20us) minus tSCLK-NCS
return data;
}
void adns_write_reg(byte reg_addr, byte data){
adns_com_begin();
//send adress of the register, with MSBit = 1 to indicate it's a write
SPI.transfer(reg_addr | 0x80 );
//sent data
SPI.transfer(data);
delayMicroseconds(20); // tSCLK-NCS for write operation
adns_com_end();
delayMicroseconds(100); // tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound
}
void adns_upload_firmware(){
// send the firmware to the chip, cf p.18 of the datasheet
//Serial.println("Uploading firmware...");
// set the configuration_IV register in 3k firmware mode
adns_write_reg(REG_Configuration_IV, 0x02); // bit 1 = 1 for 3k mode, other bits are reserved
// write 0x1d in SROM_enable reg for initializing
delay(10);
adns_write_reg(REG_SROM_Enable, 0x1d);
// wait for more than one frame period
delay(10); // assume that the frame rate is as low as 100fps... even if it should never be that low
// write 0x18 to SROM_enable to start SROM download
adns_write_reg(REG_SROM_Enable, 0x18);
// write the SROM file (=firmware data)
adns_com_begin();
//write burst destination adress
//bitwise OR to ensure MSB is 1
SPI.transfer(REG_SROM_Load_Burst | 0x80);
delayMicroseconds(50);
// send all bytes of the firmware
unsigned char c;
for(int i = 0; i < firmware_length; i++){
c = (unsigned char)pgm_read_byte(firmware_data + i);
SPI.transfer(c);
delayMicroseconds(15);
}
adns_com_end();
}
void adns_frame_capture(){
//Send signal to start datacollection frame capture
Serial.print("Frame capture");
Serial.println(parseChar);
// reset the chip
adns_write_reg(REG_Power_Up_Reset, 0x5a); // force reset
delay(50); // wait for it to reboot
delay(10);
//Write bytes to Frame_Capture
adns_write_reg(REG_Frame_Capture, 0x93);
adns_write_reg(REG_Frame_Capture, 0xc5);
// wait for more than two frame periods
delay(25); // assume that the frame rate is as low as 100fps... even if it should never be that low
//Check for the first pixel bij reading bit zero of Motion register
//If it is 1, first pixel available
byte motion = adns_read_reg(REG_Motion);
adns_com_begin();
delayMicroseconds(120);//delay t-SRAD = 100 us
byte pixel_burst;
if (motion == 0x21){
//Reading pixel values from ADNS and storing them in Array
for(int i = 0; i < 900; i++){
pixel_burst = adns_read_reg(REG_Pixel_Burst);
//Serial.print(i);
//Serial.print(":");
Serial.print(String(pixel_burst));
Serial.println(parseChar);
delayMicroseconds(15);
}
//Finished transmitting data
Serial.print("Data transfer finished");
Serial.println(parseChar);
//Transfer surface quality value
Serial.print("SQUAL");
Serial.print(String(adns_read_reg(REG_SQUAL)));
Serial.println(parseChar);
}else {
Serial.print("Frame capture failed");
Serial.println(parseChar);
}
adns_com_end();
//Hardware reset and firmware restore required to return navigation
performStartup();
}
void dispRegisters(void){
int oreg[7] = {
0x00,0x3F,0x2A,0x02 };
char* oregname[] = {
"Product_ID","Inverse_Product_ID","SROM_Version","Motion" };
byte regres;
digitalWrite(ncs,LOW);
int rctr=0;
for(rctr=0; rctr<4; rctr++){
SPI.transfer(oreg[rctr]);
delay(1);
//Serial.println("---");
//Serial.println(oregname[rctr]);
//Serial.println(oreg[rctr],HEX);
regres = SPI.transfer(0);
//Serial.println(regres,BIN);
//Serial.println(regres,HEX);
delay(1);
}
digitalWrite(ncs,HIGH);
}
/*********************************************************
DO NOT EDIT ABOVE; NECESSARY FOR RUNNING ADNS9800
*********************************************************/
String data = String();
//Process variables
int run = 0;
int t = 0;
unsigned long t_ms, t_us;
int dt = 0;//1/f = [ms]
long int t_run = 0;//[ms]
unsigned long ms_start, us_start;
void loop() {
if (dt == -1 || t_run == -1){
Serial.print("Time constant error");
Serial.println(parseChar);
}else if (run == 1 && t<t_run){
measure();
Serial.print(data);
Serial.println("");
Serial.println(parseChar);
}else if(run == 1 && t>=t_run){
//Measurement finished
Serial.print("Measurement finished");
Serial.println(parseChar);
digitalWrite(linearActPin, LOW);
run = 0;
t = 0;
}
}
void serialEvent(){
String data_rx;
if (Serial.available() > 0){
//Parse serial data until '.'
data_rx = Serial.readStringUntil('.');
//Remove '.' from buffer
data_rx = data_rx.substring(0, data_rx.length());
//Serial.print(data_rx);
if (data_rx.equals("Run")){
run = 1;
ms_start = millis();
us_start = micros();
digitalWrite(linearActPin, HIGH);
//Read registers and discard data
byte XDataL = adns_read_reg(REG_Delta_X_L);
byte XDataH = adns_read_reg(REG_Delta_X_H);
byte YDataL = adns_read_reg(REG_Delta_Y_L);
byte YDataH = adns_read_reg(REG_Delta_Y_H);
}else if(data_rx.equals("Frame capture run")){
adns_frame_capture();
}else if(data_rx.equals("SQUAL")){
Serial.println(String(adns_read_reg(REG_SQUAL)));
}else if(data_rx.startsWith("dt")){
dt = data_rx.substring(2,data_rx.length()).toInt();
}else if(data_rx.startsWith("trun")){
t_run = data_rx.substring(4,data_rx.length()).toInt();
}
}
}
void measure(void){
/*READ dx, dy, ls
increment t with dt
return String "t,dx,dy,ls"*/
//Read optic flow from ADNS
byte XDataL = adns_read_reg(REG_Delta_X_L);
byte XDataH = adns_read_reg(REG_Delta_X_H);
byte YDataL = adns_read_reg(REG_Delta_Y_L);
byte YDataH = adns_read_reg(REG_Delta_Y_H);
int ls;
unsigned long us, ms;
xdat = int(XDataH<<8);
ydat = int(YDataH<<8);
xdat |=int(XDataL);
ydat |=int(YDataL);
//int between 0-1023, with 5V/1024 = 0.0049 V/unit
ls = analogRead(lsPin);
//Calculate time elapsed between measurements
ms = millis();
us = micros();
t_ms = ms-ms_start;
t_us = us-us_start;
t = t_ms;
//Convert datatypes to string objects and combine
//us can always be divided by 4, so accurate to a resolution of 4 us
String d1 = String(t_ms);
String d2 = String(t_us);
String d3 = String(xdat);
String d4 = String(ydat);
String d5 = String(ls);
data = d2+","+d3+","+d4+","+d5;
//Increment time
delay(dt);
}
Processing code
/* BEP experiment
Communicates with arduino to conduct experiment
Receives and stores data
/
/ DATA PROTOCOL
data_rx
R start measuring
S do screendump
D device is ready
F measurement finished
/
import processing.serial.;
import controlP5.*;
//Serial COMM
Serial arduino;
String data_rx, data_tx;
String parseChar = ".";
//GUI
ControlP5 cp5;
Textfield txtfldDistance, txtfldSpeed, txtfldTs, txtfldN,
txtfldFl, txtfldBron, txtfldPattern, txtfldTrun;
Button btnRun, btnStop, btnFrame;
//File I/O
PrintWriter writer;
String path;
//Runtime variables
int run = 0;
int createWriter = 0;
int frameCapture = 0;
int frameDisplay = 0;
//Time management
String timestamp;
int ms, ms_start;
final int frameX = 30;
final int frameY = 30;
void setup() {
frameRate(60);
time();
//Create GUI
textSize(20);
size(360,660);
//Create textboxes
cp5 = new ControlP5(this);
txtfldDistance = cp5.addTextfield("Distance[m]:")
.setPosition(30, 30)
.setSize(70, 30)
.setAutoClear(false)
.setText("0.5");
txtfldSpeed = cp5.addTextfield("Speed[rev/s]:")
.setPosition(30, 90)
.setSize(70, 30)
.setAutoClear(false);
txtfldTs = cp5.addTextfield("t_s[ms]")
.setPosition(30, 150)
.setSize(70, 30)
.setAutoClear(false)
.setText("10");
txtfldTrun = cp5.addTextfield("t_run[s]")
.setPosition(30, 210)
.setSize(70, 30)
.setAutoClear(false);
txtfldFl = cp5.addTextfield("f[mm]")
.setPosition(130, 30)
.setSize(70, 30)
.setAutoClear(false)
.setText("14");
txtfldBron = cp5.addTextfield("Bron[Watt]")
.setPosition(130, 90)
.setSize(70, 30)
.setAutoClear(false)
.setText("40");
txtfldPattern = cp5.addTextfield("Pattern[mm]")
.setPosition(130, 150)
.setSize(70, 30)
.setAutoClear(false)
.setText("random");
txtfldN = cp5.addTextfield("n")
.setPosition(130, 210)
.setSize(70, 30)
.setAutoClear(false)
.setText("1");
btnRun = cp5.addButton("Run")
.setPosition(230, 270)
.setSize(50,30)
.lock();
btnStop = cp5.addButton("Stop")
.setPosition(150, 270)
.setSize(50,30)
.lock();
btnFrame = cp5.addButton("Frame_Capture")
.setPosition(30, 270)
.setSize(90,30)
.lock();
//Create Serial COMM object
print(timestamp+"SERIAL PORT: ");
println(Serial.list());
// List all the available serial ports:
//arduino = new Serial(this, Serial.list()[2], 115200);
arduino = new Serial(this, Serial.list()[0], 115200);
arduino.clear();
arduino.bufferUntil('.');
}
void draw() {
time();
Frame_Capture();
display_frame();
if (frameDisplay == 1){
display_frame();
frameDisplay = 0;
println(timestamp+"---------------------");
}
}
int n = 0;
int[] frame_capture_data = new int[900];
void serialEvent(Serial arduino){
if (arduino.available() > 0){
//Parse serial data until '.'
data_rx = arduino.readStringUntil('.');
//Remove CR, LF and '.' from buffer
data_rx = data_rx.substring(2, data_rx.length()-1);
//print(n+":");
//println(data_rx);
if(data_rx.equals("Data transfer finished")){
println(timestamp+"Data transfer finished.");
println(timestamp+"Generating visual.");
frameCapture = 0;
frameDisplay = 1;
n = 0;
//unlock textfields
txtfldSpeed.unlock();
txtfldDistance.unlock();
txtfldTs.unlock();
txtfldBron.unlock();
txtfldPattern.unlock();
txtfldFl.unlock();
txtfldN.unlock();
btnRun.unlock();
btnStop.unlock();
btnFrame.unlock();
}else if(data_rx.equals("Ready")){
println(timestamp+"Device is ready.");
println(timestamp+"---------------------");
//unlock textfields
btnRun.unlock();
btnStop.unlock();
btnFrame.unlock();
}else if(data_rx.equals("Initialized")){
println(timestamp+"Device is initialized.");
}else if(data_rx.equals("Measurement finished")){
println(timestamp+"Measurement completed.");
Stop();
}else if(data_rx.equals("Frame capture")){
println(timestamp+"Frame capture transfer started.");
frameCapture = 1;
}else if(data_rx.equals("Frame capture failed")){
println(timestamp+"Frame capture failed. Try again.");
println(timestamp+"---------------------");
//unlock textfields
txtfldSpeed.unlock();
txtfldDistance.unlock();
txtfldTs.unlock();
txtfldBron.unlock();
txtfldPattern.unlock();
txtfldFl.unlock();
txtfldN.unlock();
btnRun.unlock();
btnStop.unlock();
btnFrame.unlock();
}else if(data_rx.contains("SQUAL")){
print(timestamp+"SQUAL: ");
println(data_rx.substring(5,data_rx.length()));
}else if(data_rx.equals("Time constant error")){
print(timestamp+"TIME CONSTANT ERROR");
}else if(frameCapture == 1 && n < 900){
frame_capture_data[n] = int(data_rx);
n++;
}else if(run == 1){
//print(data_rx);
writer.print(data_rx);
}
}
}
public void Run() {
/* When RUN is pressed program starts to run */
//Read value to determine path
float speed = float(txtfldSpeed.getText());
float distance = float(txtfldDistance.getText());
int t_s = int(txtfldTs.getText());
int bron = int(txtfldBron.getText());
int fl = int(txtfldFl.getText());
String pattern = txtfldPattern.getText();
String date = day()+"-"+month();
int n = int(txtfldN.getText());
// Create CSV data file, showing the results from experiment
if (speed > 0 && distance > 0){
if (createWriter == 0){
//Creating objects for writing to file
path = "data/"+date+"/x="+distance+"/"+"x="+distance+"_v="+speed+
"_ts="+t_s+"_f="+fl+"_bron="+bron+"_pat="+pattern+"_n="+n+".csv";
writer = createWriter(path);
//Runtime variables
createWriter = 1;
run = 1;
ms_start = millis();
//Transmit t_s en t_run
arduino.write("dt"+txtfldTs.getText());
arduino.write(parseChar);
arduino.write("trun"+int(txtfldTrun.getText())*1000);
arduino.write(parseChar);
//Transmit starting char to arduino
arduino.write("Run");
arduino.write(parseChar);
//Header
//writer.println("t_ard_ms,t_ard_us,dx,dy,ls");
//lock textfields
txtfldSpeed.lock();
txtfldDistance.lock();
txtfldTs.lock();
txtfldBron.lock();
txtfldPattern.lock();
txtfldFl.lock();
txtfldN.lock();
btnRun.lock();
btnStop.lock();
btnFrame.lock();
println(timestamp+"PROGRAM INITIATED");
println(timestamp+"File stored at: "+path);
}
//ERROR messages
} else if (speed <= 0 && distance <= 0){
println(timestamp+"ERROR: INVALID SPEED AND DISTANCE");
} else if (speed <= 0){
println(timestamp+"ERROR: INVALID SPEED");
} else if (distance <= 0){
println(timestamp+"ERROR: INVALID DISTANCE ");
} else if(txtfldSpeed.getText().equals("")){
println(timestamp+"ERROR: Enter paramaters.");
}
}
public void Stop() {
/* When STOP is pressed program terminates and writes to file */
if (createWriter == 1){
//Write to file and close stream
writer.flush();
writer.close();
//Runtime variables
run = 0;
createWriter = 0;
//unlock textfields
txtfldSpeed.unlock();
txtfldDistance.unlock();
txtfldTs.unlock();
txtfldBron.unlock();
txtfldPattern.unlock();
txtfldFl.unlock();
txtfldN.unlock();
btnRun.unlock();
btnStop.unlock();
btnFrame.unlock();
txtfldN.setText(str(int(txtfldN.getText())+1));
if (int(txtfldN.getText()) > 5){
txtfldN.setText("1");
txtfldSpeed.clear();
}
println(timestamp+"Data written to file.");
println(timestamp+"---------------------");
}
}
public void Frame_Capture() {
arduino.write("Frame capture run");
arduino.write(parseChar);
//lock textfields
txtfldSpeed.lock();
txtfldDistance.lock();
txtfldTs.lock();
txtfldBron.lock();
txtfldPattern.lock();
txtfldFl.lock();
txtfldN.lock();
btnRun.lock();
btnStop.lock();
btnFrame.lock();
}
void display_frame(){
int[] frame1 = new int[225];
int[] frame2 = new int[255];
int x = 30;
int y = 320;
//resolutie 10x10
int s = 10; // size of pixel, i.e. side lengths
//Max res is 30x30
int sz = 10;
int res = 30;
for (int i = 0; i < 15; i++){
for (int m = 0; m < 15; m++){
frame1[15*i+m] = frame_capture_data[30*i+m];
frame2[15*i+m] = frame_capture_data[30*i+m+15];
}
}
//for (int i = 0; i < res*res; i++){
//Commented by Daan:
//for (int j = 0; j < res; j++){ // j resembles the column index.
// for (int k = 0; k < res; k++){ // k resembles the row index
// //fill(map(frame_capture_data[30*j+k],0,63,0,255));
// //frame_capture_data[30*j+k] = 300; // test to see how the pixel values can be manipulated
// fill(float(frame_capture_data[30*j+k]));
// rect(x+j*10, y+300-k*10, s, s);
// //println(frame_capture_data[30*j+k]);
// }
//}
for( int i = 0; i < 900; i++ )
{
fill( map(frame_capture_data[i], 0, 63, 0, 255) ); // Convert from ADNS greyscale to 0 - 255 grey scale format.
rect(x + (i / frameX * sz), // Each rect() is a rectangle that represents a pixel. I.e. width and height of each pixel is "sz".
y +300 - (i % frameY * sz),
sz, sz);
// //rect(off_x + (i % frameX * sz), // Each rect() is a rectangle that represents a pixel. I.e. width and height of each pixel is "sz".
// //off_y + (i / frameY * sz),
// //sz, sz);
}
fill(255,0,0);
rect(x+3*10, y+300-8*10, s, s); // this is red test dot, j = 3 (column), k = 8 (row).
// I.e. this is the 30*3 + 8 = 98 th pixel in frame stream from sensor.
}
public void time(){
/* Keeps track of time
Creates timestamp for messages*/
String h = str(hour());
String m = str(minute());
String s = str(second());
if (int(h) < 10){
h = "0"+h;
} else if(int(m) < 10){
m = "0"+m;
} else if(int(s) < 10){
s = "0"+s;
}
timestamp = "["+h+":"+m+":"+s+"] ";
}

ili9341 Not Working on STM32f4 discovery

I am testing IlI9341 3.2 TFT LCD on stm32F4-discovery. I wired based on Discovery datasheet. I also read ILI9341 datasheet and went through all registers.
However I get nothing. Also, the LD7, LD5 and LD6 keep on indicating overflow of current. Compiled using Coocox IDE.
The functions SETCURSORPOSITION and FILL are further down.
Here is my code if someone can help me. Thank you.
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_fsmc.h"
#include "LCD.h"
#define LCD_REG (*((volatile unsigned short *) 0x60000000))//address
#define LCD_RAM (*((volatile unsigned short *) 0x60020000))//data
#define MAX_X 320//landscape mode
#define MAX_Y 240//landscape mode
#define ILI9341_PIXEL 76800
#define Green 0x07E0
void LCD_PinsConfiguration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD,&GPIO_InitStructure);
GPIO_ResetBits(GPIOD,GPIO_Pin_7);
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource4,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource8,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource9,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource10,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource11,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_FSMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD,&GPIO_InitStructure);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource2,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource7,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource8,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource10,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource12,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource13,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource14,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource15,GPIO_AF_FSMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD,&GPIO_InitStructure);
Delay(5000);
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef FSMC_NORSRAMTimingInitStructure;
FSMC_NORSRAMTimingInitStructure.FSMC_AddressSetupTime = 0x0F;
FSMC_NORSRAMTimingInitStructure.FSMC_AddressHoldTime = 0;
FSMC_NORSRAMTimingInitStructure.FSMC_AddressSetupTime = 5;
FSMC_NORSRAMTimingInitStructure.FSMC_BusTurnAroundDuration =0;
FSMC_NORSRAMTimingInitStructure.FSMC_CLKDivision = 0;
FSMC_NORSRAMTimingInitStructure.FSMC_DataLatency =0;
FSMC_NORSRAMTimingInitStructure.FSMC_AccessMode = FSMC_AccessMode_A;
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1;
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM;
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &FSMC_NORSRAMTimingInitStructure;
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1,ENABLE);
}
void LCD_Initialization(void)
{
LCD_PinsConfiguration();
LCD_ILI9341_SendCommand(0x01);
Delay(50000);
LCD_ILI9341_SendCommand(0xcb);
LCD_ILI9341_SendData(0x39);
LCD_ILI9341_SendData(0x2C);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0x34);
LCD_ILI9341_SendData(0x02);
LCD_ILI9341_SendCommand(0xcf);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0xC1);
LCD_ILI9341_SendData(0x30);
LCD_ILI9341_SendCommand(0xe8);
LCD_ILI9341_SendData(0x85);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0x78);
LCD_ILI9341_SendCommand(0xea);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendCommand(0xed);
LCD_ILI9341_SendData(0x64);
LCD_ILI9341_SendData(0x03);
LCD_ILI9341_SendData(0x12);
LCD_ILI9341_SendData(0x81);
LCD_ILI9341_SendCommand(0xf7);
LCD_ILI9341_SendData(0x20);
LCD_ILI9341_SendCommand(0xc0);
LCD_ILI9341_SendData(0x23);
LCD_ILI9341_SendCommand(0xc1);
LCD_ILI9341_SendData(0x10);
LCD_ILI9341_SendCommand(0xc5);
LCD_ILI9341_SendData(0x3E);
LCD_ILI9341_SendData(0x28);
LCD_ILI9341_SendCommand(0xc7);
LCD_ILI9341_SendData(0x86);
LCD_ILI9341_SendCommand(0x36);
LCD_ILI9341_SendData(0x48);
LCD_ILI9341_SendCommand(0x3a);
LCD_ILI9341_SendData(0x55);
LCD_ILI9341_SendCommand(0xb1);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0x18);
LCD_ILI9341_SendCommand(0xb6);
LCD_ILI9341_SendData(0x08);
LCD_ILI9341_SendData(0x82);
LCD_ILI9341_SendData(0x27);
LCD_ILI9341_SendCommand(0xf2);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendCommand(0x2a);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0xEF);
LCD_ILI9341_SendCommand(0x2b);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0x01);
LCD_ILI9341_SendData(0x3F);
LCD_ILI9341_SendCommand(0x26);
LCD_ILI9341_SendData(0x01);
LCD_ILI9341_SendCommand(0xe0);
LCD_ILI9341_SendData(0x0F);
LCD_ILI9341_SendData(0x31);
LCD_ILI9341_SendData(0x2B);
LCD_ILI9341_SendData(0x0C);
LCD_ILI9341_SendData(0x0E);
LCD_ILI9341_SendData(0x08);
LCD_ILI9341_SendData(0x4E);
LCD_ILI9341_SendData(0xF1);
LCD_ILI9341_SendData(0x37);
LCD_ILI9341_SendData(0x07);
LCD_ILI9341_SendData(0x10);
LCD_ILI9341_SendData(0x03);
LCD_ILI9341_SendData(0x0E);
LCD_ILI9341_SendData(0x09);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendCommand(0xe1);
LCD_ILI9341_SendData(0x00);
LCD_ILI9341_SendData(0x0E);
LCD_ILI9341_SendData(0x14);
LCD_ILI9341_SendData(0x03);
LCD_ILI9341_SendData(0x11);
LCD_ILI9341_SendData(0x07);
LCD_ILI9341_SendData(0x31);
LCD_ILI9341_SendData(0xC1);
LCD_ILI9341_SendData(0x48);
LCD_ILI9341_SendData(0x08);
LCD_ILI9341_SendData(0x0F);
LCD_ILI9341_SendData(0x0C);
LCD_ILI9341_SendData(0x31);
LCD_ILI9341_SendData(0x36);
LCD_ILI9341_SendData(0x0F);
LCD_ILI9341_SendCommand(0x11);
Delay(50000);
LCD_ILI9341_SendCommand(0x29);
LCD_ILI9341_SendCommand(0x22);
}
void LCD_ILI9341_SendCommand(uint16_t index)
{
LCD_REG = index;
}
void LCD_ILI9341_SendData(uint16_t data)
{
LCD_RAM = data;
}
void LCD_ILI9341_SetCursorPosition(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
LCD_ILI9341_SendCommand(0x2A);
LCD_ILI9341_SendData(x1 >> 8);
LCD_ILI9341_SendData(x1 & 0xFF);
LCD_ILI9341_SendData(x2 >> 8);
LCD_ILI9341_SendData(x2 & 0xFF);
LCD_ILI9341_SendCommand(0x2B);
LCD_ILI9341_SendData(y1 >> 8);
LCD_ILI9341_SendData(y1 & 0xFF);
LCD_ILI9341_SendData(y2 >> 8);
LCD_ILI9341_SendData(y2 & 0xFF);
}
void LCD_ILI9341_Fill(uint16_t color) {
unsigned int n, i, j;
i = color >> 8;
j = color & 0xFF;
LCD_ILI9341_SetCursorPosition(0, 0, MAX_Y - 1, MAX_X - 1);
LCD_ILI9341_SendCommand(0x0022);
for (n = 0; n < ILI9341_PIXEL; n++) {
LCD_ILI9341_SendData(i);
LCD_ILI9341_SendData(j);
}
}
void Delay(__IO uint32_t nCount)
{
while(nCount--)
{
}
}
I am going to answer my own question to make it clear things got solved. But I want to thank the community.
Actually I did few things: I removed GPIOE 2 from configuration block, because it was not being used. I replaced GPIOD to GPIOE in the same block. Inside "LCD_ILI9341_Fill" I changed "LCD_ILI9341_SendCommand(0x0022)" to "LCD_ILI9341_SendCommand(0x002C)". 0x002C is the actual Memory Write address to where you write the data on ili9341. I also connected the LCD RESET pin to the stm32f4 NRST pin. 3V power was connected to LCD LED_A.
Now everything works, I still get wrong colors but I need to make few changes on registers, such as register 36h.
There is a typo there, you're not configuring GPIOE at all.
change the last GPIO_Init() call to
GPIO_Init(GPIOE,&GPIO_InitStructure);
instead of configuring the wrong pins of GPIOD again.
I wired based on Discovery datasheet.
Do you mean the extension board datasheet? Because the Discovery datasheet says nothing about LCD controllers.
LD7, LD5 and LD6 keep on indicating overflow of current
Are you sure? The overcurrent indicator is LD8 (red). You should expect some random lighting up or flickering of LD5, LD6, and LD8, because they are connected to the LCD data lines, but not on LD7.

STM32F4 DMA doesn't control ADC channels

I'm trying to set up my STM32F407-Discovery board to read multiple ADC channels from ADC1 using the DMA controller. I can easily read the analog value one at a time without using DMA, but as soon as I enable DMA for the ADC, ADC1->DR is always 0, and adc_vals is filled with zeros. Furthermore, it hangs on while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));.
EDIT: it would appear DMA_GetCmdStatus is returning DISABLED. Any ideas?
Is there a way to start the ADC or something that I'm missing?
//setup adc1: in1,2,3,8,9,15
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //adc1 on the apb2 peripheral bus
ADC_InitTypeDef adc;
ADC_DeInit(); //set adc to default state
adc.ADC_DataAlign = ADC_DataAlign_Right;
adc.ADC_Resolution = ADC_Resolution_12b;//12 bit = 4096
adc.ADC_ContinuousConvMode = ENABLE;
adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_NbrOfConversion = NUM_ADC;
adc.ADC_ScanConvMode = ENABLE;
ADC_Init(ADC1,&adc);
ADC_DMACmd(ADC1, ENABLE); //enable adc for dma. When this line is removed, I see data on ADC1->DR
ADC_Cmd(ADC1,ENABLE);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_144Cycles);//1:1710, 0
//ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_144Cycles);//2:1710, 0
//ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_144Cycles);//3:1710, 0
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,4,ADC_SampleTime_144Cycles);//8:3520
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,5,ADC_SampleTime_144Cycles);//9:1000
//ADC_RegularChannelConfig(ADC1,ADC_Channel_15,6,ADC_SampleTime_144Cycles);//15:3920
//DMA for multiple adc channels:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //dma1 clock enable
DMA_InitTypeDef dma;
DMA_DeInit(DMA2_Stream0); //reset DMA2 stream 0 to default values
dma.DMA_Channel = DMA_Channel_0;
dma.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
dma.DMA_Memory0BaseAddr = (uint32_t)&adc_vals[0];
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = NUM_ADC;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &dma);
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE); //Enable DMA Stream Half / Transfer Complete interrupt
DMA_Cmd(DMA2_Stream0, ENABLE); //DMA2_Stream0 enable
//dma transfer complete interrupt:
NVIC_InitTypeDef nvic;
//Enable DMA1 channel IRQ Channel
nvic.NVIC_IRQChannel = DMA2_Stream0_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority = 0;
nvic.NVIC_IRQChannelSubPriority = 0;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
ADC_SoftwareStartConv(ADC1);//Start the adc conversion
At least you can try:
change DMA_PeripheralInc to enable
use ADC_DMARequestAfterLastTransferCmd(ADC, Enable); for dma request after group conversion.
init ADC_CommonInitTypeDef
init GPIO, if not
Moreover enabling ADC before all the configurations is strange.
In my opinion the best way is to copy-paste "ADC_DualModeRegulSimu"example from standard peripherals library. It contains beautiful code exactly for your purpose.
There were a number of errors. Here's my working code for anybody else having the same trouble:
//DMA for multiple adc channels:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //ADC1 on APB2 peripheral bus
DMA_InitTypeDef dma; //dma2/stream0/channel0
dma.DMA_Channel = DMA_Channel_0;
dma.DMA_Memory0BaseAddr = (uint32_t)&adcVal;
dma.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = 6;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Enable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &dma);
DMA_Cmd(DMA2_Stream0, ENABLE); //dMA2_Stream0 enable
//analog inputs: PA1,2,3, PC5, PB0,1
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_AN;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio);
gpio.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOC, &gpio);
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &gpio);
//ADC common init
ADC_CommonInitTypeDef adcCommon;
adcCommon.ADC_Mode = ADC_Mode_Independent;
adcCommon.ADC_Prescaler = ADC_Prescaler_Div2;
adcCommon.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
adcCommon.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&adcCommon);
//setup adc1: in1,2,3,8,9,15
ADC_InitTypeDef adc;
ADC_DeInit(); //set adc to default state
adc.ADC_DataAlign = ADC_DataAlign_Right; //mask 0b 00001111 11111111
adc.ADC_Resolution = ADC_Resolution_12b;//12 bit = 4096
adc.ADC_ContinuousConvMode = ENABLE; //continuous: constantly converting data - can always read register
adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;//external trigger conversion (?)
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_NbrOfConversion = 6;
adc.ADC_ScanConvMode = ENABLE;//single/multichannel
ADC_Init(ADC1,&adc);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,4,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,5,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_15,6,ADC_SampleTime_56Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); //single adc repeated
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1,ENABLE);
Thanks for the code ethan, made minor mod to fit my case and to work as a general function.
volatile uint16_t adcVal[6];
void Setup_DMA_ADC( void )
{
GPIO_InitTypeDef gpio;
//DMA for multiple adc channels:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //ADC1 on APB2 peripheral bus
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
DMA_InitTypeDef dma; //dma2/stream0/channel0
dma.DMA_Channel = DMA_Channel_0;
dma.DMA_Memory0BaseAddr = (uint32_t) &adcVal[0];
dma.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = 6;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Enable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &dma);
DMA_Cmd(DMA2_Stream0, ENABLE); //dMA2_Stream0 enable
//analog inputs: PA1,2,3, PC5, PB0,1
GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_AN;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio);
gpio.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOC, &gpio);
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &gpio);
//ADC common init
ADC_CommonInitTypeDef adcCommon;
adcCommon.ADC_Mode = ADC_Mode_Independent;
adcCommon.ADC_Prescaler = ADC_Prescaler_Div2;
adcCommon.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
adcCommon.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&adcCommon);
//setup adc1: in1,2,3,8,9,15
ADC_InitTypeDef adc;
ADC_DeInit(); //set adc to default state
adc.ADC_DataAlign = ADC_DataAlign_Right; //mask 0b 00001111 11111111
adc.ADC_Resolution = ADC_Resolution_12b;//12 bit = 4096
adc.ADC_ContinuousConvMode = ENABLE; //continuous: constantly converting data - can always read register
adc.ADC_ExternalTrigConv = DISABLE;//ADC_ExternalTrigConv_T1_CC1;//external trigger conversion (?)
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_NbrOfConversion = 6;
adc.ADC_ScanConvMode = ENABLE;//single/multichannel
ADC_Init(ADC1,&adc);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,4,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,5,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_15,6,ADC_SampleTime_56Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); //single adc repeated
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1,ENABLE);
// Start ADC conversion
ADC_SoftwareStartConv(ADC1);
return;
}

Why does XBee transmit fail sometimes?

I doing a project with Arduino Uno R3 and XBee S2 transmission. I use a couple of sensors like a wireless (RF) temperature sensor, two SHT75 sensors, a 3-axis accelerometer and an illumination sensor. And after collecting the data, we use XBee (S2, API mode) to send the data to the gateway. Every round is about one second.
The first problem is the data is about 16 bytes, but the packet does not send successful every round. Sometime it works, and sometimes it doesn't, but the payload of XBee can be 60 or 70 bytes in the datasheet... But if I put the payload as some simply an integer (like 1, 2, 3), not the data from sensor, and the transmission will be stable.
After meeting the problem above, I divided the data into two packets (each with an eight bytes payload), and the first packet is very stable, but the second is very unstable. As mentioned above, if I put some number into the second packets instead of the sensing data the second packet will become stable and send successfully every round.
So I think it's the code problem, but idk where is the problem. I try to change the baud rate or increasing the delay time between the two packets. Where is the problem? The following is my code:
#include <XBee.h>
#include <i2cmaster.h>
#include <string.h>
#include <ctype.h>
#include <Sensirion.h>
#include "Wire.h"
#include "MMA845XQ.h"
**///////////////////////////// XBee setup //////////////////////////////////**
XBee xbee = XBee();
XBeeAddress64 remoteAddress = XBeeAddress64(0x00000000, 0x00000000);
ZBRxResponse zbRx = ZBRxResponse();
ZBTxStatusResponse zbTxStus = ZBTxStatusResponse();
uint8_t payload[] = {0,0,0,0,0,0,0,0,0};
uint8_t payload1[] = {0,0,0,0,0,0,0,0,0};
**///////////////////////////// Accelerometer //////////////////////////////////**
MMA845XQ accel;
**////////////////////////// SHT1 serial data and clock ////////////////////**
const byte dataPin = 2;
const byte sclkPin = 3;
Sensirion sht = Sensirion(dataPin, sclkPin);
unsigned int rawData;
float temperature;
float humidity;
byte stat;
**////////////////////////// SHT2 serial data and clock ////////////////////**
const byte dataPin1 = 4;
const byte sclkPin1 = 5;
Sensirion sht1 = Sensirion(dataPin1, sclkPin1);
unsigned int rawData1;
float temperature1;
float humidity1;
byte stat1;
**//////////////////////////// Illumination sensor ////////////////////////**
int sensorPin = A0; // Select the input pin for the potentiometer
int sensorValue = 0; // Variable to store the value coming from the sensor
long int pardata, pardata_low, pardata_hi, real_pardata;
uint16_t illumindata = 0;
void setup () {
i2c_init(); //Initialise the I²C bus
PORTC = (1 << PORTC4) | (1 << PORTC5); //Enable pullups
Wire.begin();
accel.begin(false, 2);
Serial.begin(115200);
xbee.begin(Serial);
}
void loop () {
payload[0] = 10;
payload1[0] = 11;
**/////////////////////RF temperature sensor/////////////////////////////**
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start_wait(dev + I2C_WRITE);
i2c_write(0x07);
i2c_rep_start(dev + I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData = 0x0000; // Zero out the data
int frac; // Data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
float celcius = tempData - 273.15;
float fahrenheit = (celcius*1.8) + 32;
celcius *= 100;
int a = int(celcius) + 1;
payload[1] = a >> 8 & 0xff;
payload[2] = a & 0xff;
**//////////////////////////// Illumination sensor ////////////////////////////////**
sensorValue = analogRead(sensorPin);
TSR(sensorValue);
payload[3] = pardata_low >> 8 & 0xff;
payload[4] = pardata_low & 0xff;
**//////////////////////////// 3-axis accelemeter sensor ////////////////////////////////**
accel.update();
payload[5] = accel.getX()*10;
payload[6] = accel.getY()*10;
payload[7] = accel.getZ()*10;
delay(100);
**////////////////////////////// XBee send first packet///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
ZBTxRequest zbTx = ZBTxRequest(remoteAddress, payload, sizeof(payload));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
**//////////////// SHT 1x temperature and humidity sensor /////////////////////////**
sht.readSR(&stat); // Read sensor status register
sht.writeSR(LOW_RES); // Set sensor to low resolution
sht.readSR(&stat); // Read sensor status register again
sht.measTemp(&rawData); // sht.meas(TEMP, &rawData, BLOCK)
sht.meas(TEMP, &rawData, NONBLOCK);
temperature = sht.calcTemp(rawData);
sht.measHumi(&rawData); // sht.meas(HUMI, &rawData, BLOCK)
humidity = sht.calcHumi(rawData, temperature);
sht.meas(HUMI, &rawData, NONBLOCK);
humidity = sht.calcHumi(rawData, temperature);
temperature *= 100;
a = int(temperature) + 1;
payload1[1] = a >> 8 & 0xff;
payload1[2] = a & 0xff;
humidity *= 100;
a = int(humidity) + 1;
payload1[3] = a >> 8 & 0xff;
payload1[4] = a & 0xff;
delay(10);
sht1.readSR(&stat1);
sht1.writeSR(LOW_RES); // Set sensor to low resolution
sht1.readSR(&stat1);
sht1.measTemp(&rawData1); // sht.meas(TEMP, &rawData, BLOCK)
temperature1 = sht1.calcTemp(rawData1);
sht1.measHumi(&rawData1); // sht.meas(HUMI, &rawData, BLOCK)
humidity1 = sht1.calcHumi(rawData1, temperature1);
delay(10);
temperature1 *= 100;
a = int(temperature1) + 1;
payload1[5] = a >> 8 & 0xff;
payload1[6] = a & 0xff;
humidity1 *= 100;
a = int(humidity1) + 1;
payload1[7] = a >> 8 & 0xff;
payload1[8] = a & 0xff;
**////////////////////////////// XBee send second packet ///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
zbTx = ZBTxRequest(remoteAddress,payload1, sizeof(payload1));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
}
void TSR(int sensorValue)
{
illumindata = (sensorValue * 4 * 5) / 1.5;
pardata = 6250/6144*illumindata*10;
if(pardata > 0)
{
if(pardata < 11500)
{
real_pardata = 0.0000000020561*pardata*pardata*pardata -
0.00002255*pardata*pardata +
0.25788*pardata -
6.481;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
else
{
real_pardata = 0.0000049204*pardata*pardata*pardata -
0.17114*pardata*pardata +
1978.7*pardata -
7596900;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
}
else
{
pardata_hi = 0;
pardata_low = 0;
}
}
as I am writing this I have solved the same problem you have, though with similar hardware setup. I have used bare avr atxmega128a3u (so no arduino board) and an Xbee S1 communicating on baud rate 115200. After a few days trying to figure this out I came to conclusion, that if your avr is not running at precise clock (external xtal) and you use slightly "faster" baud rate ( >= 115200 ) Xbee's serial hardware has probably trouble recovering clock signal resulting in errors in transmission. (Maybe Xbee has slow bit sampling rate).
Anyway, by ensuring your microprocessor is running at stable clock (you should be safe here 'cause arduino has an external xtal) and by using slower baud rate (try 57600, 19200 or 9600) should solve your problem. I hope so. :) ...And don't forget to reconfigure Xbee's baud rate in XCTU.
And also it might help if you initliaze xbee only once.Move these lines into setup() function:
setup(){
// This is changed
Serial.begin(9600);
// This is new
xbee = XBee();
xbee.begin(Serial);
// ...
}
EDIT: Also you might be interested in this website where you can see what is the % of error for given clock frequency and baud rate (as well as direct register values to set if you were using bare avr) http://www.wormfood.net/avrbaudcalc.php?postbitrate=9600&postclock=16&hidetables=1

Resources