4

I am new to the Arduino world and I hope I can find a solution here. The code below functionally works ok. The problem I have is, at line 45 I've inserted an if statement to change dac_value. It is very slow while serial and all that is outside if works fast/fine... What would be a solution to make it fast? Tried if - else if and also while... result is the same. Hope someone can help. Thank you.

{    
#include <Arduino.h>
#include <Wire.h>
// #include <LiquidCrystal_I2C.h>
#define MCP4725 0x61
#define MCP4725B 0x60
unsigned int val;
byte buffer[3];
byte buff[3];

int ClockPinV = PB1; int ClockPinA = PA6; const int currsensPin = PA3; const int voltsensPin = PA2;

void setup() { Serial.begin(115200); pinMode(currsensPin , INPUT_ANALOG); pinMode(voltsensPin , INPUT_ANALOG); pinMode(ClockPinV , INPUT); pinMode(ClockPinA , INPUT); Wire.begin(); }

int val0 = 1024; int val1 = 4096; volatile int dac_value = 0;

void loop() { analogReadResolution(12);

volatile int svolt = analogRead(ClockPinV); volatile int scurr = analogRead(ClockPinA); volatile int set_voltage = (3.3/4096)svolt; volatile int set_curr = (3.3/4096)scurr; volatile int securr = analogRead(currsensPin); volatile int real_curr = (3.3/4096)securr; volatile int sevolt= analogRead(voltsensPin); volatile int real_output2 = (3.3/4096)sevolt;

if(real_curr < set_curr){ if(set_voltage > real_output2) { dac_value = dac_value + 1; } if(set_voltage < real_output2) { dac_value = dac_value - 1; }
} else if(real_curr > set_curr) { dac_value --;
}

dac_value = constrain(dac_value, 0, 2673); buffer[0] = 0b01000000; //control byte buffer[1] = dac_value >> 4; //MSB 11-4 shift right 4 places buffer[2] = dac_value << 4; //LSB 3-0 shift left 4 places

Wire.beginTransmission(MCP4725); //address device Wire.write(buffer[0]); //pointer Wire.write(buffer[1]); //8 MSB Wire.write(buffer[2]); //4 LSB Wire.endTransmission();

// val1 = constrain(val1, 0, 2673); buff[0] = 0b01000000; //control byte buff[1] = svolt >> 4; //MSB 11-4 shift right 4 places buff[2] = svolt << 4; //LSB 3-0 shift left 4 places

Wire.beginTransmission(MCP4725B); //address device Wire.write(buff[0]); //pointer Wire.write(buff[1]); //8 MSB Wire.write(buff[2]); //4 LSB Wire.endTransmission();

Serial.println("============================="); Serial.println("============================="); Serial.println("========= Volt Test ========="); Serial.println("test: " + String(set_voltage)); Serial.println(" " + String(real_output2)); Serial.println("======== Current Test ======="); Serial.println("test: " + String(set_curr)); Serial.println(" " + String(real_curr)); Serial.println("============================="); Serial.println("============================="); } }

chicks
  • 223
  • 4
  • 10
