Week 6: embedded programming

Assignment

Individual assignment: Write a program for a microcontroller development board that you made, to interact (with local input &/or output devices) and communicate (with remote wired or wireless devices)

Group assignment: Browse through the data sheet for your microcontroller compare the performance and development workflows for other architectures. It can be found on our fablab web page.

Write a program

For my final project, I need to do vacuum inside a membrane to change the stiffness of my pneumatic actuator. To do so, I will use a air pump, and write a code for it this week. It should be an easy program, as the goal is just to switch on the pump by pressing a push button and to switch it off with the same button. I started with the blink code example, and i modified it to do what I want.

I just started with the program here, to switch on the pump during 10 seconds and and switch it off. I tested the code with the led, instead of the pump, but I will try the pump during the week 9 - ouput devices.

const int VACUUM_PIN = 26;  (28 for the vacuum / 26 LED)
void setup () 
{   
  pinMode(VACUUM_PIN, OUTPUT); 
} 

void loop () 
{   
  digitalWrite(VACUUM_PIN, HIGH);   
  delay (10000);  
  digitalWrite(VACUUM_PIN, LOW);   
  delay (10000);  
} 

I had some troubles when trying my code:

Board not recongnized Sometimes the board is not recongnized by my computer, so I got an error message when I try to load the program on it: if I unplug and then plug back in with the BOOTSEL button held down, the board is recognized and it works well.

Issue with soldering I first had an issue because of one of my soldering that was not well done (cold joint), which causes that there was not enough current to switch on the led. That’s also why during my week 4, I had a very low intensity on my led when blinking. I realised it by connecting a LED directly on the pin of my microcontroller, in that case the LED was very bright.

After trying this basic code, I modified it to start pumping only when I press the button, and to stop pumping when the button is pressed again. I removed the delay because in my final project, it won’t be needed. The button is thus defined as an input in my code and the pump as an output, and this is specified in the “void setup” function of my code, which is the part where the initialization of components takes place. The void loop() function is used for managing real-time tasks, monitoring sensors, communicating with other devices or other things that the microcontroller should perform continuously. I have thus used this function to read the status of my push button, and to change the state of the pump accordingly.

const int BUTTON_PIN = 27;     // the number of the pushbutton pin
const int VACUUM_PIN =  26;    // the number of the pump pin (28 for the vacuum / 26 LED)

int buttonState = 0;         // variable for reading the pushbutton status
bool lastButtonState = LOW;
bool pumpState = LOW;

void setup() {
  pinMode(VACUUM_PIN, OUTPUT);    // pump is defined as output
  pinMode(BUTTON_PIN, INPUT);    // pushbutton is defined as input
}

void loop() {
  // read button status
  int reading = digitalRead(BUTTON_PIN);

  // check if button status changed
  if (reading != lastButtonState) {
    if (reading == HIGH) {
      //change pump state
      pumpState = !pumpState;
      digitalWrite(VACUUM_PIN, pumpState); 
    }
  }

  lastButtonState = reading;
}

I also wanted to add some basic communication between my microcontroller and my computer. The microcontroller will send a message when the pump is on. To do that, I need to initialize the serial communication in the “void setup” function with the following line: Serial.begin(9600); and then I can use Serial.print("pump state is "); Serial.println(pumpState ? "open" : "off");.

My code can be downloaded here.

Use my board as a programmer

I will continue what I wanted to do in week 4, i.e. use my board as a programmer. I had an issue with the version of pymcuprog, but I found the solution on the Quentorres gitlab:

  • open terminal
  • pip install pymcuprog -> now the good version of pymcoprog is installed.

-> The error is solved, I can use my board as a programmer! I just used it to make the led of the second board blink, with the code above. The pin number specified should be the one of the LED on the UPDI target.

programmersolved

Code to send analog control signal to a pressure regulator

For my final project, I will use industrial pressure regulator from Festo (VPPE model), that I will test during week 9 as an output device. However, I already wanted to check how to send this analog commands, as I will be using a DAC (digital to analog converter) linked to an Arduino to send the commands.

The DAC that I chose is a AD5724 from Analogue Devices. I chose it based on the requirements of my pressure regulator: the analog signal must be betwwen 0 to 10V and I will control 3 devices independently. In addition, this DAC is compatible with SPI (serial peripheral interface), which is a typical way to interface microcontroller with a digital-to-analog converters.

SPI communication

