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.

source/Serial.cpp

Committer:
hudakz
Date:
18 months ago
Revision:
2:131555dc6fb7
Parent:
1:1f2d9982fa8c

File content as of revision 2:131555dc6fb7:

#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;
}