mbed API for Raspberry Pi boards.

mbedPi

This is an attempt to implement a limited number of mbed APIs for Raspberry Pi single-board computers. The project was inspired by and based on the arduPi library developed for the Arduino by Cooking Hacks .

/media/uploads/hudakz/board01.jpg

Specifications

  • Chip: Broadcom BCM2836 SoC
  • Core architecture: Quad-core ARM Cortex-A7
  • CPU frequency: 900 MHz
  • GPU: Dual Core VideoCore IV® Multimedia Co-Processor
  • Memory: 1GB LPDDR2
  • Operating System: Boots from Micro SD card, running a version of the Linux operating system
  • Power: Micro USB socket 5V, 2A

Connectors

  • Ethernet: 10/100 BaseT Ethernet socket
  • Video Output: HDMI (rev 1.3 & 1.4)
  • Audio Output: 3.5mm jack, HDMI
  • USB: 4 x USB 2.0 Connector
  • GPIO Connector: 40-pin 2.54 mm (100 mil) expansion header: 2x20 strip providing 27 GPIO pins as well as +3.3 V, +5 V and GND supply lines
  • Camera Connector: 15-pin MIPI Camera Serial Interface (CSI-2)
  • JTAG: Not populated
  • Display Connector: Display Serial Interface (DSI) 15 way flat flex cable connector with two data lanes and a clock lane
  • Memory Card Slot: Micro SDIO

GPIO connector pinout

Zoom in /media/uploads/hudakz/mbedpi_pinout02.png

Information

Only the labels printed in blue/white or green/white (i.e. p3, gpio2 ...) must be used in your code. The other labels are given as information (alternate-functions, power pins, ...).


Building programs for the Raspberry Pi with mbedPi

I use Qt Creator for development, however you can use any other IDE available on the Raspberry Pi (e.g. Geany) if you like. For a quick try:

  • Install Qt and the Qt Creator onto your Raspberry Pi. Then create a new "Blinky" Plain non-Qt C++ Project as follows: /media/uploads/hudakz/newproject.png

  • Change the main code as below:

main.cpp

#include "mbedPi.h"

int main()
{
    DigitalOut  myled(p7);

    while(1) {
        myled = 1; // LED is ON
        wait(0.2); // 200 ms
        myled = 0; // LED is OFF
        wait(1.0); // 1 sec
        printf("Blink\r\n");
    }
}


  • Copy the mbedPi.zip file into your project's folder and unzip.
  • Add the mbedPi.h and mbedPi.cpp files to your project by right clicking on the "Blinky" project and then clicking on the "Add Existing Files..." option in the local menu:

    /media/uploads/hudakz/addfiles.png

    /media/uploads/hudakz/addfiles02.png

  • Double click on Blinky.pro to open it for editing and add new libraries by inserting a new line as follows:

    /media/uploads/hudakz/libs.png

  • Compile the project.

  • Connect an LED through a 1k resistor to pin 7 and the ground on the Raspberry Pi GPIO connector.

  • Run the binary as sudo (sudo ./Blinky) and you should see the LED blinking. /media/uploads/hudakz/mbedpi_run.png

  • Press Ctrl+c to stop running the application.