Marius
  • 41
  • 2
  • 1
    How do you see, that its the if statements, which is slow? Are you sure, that your problem doesn't lie at another place? And what means "slow" in this case? – chrisl Sep 17 '20 at 07:59
  • I asume that... tride a pot connected to a analog pin and output directly to dac - it was working fast... – Marius Sep 17 '20 at 08:14
  • Why are you using volatile everywhere? What do you mean by "slow" and "fast"? How have you measured that? – Nick Gammon Sep 17 '20 at 08:23
  • "if" isn't slow, just for your info. The things you do inside the "if" will be affecting what the rest of the code is doing. For example, if you say "if it is Monday, sleep for 4 hours" then the "if" isn't the problem, it is "sleep for 4 hours" that is. – Nick Gammon Sep 17 '20 at 08:28
  • It's not the if statement itself that makes your code slow. But it may well be the sketch behaving differently than you expect which makes you believe it was slow. Compare and print timestamps to determine how long the execution of certain parts takes. – Sim Son Sep 17 '20 at 08:32
  • if I read a pot on a analog pin and write to dac in serial print i can see it changing the dac value as i spin the pot. In the same time if the conditions in the if are met and i increase the voltage i can see dac_value incrementing very slow. it takes seconds until it reaches the set value... – Marius Sep 17 '20 at 08:34
  • 1
    as I said... new here so pleas don't jump at me. I agree that my problem could be something else - that is why i posted. hopefully to find a solution and to learn something new :P – Marius Sep 17 '20 at 08:38
  • No-one is attacking you. We are just curious as to some things about your code. If you can explain, we can better advise you. – Nick Gammon Sep 17 '20 at 08:41
  • if the conditions in the if are met and i increase the voltage i can see dac_value incrementing very slow. - you mean, the serial prints are slower? – Nick Gammon Sep 17 '20 at 08:43
  • 1
    yes, but just the dac reading dac_value. If I print anything else + dac_value everything updates fast except the dac_value... – Marius Sep 17 '20 at 08:47
  • I didn't understand that. – Nick Gammon Sep 17 '20 at 08:51
  • 2
    From your code it seems, that you are trying to do a control loop (outputting a control signal via DAC, reading correlated values back and change the control signal based on that. The behavior of such control loops are not always obvious. I'm rather sure this is one of these cases. So please describe, how everything is connected, what you are trying to control and what exactly you expect to happen. A schematic or wiring diagram (and maybe a good image of your real circuit) would also help here – chrisl Sep 17 '20 at 09:00
  • 1
    try if (real_curr <= set_curr){ – Juraj Sep 17 '20 at 09:19
  • int ClockPinV = PB1; int ClockPinA = PA6; is nonsense, BTW. pinMode and analogRead do work with Arduino pin numbers. – DataFiddler Sep 17 '20 at 10:36
  • 1
    @DataFiddler: made it with rotary enc first. Removed and now using pot but did not change pin name... also board is stm32f103 – Marius Sep 17 '20 at 10:42
  • 1
    added full main.cpp to github. https://github.com/mariusdp/psu_test.git – Marius Sep 17 '20 at 10:44

1 Answers1

4

The if statements (plural) you posted on GitHub are a lot different to the one you posted above. They contain a lot of of print commands to the LCD, so I think this is what is slowing your code down. It's a fair effort at nicely formatting the output on the display, but is rather convoluted.

Here is a simplified version which writes to the LCD as little as possible (2 cursor moves and 2 prints). The formatting of the string is done in Arduino memory before sending it out to the LCD as one complete string.

I couldn't understand your variable names, so I've renamed them.

setup()

I moved the analogReadResolution(12) from loop() to setup() for a slight performance gain.

void setup()
{
  pinMode(currsensPin , INPUT_ANALOG);
  pinMode(voltsensPin , INPUT_ANALOG);
  pinMode(voltPin, INPUT_ANALOG);
  pinMode(currPin, INPUT_ANALOG);
  Wire.begin();
  lcd0.begin(20, 4);
  lcd0.backlight();

analogReadResolution(12); // Moved from loop(). Only need to call it once.

Serial.begin(115200); }

loop()

I've grouped the analogue reads together to give a smaller sampling window. Since it's for a control loop, these values should ideally be sampled at exactly the same time and synchronised to a clock (e.g. in hardware).

float real_current_offset = 0;

void loop() { // // Obtain data samples as close together as possible with no interrupts. // cli(); // Disable interrupts. int svolt = analogRead(voltPin); int scurr = analogRead(currPin); int raw_voltage = analogRead(voltsensPin); int raw_current = analogRead(currsensPin); sei(); // Enable interrupts.

// Calculate set voltage and current. float set_voltage = (3.3 / 4096) * svolt; float set_current = (3.3 / 4096) * scurr;

// Calculate real voltage and current. float real_voltage = (3.3 / 4096) * raw_voltage; float real_current = raw_current * (3.3 / 4096) - real_current_offset; float real_current_ma = real_current * 1000.0;

int dac_value = dac_value + (real_current <= set_current) * (set_voltage > real_voltage) - (real_current < set_current) * (set_voltage < real_voltage) - (real_current > set_current);

buffer[0] = 0b01000000; buffer[1] = dac_value >> 4; buffer[2] = dac_value << 4; Wire.beginTransmission(MCP4725); Wire.write(buffer[0]); Wire.write(buffer[1]); Wire.write(buffer[2]); Wire.endTransmission();

DisplayDataOnLcd(set_voltage, set_current, real_voltage, real_current); }

DisplayDataOnLcd()

I created a new function for displaying the data on the LCD. It's good practice to break the code down into smaller functional blocks.

void DisplayDataOnLcd(const int set_voltage, const int set_current, const int real_voltage, const int real_current)
{
  Serial.println("\nLCD Data Display");

// Define the formats for printing to the LCD. const char data_format_set = "Set : %s V %s mA"; const char data_format_real = "Real: %s V %s mA"; char voltage_str[10]; char current_str[10]; char data_str[30];

// Format the set voltage and current, and display on the LCD. dtostrf(set_voltage, 6, 3, voltage_str); dtostrf(set_current, 6, 3, current_str); sprintf(data_str, data_format_set, voltage_str, current_str); lcd0.setCursor(0, 0); lcd0.println(data_str); Serial.println(data_str);

// Format the real voltage and current, and display on the LCD. dtostrf(real_voltage, 6, 3, voltage_str); dtostrf(real_current, 6, 3, current_str); sprintf(data_str, data_format_real, voltage_str, current_str); lcd0.setCursor(0, 1); lcd0.println(data_str); Serial.println(data_str); }

tim
  • 699
  • 6
  • 15
  • Thank you. Will try later today. Q: I do not know lot of things so be patient with me please. On the LCD the only value that updates slow is the reading from dac (dac_value), all else updates fast... That is why I assumed I am doing something wrong... . The test I made was - pot on a analog input and the reading sent over i2c to dac converter - output from converter to another adc pin as feedback and feedback to LCD trough i2c ==> this setup was updating in real time (or fast enough to perceive as real time and be able to work with it)... – Marius Sep 18 '20 at 13:18
  • 1
    I'm struggling to understand your control loop. Could you post a full schematic of it please? Edit your original post to add an image. I can't see how writing 3 bytes to the MCP4725 DAC at the standard 100 kbps is drastically slowing down the loop. Try adding debug statements to the loop to Serial.println() the time of each iteration. – tim Sep 18 '20 at 14:31
  • DAC connected to analog pin controlled by pot or enc and "if" conditionals... the DAC controls a mosfet driver IC. Divider for voltage monitor (real_voltage) and made low side current sensor from LM358 and shunt for "real_current". The way has to work is if set_volt < real_volt the DAC output should get lower... it does that but is to slow. In a short would smoke (output is up to 100VDC 20Amp LINEAR) Before u ask - linear is less noisy and a lot cheaper to build than buy + using trafo I see it silly to make it switch mode. :P THANK YOU! – Marius Sep 25 '20 at 06:44
  • Nice answer guy, I think your assumption was right. Every I2C liquid crystal display I have used with arduino are dreadfully slow for w.e reason. +1 – Tim_Stewart Oct 04 '20 at 00:00