SPI stands for Serial Peripheral Interface. It’s a communication protocol used to transfer data between microcontrollers, sensors, and other peripheral devices:

  • Serial: SPI sends data one bit at a time, sequentially, over multiple wires (typically four or more).
  • Peripheral interface: It’s designed for communication between a microcontroller (usually referred to as the “master” or “controller”) and peripheral devices (often called “slaves” or “peripherals”) -> in this case, the microcontroller (master) will interact with the DAC (slave) for the control of prssure regulators.
  • Clock and Data Lines: SPI uses at least four wires:

    • SCLK (Serial Clock): This line carries a clock signal generated by the master, which synchronizes the data transfer.
    • MOSI/COPI (Master Out Slave In): This line carries data from the master to the slave.
    • MISO/CIPO (Master In Slave Out): This line carries data from the slave to the master -> here I won’t use this line most of the time because I just want to send command to the pressure regulators, but I will connect it anyway if at some point I want to receive informations from the regulators as well.
    • SS/CS (Slave Select/Chip Select): This line is used to select which slave device the master wants to communicate with.

You can refer to this documentation for more details on SPI communication.

I have found on internet a library developped during a project that allows to make the SPI communication between the microcontroller and the DAC easier, as the function needed have already been coded. I will just need to understand it and use it if everything goes well. -> source. On the github project, the header file, the cpp file and an example of how to use the library are available.

- Header file: it’s the file that contains the functions definitions, variables and macros that will be shared among multiple source files. It serves as an interface to various functions and date structures usable by other parts of the program. It specifies the available features/operations to the rest of the program but without the implementation details.

- Cpp file: it’s the file where the implementation details are coded, the functions are specified here. It will include the header file at the beginning of the code. In this library, there is multiple functions, one important is the “ConfigDACs” function, that will specify the number of outputs that i will be using, as well asthe range of the output values that I will be using (0 to 10V). “SetDAC” is also very important, as it’s the one that will be used to send the command my pressure regulators.

For the SPI communication, special pins of the Arduino UNO must be used and are specified on the picture below. The SS (slave select) pin will be used in the code, during the configuration of the DAC (ConfigDACs). It’s this pin that will activate the communication with the DAC.

pinoutarduino

The example file can be can be downloaded here , as well as the library. I modified the example code for my purpose, as I first want to have a correspondance between the command voltage send to the pressure regulator and the output pressure. To do so, I wrote the simple code below, that start from a voltage of 0.0V and that increment it up to 5.0V. Each time the voltage is incremented, I send a command to the DAC to change the pressure. I will use that to have a mapping between the voltage command and the output pressure, in order to know what command I want to send to my pneumatic actuator. I used a delay of 5 seconds so the pressure doesn’t change to fast.

void loop() {
  float voltage= 0.0; 

  for (float i = 0.0; i<5.0 ; i+= 0.2) {
    voltage += 0.2;
    Serial.println(voltage);
    DAC.SetDAC(voltage,1,0); //SetDAC(voltage,DACOutput,ChipNumber=0)
    delay(5000);

  }
}

My code will be tested with the pressure regulator in week 9, and can be downloaded here , but note that this code has not been tested during this week 6. It was just a first attemp to code it and to try it during week 9.

Update week 8 & 9

During regional meeting of week 6, I realised that using an Arduino board for my final project was not the prefered option. I thus switched for a Raspberry Pi Pico W board that was available at my fablab and which also allowed the SPI communcation.

During week 8 I developped the PCB with the Raspberry Pi Pico W board and I tested it during week 9 with the code just above.

Update week 14

As suggest by my instructor Nicolas, I add some debounce in the code where I used a button here above. Indeed, Pushbuttons often generate unwanted open/close transitions when actuated, due to mechanical and physical problems: these transitions can be interpreted as multiple presses in a very short space of time, misleading the program. To avoid false readings from the pushbutton due to mechanical bouncing, some debouncing using the function “millis()” can be used in the program, as explained here. I followed what was suggested, and the new code with debounce can be downloaded here .

const int BUTTON_PIN = 27;     // the number of the pushbutton pin
const int VACUUM_PIN =  26;      // the number of the pump pin (28 for pump, 26 for LED)

int buttonState = 0;         // variable for reading the pushbutton status
bool lastButtonState = LOW;
bool pumpState = LOW;

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(VACUUM_PIN, OUTPUT);      // pump is defined as output
  pinMode(BUTTON_PIN, INPUT);    // pushbutton is defined as input
  Serial.begin(9600);
}

void loop() {
  // read button status
  int reading = digitalRead(BUTTON_PIN);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce delay,
    // so take it as the actual current state.

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the pump if the new button state is HIGH (pressed)
      if (buttonState == HIGH) {
        pumpState = !pumpState;
        digitalWrite(VACUUM_PIN, pumpState);
      }
    }
  }

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}