Revision:
1:1f2d9982fa8c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/Serial.cpp	Tue Dec 20 12:08:07 2022 +0000
@@ -0,0 +1,449 @@
+#include "mbed.h"
+#include <stdarg.h>
+
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+Serial::Serial()
+{
+    //if((tx == gpio14) && (tx == gpio15)) {
+
+    REV = getBoardRev();
+    serialPort = "/dev/ttyAMA0";
+    timeOut = 1000;
+
+    //baud(9600);
+    //}
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Serial::baud(int baudrate)
+{
+    switch (baudrate) {
+        case 50:
+            speed = B50;
+            break;
+
+        case 75:
+            speed = B75;
+            break;
+
+        case 110:
+            speed = B110;
+            break;
+
+        case 134:
+            speed = B134;
+            break;
+
+        case 150:
+            speed = B150;
+            break;
+
+        case 200:
+            speed = B200;
+            break;
+
+        case 300:
+            speed = B300;
+            break;
+
+        case 600:
+            speed = B600;
+            break;
+
+        case 1200:
+            speed = B1200;
+            break;
+
+        case 1800:
+            speed = B1800;
+            break;
+
+        case 2400:
+            speed = B2400;
+            break;
+
+        case 9600:
+            speed = B9600;
+            break;
+
+        case 19200:
+            speed = B19200;
+            break;
+
+        case 38400:
+            speed = B38400;
+            break;
+
+        case 57600:
+            speed = B57600;
+            break;
+
+        case 115200:
+            speed = B115200;
+            break;
+
+        default:
+            speed = B230400;
+            break;
+    }
+
+    if ((sd = open(serialPort, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) {
+        fprintf(stderr, "Unable to open the serial port %s - \n", serialPort);
+        exit(-1);
+    }
+
+    fcntl(sd, F_SETFL, O_RDWR);
+
+    tcgetattr(sd, &options);
+    cfmakeraw(&options);
+    cfsetispeed(&options, speed);
+    cfsetospeed(&options, speed);
+
+    options.c_cflag |= (CLOCAL | CREAD);
+    options.c_cflag &= ~PARENB;
+    options.c_cflag &= ~CSTOPB;
+    options.c_cflag &= ~CSIZE;
+    options.c_cflag |= CS8;
+    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+    options.c_oflag &= ~OPOST;
+
+    tcsetattr(sd, TCSANOW, &options);
+
+    ioctl(sd, TIOCMGET, &status);
+
+    status |= TIOCM_DTR;
+    status |= TIOCM_RTS;
+
+    ioctl(sd, TIOCMSET, &status);
+
+    unistd::usleep(10000);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Serial::printf(const char* format, ...)
+{
+    char*   buf;
+    va_list args;
+
+    va_start(args, format);
+    vasprintf(&buf, format, args);
+    va_end(args);
+    unistd::write(sd, buf, strlen(buf));
+    free(buf);
+}
+
+/* Writes binary data to the serial port. This data is sent as a byte
+ * Returns: number of bytes written */
+int Serial::write(uint8_t message)
+{
+    unistd::write(sd, &message, 1);
+    return 1;
+}
+
+/* Writes binary data to the serial port. This data is sent as a series
+ * of bytes
+ * Returns: number of bytes written */
+int Serial::write(const char* message)
+{
+    int len = strlen(message);
+    unistd::write(sd, &message, len);
+    return len;
+}
+
+/* Writes binary data to the serial port. This data is sent as a series
+ * of bytes placed in an buffer. It needs the length of the buffer
+ * Returns: number of bytes written */
+int Serial::write(char* message, int size)
+{
+    unistd::write(sd, message, size);
+    return size;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int Serial::readable()
+{
+    int nbytes = 0;
+    if (ioctl(sd, FIONREAD, &nbytes) < 0) {
+        fprintf(stderr, "Failed to get byte count on serial.\n");
+        exit(-1);
+    }
+
+    return(nbytes > 0 ? 1 : 0);
+}
+
+/* Reads 1 byte of incoming serial data
+ * Returns: first byte of incoming serial data available */
+char Serial::read()
+{
+    unistd::read(sd, &c, 1);
+    return c;
+}
+
+/* Reads characters from th serial port into a buffer. The function
+ * terminates if the determined length has been read, or it times out
+ * Returns: number of bytes readed */
+int Serial::readBytes(char message[], int size)
+{
+    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
+
+    int count;
+    for (count = 0; count < size; count++) {
+        if (readable())
+            unistd::read(sd, &message[count], 1);
+        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
+
+        timespec    t = timeDiff(time1, time2);
+        if ((t.tv_nsec / 1000) > timeOut)
+            break;
+    }
+
+    return count;
+}
+
+/* Reads characters from the serial buffer into an array.
+ * The function terminates if the terminator character is detected,
+ * the determined length has been read, or it times out.
+ * Returns: number of characters read into the buffer. */
+int Serial::readBytesUntil(char character, char buffer[], int length)
+{
+    char    lastReaded = character + 1; //Just to make lastReaded != character
+    int     count = 0;
+    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
+    while (count != length && lastReaded != character) {
+        if (readable())
+            unistd::read(sd, &buffer[count], 1);
+        lastReaded = buffer[count];
+        count++;
+        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
+
+        timespec    t = timeDiff(time1, time2);
+        if ((t.tv_nsec / 1000) > timeOut)
+            break;
+    }
+
+    return count;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool Serial::find(const char* target)
+{
+    findUntil(target, NULL);
+}
+
+/* Reads data from the serial buffer until a target string of given length
+ * or terminator string is found.
+ * Returns: true if the target string is found, false if it times out */
+bool Serial::findUntil(const char* target, const char* terminal)
+{
+    int         index = 0;
+    int         termIndex = 0;
+    int         targetLen = strlen(target);
+    int         termLen = strlen(terminal);
+    char        readed;
+    timespec    t;
+
+    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
+
+    if (*target == 0)
+        return true;                // return true if target is a null string
+    do
+    {
+        if (readable()) {
+            unistd::read(sd, &readed, 1);
+            if (readed != target[index])
+                index = 0;          // reset index if any char does not match
+            if (readed == target[index]) {
+                if (++index >= targetLen) {
+
+                    // return true if all chars in the target match
+                    return true;
+                }
+            }
+
+            if (termLen > 0 && c == terminal[termIndex]) {
+                if (++termIndex >= termLen)
+                    return false;   // return false if terminate string found before target string
+            }
+            else {
+                termIndex = 0;
+            }
+        }
+
+        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
+        t = timeDiff(time1, time2);
+    } while ((t.tv_nsec / 1000) <= timeOut);
+
+    return false;
+}
+
+/* returns the first valid (long) integer value from the current position.
+ * initial characters that are not digits (or the minus sign) are skipped
+ * function is terminated by the first character that is not a digit. */
+long Serial::parseInt()
+{
+    bool    isNegative = false;
+    long    value = 0;
+    char    c;
+
+    //Skip characters until a number or - sign found
+
+    do
+    {
+        c = peek();
+        if (c == '-')
+            break;
+        if (c >= '0' && c <= '9')
+            break;
+        unistd::read(sd, &c, 1);    // discard non-numeric
+    } while (1);
+
+    do
+    {
+        if (c == '-')
+            isNegative = true;
+        else
+        if (c >= '0' && c <= '9')   // is c a digit?
+            value = value * 10 + c - '0';
+        unistd::read(sd, &c, 1);    // consume the character we got with peek
+        c = peek();
+    } while (c >= '0' && c <= '9');
+
+    if (isNegative)
+        value = -value;
+    return value;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+float Serial::parseFloat()
+{
+    boolean isNegative = false;
+    boolean isFraction = false;
+    long    value = 0;
+    char    c;
+    float   fraction = 1.0;
+
+    //Skip characters until a number or - sign found
+
+    do
+    {
+        c = peek();
+        if (c == '-')
+            break;
+        if (c >= '0' && c <= '9')
+            break;
+        unistd::read(sd, &c, 1);    // discard non-numeric
+    } while (1);
+
+    do
+    {
+        if (c == '-')
+            isNegative = true;
+        else
+        if (c == '.')
+            isFraction = true;
+        else
+        if (c >= '0' && c <= '9') {
+
+            // is c a digit?
+            value = value * 10 + c - '0';
+            if (isFraction)
+                fraction *= 0.1;
+        }
+
+        unistd::read(sd, &c, 1);    // consume the character we got with peek
+        c = peek();
+    } while ((c >= '0' && c <= '9') || (c == '.' && isFraction == false));
+
+    if (isNegative)
+        value = -value;
+    if (isFraction)
+        return value * fraction;
+    else
+        return value;
+}
+
+// Returns the next byte (character) of incoming serial data without removing it from the internal serial buffer.
+char Serial::peek()
+{
+    //We obtain a pointer to FILE structure from the file descriptor sd
+    FILE*   f = fdopen(sd, "r+");
+
+    //With a pointer to FILE we can do getc and ungetc
+
+    c = getc(f);
+    ungetc(c, f);
+    return c;
+}
+
+// Remove any data remaining on the serial buffer
+void Serial::flush()
+{
+    while (readable()) {
+        unistd::read(sd, &c, 1);
+    }
+}
+
+/* Sets the maximum milliseconds to wait for serial data when using SerialPI::readBytes()
+ * The default value is set to 1000 */
+void Serial::setTimeout(long millis)
+{
+    timeOut = millis;
+}
+
+//Closes serial communication
+void Serial::close()
+{
+    unistd::close(sd);
+}
+
+/*******************
+ * Private methods *
+ *******************/
+
+//Returns a timespec struct with the time elapsed between start and end timespecs
+timespec Serial::timeDiff(timespec start, timespec end)
+{
+    timespec    temp;
+    if ((end.tv_nsec - start.tv_nsec) < 0) {
+        temp.tv_sec = end.tv_sec - start.tv_sec - 1;
+        temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
+    }
+    else {
+        temp.tv_sec = end.tv_sec - start.tv_sec;
+        temp.tv_nsec = end.tv_nsec - start.tv_nsec;
+    }
+
+    return temp;
+}
+