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 .
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
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:
- 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:
- Double click on Blinky.pro to open it for editing and add new libraries by inserting a new line as follows:
- 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.
- Press Ctrl+c to stop running the application.
Diff: source/Serial.cpp
- Revision:
- 1:1f2d9982fa8c
diff -r 91392e1f8551 -r 1f2d9982fa8c source/Serial.cpp --- /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; +} +