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.
Committer:
hudakz
Date:
Tue Oct 18 18:18:37 2016 +0000
Revision:
0:91392e1f8551
Initial issue.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:91392e1f8551 1 /*
hudakz 0:91392e1f8551 2 * Copyright (C) 2016 Zoltan Hudak
hudakz 0:91392e1f8551 3 * hudakz@outlook.com
hudakz 0:91392e1f8551 4 *
hudakz 0:91392e1f8551 5 * Portions Copyright (C) Libelium Comunicaciones Distribuidas S.L.
hudakz 0:91392e1f8551 6 * http://www.libelium.com
hudakz 0:91392e1f8551 7 *
hudakz 0:91392e1f8551 8 * This program is free software: you can redistribute it and/or modify
hudakz 0:91392e1f8551 9 * it under the terms of the GNU General Public License as published by
hudakz 0:91392e1f8551 10 * the Free Software Foundation, either version 3 of the License, or
hudakz 0:91392e1f8551 11 * (at your option) any later version.
hudakz 0:91392e1f8551 12 *
hudakz 0:91392e1f8551 13 * This program is distributed in the hope that it will be useful,
hudakz 0:91392e1f8551 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
hudakz 0:91392e1f8551 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
hudakz 0:91392e1f8551 16 * GNU General Public License for more details.
hudakz 0:91392e1f8551 17 *
hudakz 0:91392e1f8551 18 * You should have received a copy of the GNU General Public License
hudakz 0:91392e1f8551 19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
hudakz 0:91392e1f8551 20 *
hudakz 0:91392e1f8551 21 * Version 1.0
hudakz 0:91392e1f8551 22 */
hudakz 0:91392e1f8551 23 //
hudakz 0:91392e1f8551 24 #include "mbedPi.h"
hudakz 0:91392e1f8551 25 #include <stdarg.h>
hudakz 0:91392e1f8551 26 /*$off*/
hudakz 0:91392e1f8551 27 struct bcm2835_peripheral gpio = { GPIO_BASE };
hudakz 0:91392e1f8551 28 struct bcm2835_peripheral bsc_rev1 = { IOBASE + 0X205000 };
hudakz 0:91392e1f8551 29 struct bcm2835_peripheral bsc_rev2 = { IOBASE + 0X804000 };
hudakz 0:91392e1f8551 30 struct bcm2835_peripheral bsc0;
hudakz 0:91392e1f8551 31 volatile uint32_t* bcm2835_bsc1;
hudakz 0:91392e1f8551 32
hudakz 0:91392e1f8551 33 void* spi0 = MAP_FAILED;
hudakz 0:91392e1f8551 34 static uint8_t* spi0Mem = NULL;
hudakz 0:91392e1f8551 35
hudakz 0:91392e1f8551 36 pthread_t idThread2;
hudakz 0:91392e1f8551 37 pthread_t idThread3;
hudakz 0:91392e1f8551 38 pthread_t idThread4;
hudakz 0:91392e1f8551 39 pthread_t idThread5;
hudakz 0:91392e1f8551 40 pthread_t idThread6;
hudakz 0:91392e1f8551 41 pthread_t idThread7;
hudakz 0:91392e1f8551 42 pthread_t idThread8;
hudakz 0:91392e1f8551 43 pthread_t idThread9;
hudakz 0:91392e1f8551 44 pthread_t idThread10;
hudakz 0:91392e1f8551 45 pthread_t idThread11;
hudakz 0:91392e1f8551 46 pthread_t idThread12;
hudakz 0:91392e1f8551 47 pthread_t idThread13;
hudakz 0:91392e1f8551 48 pthread_t idThread14;
hudakz 0:91392e1f8551 49 pthread_t idThread15;
hudakz 0:91392e1f8551 50 pthread_t idThread16;
hudakz 0:91392e1f8551 51 pthread_t idThread17;
hudakz 0:91392e1f8551 52 pthread_t idThread18;
hudakz 0:91392e1f8551 53 pthread_t idThread19;
hudakz 0:91392e1f8551 54 pthread_t idThread20;
hudakz 0:91392e1f8551 55 pthread_t idThread21;
hudakz 0:91392e1f8551 56 pthread_t idThread22;
hudakz 0:91392e1f8551 57 pthread_t idThread23;
hudakz 0:91392e1f8551 58 pthread_t idThread24;
hudakz 0:91392e1f8551 59 pthread_t idThread25;
hudakz 0:91392e1f8551 60 pthread_t idThread26;
hudakz 0:91392e1f8551 61 pthread_t idThread27;
hudakz 0:91392e1f8551 62
hudakz 0:91392e1f8551 63 pthread_t* idThreads[26] =
hudakz 0:91392e1f8551 64 {
hudakz 0:91392e1f8551 65 &idThread2,
hudakz 0:91392e1f8551 66 &idThread3,
hudakz 0:91392e1f8551 67 &idThread4,
hudakz 0:91392e1f8551 68 &idThread5,
hudakz 0:91392e1f8551 69 &idThread6,
hudakz 0:91392e1f8551 70 &idThread7,
hudakz 0:91392e1f8551 71 &idThread8,
hudakz 0:91392e1f8551 72 &idThread9,
hudakz 0:91392e1f8551 73 &idThread10,
hudakz 0:91392e1f8551 74 &idThread11,
hudakz 0:91392e1f8551 75 &idThread12,
hudakz 0:91392e1f8551 76 &idThread13,
hudakz 0:91392e1f8551 77 &idThread14,
hudakz 0:91392e1f8551 78 &idThread15,
hudakz 0:91392e1f8551 79 &idThread16,
hudakz 0:91392e1f8551 80 &idThread17,
hudakz 0:91392e1f8551 81 &idThread18,
hudakz 0:91392e1f8551 82 &idThread19,
hudakz 0:91392e1f8551 83 &idThread20,
hudakz 0:91392e1f8551 84 &idThread21,
hudakz 0:91392e1f8551 85 &idThread22,
hudakz 0:91392e1f8551 86 &idThread23,
hudakz 0:91392e1f8551 87 &idThread24,
hudakz 0:91392e1f8551 88 &idThread25,
hudakz 0:91392e1f8551 89 &idThread26,
hudakz 0:91392e1f8551 90 &idThread27
hudakz 0:91392e1f8551 91 };
hudakz 0:91392e1f8551 92
hudakz 0:91392e1f8551 93 timeval start_program, end_point;
hudakz 0:91392e1f8551 94
hudakz 0:91392e1f8551 95 /*$on*/
hudakz 0:91392e1f8551 96 /**
hudakz 0:91392e1f8551 97 * @brief
hudakz 0:91392e1f8551 98 * @note
hudakz 0:91392e1f8551 99 * @param
hudakz 0:91392e1f8551 100 * @retval
hudakz 0:91392e1f8551 101 */
hudakz 0:91392e1f8551 102 void wait(float s) {
hudakz 0:91392e1f8551 103 unistd::usleep(s * 1000 * 1000);
hudakz 0:91392e1f8551 104 }
hudakz 0:91392e1f8551 105
hudakz 0:91392e1f8551 106 /**
hudakz 0:91392e1f8551 107 * @brief
hudakz 0:91392e1f8551 108 * @note
hudakz 0:91392e1f8551 109 * @param
hudakz 0:91392e1f8551 110 * @retval
hudakz 0:91392e1f8551 111 */
hudakz 0:91392e1f8551 112 void wait_ms(int ms) {
hudakz 0:91392e1f8551 113 unistd::usleep(ms * 1000);
hudakz 0:91392e1f8551 114 }
hudakz 0:91392e1f8551 115
hudakz 0:91392e1f8551 116 /**
hudakz 0:91392e1f8551 117 * @brief
hudakz 0:91392e1f8551 118 * @note
hudakz 0:91392e1f8551 119 * @param
hudakz 0:91392e1f8551 120 * @retval
hudakz 0:91392e1f8551 121 */
hudakz 0:91392e1f8551 122 void wait_us(int us) {
hudakz 0:91392e1f8551 123 if(us > 100) {
hudakz 0:91392e1f8551 124 struct timespec tim, tim2;
hudakz 0:91392e1f8551 125 tim.tv_sec = 0;
hudakz 0:91392e1f8551 126 tim.tv_nsec = us * 1000;
hudakz 0:91392e1f8551 127
hudakz 0:91392e1f8551 128 if(nanosleep(&tim, &tim2) < 0) {
hudakz 0:91392e1f8551 129 fprintf(stderr, "Nano sleep system call failed \n");
hudakz 0:91392e1f8551 130 exit(1);
hudakz 0:91392e1f8551 131 }
hudakz 0:91392e1f8551 132 }
hudakz 0:91392e1f8551 133 else {
hudakz 0:91392e1f8551 134 struct timeval tNow, tLong, tEnd;
hudakz 0:91392e1f8551 135
hudakz 0:91392e1f8551 136 gettimeofday(&tNow, NULL);
hudakz 0:91392e1f8551 137 tLong.tv_sec = us / 1000000;
hudakz 0:91392e1f8551 138 tLong.tv_usec = us % 1000000;
hudakz 0:91392e1f8551 139 timeradd(&tNow, &tLong, &tEnd);
hudakz 0:91392e1f8551 140
hudakz 0:91392e1f8551 141 while(timercmp(&tNow, &tEnd, < ))
hudakz 0:91392e1f8551 142 gettimeofday(&tNow, NULL);
hudakz 0:91392e1f8551 143 }
hudakz 0:91392e1f8551 144 }
hudakz 0:91392e1f8551 145
hudakz 0:91392e1f8551 146 /**
hudakz 0:91392e1f8551 147 * @brief
hudakz 0:91392e1f8551 148 * @note
hudakz 0:91392e1f8551 149 * @param
hudakz 0:91392e1f8551 150 * @retval
hudakz 0:91392e1f8551 151 */
hudakz 0:91392e1f8551 152 Serial::Serial(void) {
hudakz 0:91392e1f8551 153 //if((tx == gpio14) && (tx == gpio15)) {
hudakz 0:91392e1f8551 154 REV = getBoardRev();
hudakz 0:91392e1f8551 155 serialPort = "/dev/ttyAMA0";
hudakz 0:91392e1f8551 156 timeOut = 1000;
hudakz 0:91392e1f8551 157 //baud(9600);
hudakz 0:91392e1f8551 158 //}
hudakz 0:91392e1f8551 159 }
hudakz 0:91392e1f8551 160
hudakz 0:91392e1f8551 161 /**
hudakz 0:91392e1f8551 162 * @brief
hudakz 0:91392e1f8551 163 * @note
hudakz 0:91392e1f8551 164 * @param
hudakz 0:91392e1f8551 165 * @retval
hudakz 0:91392e1f8551 166 */
hudakz 0:91392e1f8551 167 void Serial::baud(int baudrate) {
hudakz 0:91392e1f8551 168 switch(baudrate) {
hudakz 0:91392e1f8551 169 case 50:
hudakz 0:91392e1f8551 170 speed = B50;
hudakz 0:91392e1f8551 171 break;
hudakz 0:91392e1f8551 172
hudakz 0:91392e1f8551 173 case 75:
hudakz 0:91392e1f8551 174 speed = B75;
hudakz 0:91392e1f8551 175 break;
hudakz 0:91392e1f8551 176
hudakz 0:91392e1f8551 177 case 110:
hudakz 0:91392e1f8551 178 speed = B110;
hudakz 0:91392e1f8551 179 break;
hudakz 0:91392e1f8551 180
hudakz 0:91392e1f8551 181 case 134:
hudakz 0:91392e1f8551 182 speed = B134;
hudakz 0:91392e1f8551 183 break;
hudakz 0:91392e1f8551 184
hudakz 0:91392e1f8551 185 case 150:
hudakz 0:91392e1f8551 186 speed = B150;
hudakz 0:91392e1f8551 187 break;
hudakz 0:91392e1f8551 188
hudakz 0:91392e1f8551 189 case 200:
hudakz 0:91392e1f8551 190 speed = B200;
hudakz 0:91392e1f8551 191 break;
hudakz 0:91392e1f8551 192
hudakz 0:91392e1f8551 193 case 300:
hudakz 0:91392e1f8551 194 speed = B300;
hudakz 0:91392e1f8551 195 break;
hudakz 0:91392e1f8551 196
hudakz 0:91392e1f8551 197 case 600:
hudakz 0:91392e1f8551 198 speed = B600;
hudakz 0:91392e1f8551 199 break;
hudakz 0:91392e1f8551 200
hudakz 0:91392e1f8551 201 case 1200:
hudakz 0:91392e1f8551 202 speed = B1200;
hudakz 0:91392e1f8551 203 break;
hudakz 0:91392e1f8551 204
hudakz 0:91392e1f8551 205 case 1800:
hudakz 0:91392e1f8551 206 speed = B1800;
hudakz 0:91392e1f8551 207 break;
hudakz 0:91392e1f8551 208
hudakz 0:91392e1f8551 209 case 2400:
hudakz 0:91392e1f8551 210 speed = B2400;
hudakz 0:91392e1f8551 211 break;
hudakz 0:91392e1f8551 212
hudakz 0:91392e1f8551 213 case 9600:
hudakz 0:91392e1f8551 214 speed = B9600;
hudakz 0:91392e1f8551 215 break;
hudakz 0:91392e1f8551 216
hudakz 0:91392e1f8551 217 case 19200:
hudakz 0:91392e1f8551 218 speed = B19200;
hudakz 0:91392e1f8551 219 break;
hudakz 0:91392e1f8551 220
hudakz 0:91392e1f8551 221 case 38400:
hudakz 0:91392e1f8551 222 speed = B38400;
hudakz 0:91392e1f8551 223 break;
hudakz 0:91392e1f8551 224
hudakz 0:91392e1f8551 225 case 57600:
hudakz 0:91392e1f8551 226 speed = B57600;
hudakz 0:91392e1f8551 227 break;
hudakz 0:91392e1f8551 228
hudakz 0:91392e1f8551 229 case 115200:
hudakz 0:91392e1f8551 230 speed = B115200;
hudakz 0:91392e1f8551 231 break;
hudakz 0:91392e1f8551 232
hudakz 0:91392e1f8551 233 default:
hudakz 0:91392e1f8551 234 speed = B230400;
hudakz 0:91392e1f8551 235 break;
hudakz 0:91392e1f8551 236 }
hudakz 0:91392e1f8551 237
hudakz 0:91392e1f8551 238 if((sd = open(serialPort, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) {
hudakz 0:91392e1f8551 239 fprintf(stderr, "Unable to open the serial port %s - \n", serialPort);
hudakz 0:91392e1f8551 240 exit(-1);
hudakz 0:91392e1f8551 241 }
hudakz 0:91392e1f8551 242
hudakz 0:91392e1f8551 243 fcntl(sd, F_SETFL, O_RDWR);
hudakz 0:91392e1f8551 244
hudakz 0:91392e1f8551 245 tcgetattr(sd, &options);
hudakz 0:91392e1f8551 246 cfmakeraw(&options);
hudakz 0:91392e1f8551 247 cfsetispeed(&options, speed);
hudakz 0:91392e1f8551 248 cfsetospeed(&options, speed);
hudakz 0:91392e1f8551 249
hudakz 0:91392e1f8551 250 options.c_cflag |= (CLOCAL | CREAD);
hudakz 0:91392e1f8551 251 options.c_cflag &= ~PARENB;
hudakz 0:91392e1f8551 252 options.c_cflag &= ~CSTOPB;
hudakz 0:91392e1f8551 253 options.c_cflag &= ~CSIZE;
hudakz 0:91392e1f8551 254 options.c_cflag |= CS8;
hudakz 0:91392e1f8551 255 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
hudakz 0:91392e1f8551 256 options.c_oflag &= ~OPOST;
hudakz 0:91392e1f8551 257
hudakz 0:91392e1f8551 258 tcsetattr(sd, TCSANOW, &options);
hudakz 0:91392e1f8551 259
hudakz 0:91392e1f8551 260 ioctl(sd, TIOCMGET, &status);
hudakz 0:91392e1f8551 261
hudakz 0:91392e1f8551 262 status |= TIOCM_DTR;
hudakz 0:91392e1f8551 263 status |= TIOCM_RTS;
hudakz 0:91392e1f8551 264
hudakz 0:91392e1f8551 265 ioctl(sd, TIOCMSET, &status);
hudakz 0:91392e1f8551 266
hudakz 0:91392e1f8551 267 unistd::usleep(10000);
hudakz 0:91392e1f8551 268 }
hudakz 0:91392e1f8551 269
hudakz 0:91392e1f8551 270 void Serial::printf(const char* format, ...) {
hudakz 0:91392e1f8551 271 char *buf;
hudakz 0:91392e1f8551 272 va_list args;
hudakz 0:91392e1f8551 273
hudakz 0:91392e1f8551 274 va_start(args, format);
hudakz 0:91392e1f8551 275 vasprintf(&buf, format, args);
hudakz 0:91392e1f8551 276 va_end(args);
hudakz 0:91392e1f8551 277 unistd::write(sd, buf, strlen(buf));
hudakz 0:91392e1f8551 278 free(buf);
hudakz 0:91392e1f8551 279 }
hudakz 0:91392e1f8551 280
hudakz 0:91392e1f8551 281 /* Writes binary data to the serial port. This data is sent as a byte
hudakz 0:91392e1f8551 282 * Returns: number of bytes written */
hudakz 0:91392e1f8551 283 int Serial::write(uint8_t message) {
hudakz 0:91392e1f8551 284 unistd::write(sd, &message, 1);
hudakz 0:91392e1f8551 285 return 1;
hudakz 0:91392e1f8551 286 }
hudakz 0:91392e1f8551 287
hudakz 0:91392e1f8551 288 /* Writes binary data to the serial port. This data is sent as a series
hudakz 0:91392e1f8551 289 * of bytes
hudakz 0:91392e1f8551 290 * Returns: number of bytes written */
hudakz 0:91392e1f8551 291 int Serial::write(const char* message) {
hudakz 0:91392e1f8551 292 int len = strlen(message);
hudakz 0:91392e1f8551 293 unistd::write(sd, &message, len);
hudakz 0:91392e1f8551 294 return len;
hudakz 0:91392e1f8551 295 }
hudakz 0:91392e1f8551 296
hudakz 0:91392e1f8551 297 /* Writes binary data to the serial port. This data is sent as a series
hudakz 0:91392e1f8551 298 * of bytes placed in an buffer. It needs the length of the buffer
hudakz 0:91392e1f8551 299 * Returns: number of bytes written */
hudakz 0:91392e1f8551 300 int Serial::write(char* message, int size) {
hudakz 0:91392e1f8551 301 unistd::write(sd, message, size);
hudakz 0:91392e1f8551 302 return size;
hudakz 0:91392e1f8551 303 }
hudakz 0:91392e1f8551 304
hudakz 0:91392e1f8551 305 int Serial::readable(void) {
hudakz 0:91392e1f8551 306 int nbytes = 0;
hudakz 0:91392e1f8551 307 if(ioctl(sd, FIONREAD, &nbytes) < 0) {
hudakz 0:91392e1f8551 308 fprintf(stderr, "Failed to get byte count on serial.\n");
hudakz 0:91392e1f8551 309 exit(-1);
hudakz 0:91392e1f8551 310 }
hudakz 0:91392e1f8551 311
hudakz 0:91392e1f8551 312 return (nbytes > 0 ? 1 : 0);
hudakz 0:91392e1f8551 313 }
hudakz 0:91392e1f8551 314
hudakz 0:91392e1f8551 315 /* Reads 1 byte of incoming serial data
hudakz 0:91392e1f8551 316 * Returns: first byte of incoming serial data available */
hudakz 0:91392e1f8551 317 char Serial::read(void) {
hudakz 0:91392e1f8551 318 unistd::read(sd, &c, 1);
hudakz 0:91392e1f8551 319 return c;
hudakz 0:91392e1f8551 320 }
hudakz 0:91392e1f8551 321
hudakz 0:91392e1f8551 322 /* Reads characters from th serial port into a buffer. The function
hudakz 0:91392e1f8551 323 * terminates if the determined length has been read, or it times out
hudakz 0:91392e1f8551 324 * Returns: number of bytes readed */
hudakz 0:91392e1f8551 325 int Serial::readBytes(char message[], int size) {
hudakz 0:91392e1f8551 326 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
hudakz 0:91392e1f8551 327
hudakz 0:91392e1f8551 328 int count;
hudakz 0:91392e1f8551 329 for(count = 0; count < size; count++) {
hudakz 0:91392e1f8551 330 if(readable())
hudakz 0:91392e1f8551 331 unistd::read(sd, &message[count], 1);
hudakz 0:91392e1f8551 332 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
hudakz 0:91392e1f8551 333
hudakz 0:91392e1f8551 334 timespec t = timeDiff(time1, time2);
hudakz 0:91392e1f8551 335 if((t.tv_nsec / 1000) > timeOut)
hudakz 0:91392e1f8551 336 break;
hudakz 0:91392e1f8551 337 }
hudakz 0:91392e1f8551 338
hudakz 0:91392e1f8551 339 return count;
hudakz 0:91392e1f8551 340 }
hudakz 0:91392e1f8551 341
hudakz 0:91392e1f8551 342 /* Reads characters from the serial buffer into an array.
hudakz 0:91392e1f8551 343 * The function terminates if the terminator character is detected,
hudakz 0:91392e1f8551 344 * the determined length has been read, or it times out.
hudakz 0:91392e1f8551 345 * Returns: number of characters read into the buffer. */
hudakz 0:91392e1f8551 346 int Serial::readBytesUntil(char character, char buffer[], int length) {
hudakz 0:91392e1f8551 347 char lastReaded = character + 1; //Just to make lastReaded != character
hudakz 0:91392e1f8551 348 int count = 0;
hudakz 0:91392e1f8551 349 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
hudakz 0:91392e1f8551 350 while(count != length && lastReaded != character) {
hudakz 0:91392e1f8551 351 if(readable())
hudakz 0:91392e1f8551 352 unistd::read(sd, &buffer[count], 1);
hudakz 0:91392e1f8551 353 lastReaded = buffer[count];
hudakz 0:91392e1f8551 354 count++;
hudakz 0:91392e1f8551 355 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
hudakz 0:91392e1f8551 356
hudakz 0:91392e1f8551 357 timespec t = timeDiff(time1, time2);
hudakz 0:91392e1f8551 358 if((t.tv_nsec / 1000) > timeOut)
hudakz 0:91392e1f8551 359 break;
hudakz 0:91392e1f8551 360 }
hudakz 0:91392e1f8551 361
hudakz 0:91392e1f8551 362 return count;
hudakz 0:91392e1f8551 363 }
hudakz 0:91392e1f8551 364
hudakz 0:91392e1f8551 365 /**
hudakz 0:91392e1f8551 366 * @brief
hudakz 0:91392e1f8551 367 * @note
hudakz 0:91392e1f8551 368 * @param
hudakz 0:91392e1f8551 369 * @retval
hudakz 0:91392e1f8551 370 */
hudakz 0:91392e1f8551 371 bool Serial::find(const char* target) {
hudakz 0:91392e1f8551 372 findUntil(target, NULL);
hudakz 0:91392e1f8551 373 }
hudakz 0:91392e1f8551 374
hudakz 0:91392e1f8551 375 /* Reads data from the serial buffer until a target string of given length
hudakz 0:91392e1f8551 376 * or terminator string is found.
hudakz 0:91392e1f8551 377 * Returns: true if the target string is found, false if it times out */
hudakz 0:91392e1f8551 378 bool Serial::findUntil(const char* target, const char* terminal) {
hudakz 0:91392e1f8551 379 int index = 0;
hudakz 0:91392e1f8551 380 int termIndex = 0;
hudakz 0:91392e1f8551 381 int targetLen = strlen(target);
hudakz 0:91392e1f8551 382 int termLen = strlen(terminal);
hudakz 0:91392e1f8551 383 char readed;
hudakz 0:91392e1f8551 384 timespec t;
hudakz 0:91392e1f8551 385
hudakz 0:91392e1f8551 386 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
hudakz 0:91392e1f8551 387
hudakz 0:91392e1f8551 388 if(*target == 0)
hudakz 0:91392e1f8551 389 return true; // return true if target is a null string
hudakz 0:91392e1f8551 390 do
hudakz 0:91392e1f8551 391 {
hudakz 0:91392e1f8551 392 if(readable()) {
hudakz 0:91392e1f8551 393 unistd::read(sd, &readed, 1);
hudakz 0:91392e1f8551 394 if(readed != target[index])
hudakz 0:91392e1f8551 395 index = 0; // reset index if any char does not match
hudakz 0:91392e1f8551 396 if(readed == target[index]) {
hudakz 0:91392e1f8551 397 if(++index >= targetLen) {
hudakz 0:91392e1f8551 398
hudakz 0:91392e1f8551 399 // return true if all chars in the target match
hudakz 0:91392e1f8551 400 return true;
hudakz 0:91392e1f8551 401 }
hudakz 0:91392e1f8551 402 }
hudakz 0:91392e1f8551 403
hudakz 0:91392e1f8551 404 if(termLen > 0 && c == terminal[termIndex]) {
hudakz 0:91392e1f8551 405 if(++termIndex >= termLen)
hudakz 0:91392e1f8551 406 return false; // return false if terminate string found before target string
hudakz 0:91392e1f8551 407 }
hudakz 0:91392e1f8551 408 else {
hudakz 0:91392e1f8551 409 termIndex = 0;
hudakz 0:91392e1f8551 410 }
hudakz 0:91392e1f8551 411 }
hudakz 0:91392e1f8551 412
hudakz 0:91392e1f8551 413 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
hudakz 0:91392e1f8551 414 t = timeDiff(time1, time2);
hudakz 0:91392e1f8551 415 } while((t.tv_nsec / 1000) <= timeOut);
hudakz 0:91392e1f8551 416
hudakz 0:91392e1f8551 417 return false;
hudakz 0:91392e1f8551 418 }
hudakz 0:91392e1f8551 419
hudakz 0:91392e1f8551 420 /* returns the first valid (long) integer value from the current position.
hudakz 0:91392e1f8551 421 * initial characters that are not digits (or the minus sign) are skipped
hudakz 0:91392e1f8551 422 * function is terminated by the first character that is not a digit. */
hudakz 0:91392e1f8551 423 long Serial::parseInt(void) {
hudakz 0:91392e1f8551 424 bool isNegative = false;
hudakz 0:91392e1f8551 425 long value = 0;
hudakz 0:91392e1f8551 426 char c;
hudakz 0:91392e1f8551 427
hudakz 0:91392e1f8551 428 //Skip characters until a number or - sign found
hudakz 0:91392e1f8551 429 do
hudakz 0:91392e1f8551 430 {
hudakz 0:91392e1f8551 431 c = peek();
hudakz 0:91392e1f8551 432 if(c == '-')
hudakz 0:91392e1f8551 433 break;
hudakz 0:91392e1f8551 434 if(c >= '0' && c <= '9')
hudakz 0:91392e1f8551 435 break;
hudakz 0:91392e1f8551 436 unistd::read(sd, &c, 1); // discard non-numeric
hudakz 0:91392e1f8551 437 } while(1);
hudakz 0:91392e1f8551 438
hudakz 0:91392e1f8551 439 do
hudakz 0:91392e1f8551 440 {
hudakz 0:91392e1f8551 441 if(c == '-')
hudakz 0:91392e1f8551 442 isNegative = true;
hudakz 0:91392e1f8551 443 else
hudakz 0:91392e1f8551 444 if(c >= '0' && c <= '9') // is c a digit?
hudakz 0:91392e1f8551 445 value = value * 10 + c - '0';
hudakz 0:91392e1f8551 446 unistd::read(sd, &c, 1); // consume the character we got with peek
hudakz 0:91392e1f8551 447 c = peek();
hudakz 0:91392e1f8551 448 } while(c >= '0' && c <= '9');
hudakz 0:91392e1f8551 449
hudakz 0:91392e1f8551 450 if(isNegative)
hudakz 0:91392e1f8551 451 value = -value;
hudakz 0:91392e1f8551 452 return value;
hudakz 0:91392e1f8551 453 }
hudakz 0:91392e1f8551 454
hudakz 0:91392e1f8551 455 /**
hudakz 0:91392e1f8551 456 * @brief
hudakz 0:91392e1f8551 457 * @note
hudakz 0:91392e1f8551 458 * @param
hudakz 0:91392e1f8551 459 * @retval
hudakz 0:91392e1f8551 460 */
hudakz 0:91392e1f8551 461 float Serial::parseFloat(void) {
hudakz 0:91392e1f8551 462 boolean isNegative = false;
hudakz 0:91392e1f8551 463 boolean isFraction = false;
hudakz 0:91392e1f8551 464 long value = 0;
hudakz 0:91392e1f8551 465 char c;
hudakz 0:91392e1f8551 466 float fraction = 1.0;
hudakz 0:91392e1f8551 467
hudakz 0:91392e1f8551 468 //Skip characters until a number or - sign found
hudakz 0:91392e1f8551 469 do
hudakz 0:91392e1f8551 470 {
hudakz 0:91392e1f8551 471 c = peek();
hudakz 0:91392e1f8551 472 if(c == '-')
hudakz 0:91392e1f8551 473 break;
hudakz 0:91392e1f8551 474 if(c >= '0' && c <= '9')
hudakz 0:91392e1f8551 475 break;
hudakz 0:91392e1f8551 476 unistd::read(sd, &c, 1); // discard non-numeric
hudakz 0:91392e1f8551 477 } while(1);
hudakz 0:91392e1f8551 478
hudakz 0:91392e1f8551 479 do
hudakz 0:91392e1f8551 480 {
hudakz 0:91392e1f8551 481 if(c == '-')
hudakz 0:91392e1f8551 482 isNegative = true;
hudakz 0:91392e1f8551 483 else
hudakz 0:91392e1f8551 484 if(c == '.')
hudakz 0:91392e1f8551 485 isFraction = true;
hudakz 0:91392e1f8551 486 else
hudakz 0:91392e1f8551 487 if(c >= '0' && c <= '9') {
hudakz 0:91392e1f8551 488
hudakz 0:91392e1f8551 489 // is c a digit?
hudakz 0:91392e1f8551 490 value = value * 10 + c - '0';
hudakz 0:91392e1f8551 491 if(isFraction)
hudakz 0:91392e1f8551 492 fraction *= 0.1;
hudakz 0:91392e1f8551 493 }
hudakz 0:91392e1f8551 494
hudakz 0:91392e1f8551 495 unistd::read(sd, &c, 1); // consume the character we got with peek
hudakz 0:91392e1f8551 496 c = peek();
hudakz 0:91392e1f8551 497 } while((c >= '0' && c <= '9') || (c == '.' && isFraction == false));
hudakz 0:91392e1f8551 498
hudakz 0:91392e1f8551 499 if(isNegative)
hudakz 0:91392e1f8551 500 value = -value;
hudakz 0:91392e1f8551 501 if(isFraction)
hudakz 0:91392e1f8551 502 return value * fraction;
hudakz 0:91392e1f8551 503 else
hudakz 0:91392e1f8551 504 return value;
hudakz 0:91392e1f8551 505 }
hudakz 0:91392e1f8551 506
hudakz 0:91392e1f8551 507 // Returns the next byte (character) of incoming serial data without removing it from the internal serial buffer.
hudakz 0:91392e1f8551 508 char Serial::peek(void) {
hudakz 0:91392e1f8551 509
hudakz 0:91392e1f8551 510 //We obtain a pointer to FILE structure from the file descriptor sd
hudakz 0:91392e1f8551 511 FILE* f = fdopen(sd, "r+");
hudakz 0:91392e1f8551 512
hudakz 0:91392e1f8551 513 //With a pointer to FILE we can do getc and ungetc
hudakz 0:91392e1f8551 514 c = getc(f);
hudakz 0:91392e1f8551 515 ungetc(c, f);
hudakz 0:91392e1f8551 516 return c;
hudakz 0:91392e1f8551 517 }
hudakz 0:91392e1f8551 518
hudakz 0:91392e1f8551 519 // Remove any data remaining on the serial buffer
hudakz 0:91392e1f8551 520 void Serial::flush(void) {
hudakz 0:91392e1f8551 521 while(readable()) {
hudakz 0:91392e1f8551 522 unistd::read(sd, &c, 1);
hudakz 0:91392e1f8551 523 }
hudakz 0:91392e1f8551 524 }
hudakz 0:91392e1f8551 525
hudakz 0:91392e1f8551 526 /* Sets the maximum milliseconds to wait for serial data when using SerialPI::readBytes()
hudakz 0:91392e1f8551 527 * The default value is set to 1000 */
hudakz 0:91392e1f8551 528 void Serial::setTimeout(long millis) {
hudakz 0:91392e1f8551 529 timeOut = millis;
hudakz 0:91392e1f8551 530 }
hudakz 0:91392e1f8551 531
hudakz 0:91392e1f8551 532 //Closes serial communication
hudakz 0:91392e1f8551 533 void Serial::close(void) {
hudakz 0:91392e1f8551 534 unistd::close(sd);
hudakz 0:91392e1f8551 535 }
hudakz 0:91392e1f8551 536
hudakz 0:91392e1f8551 537 /*******************
hudakz 0:91392e1f8551 538 * Private methods *
hudakz 0:91392e1f8551 539 *******************/
hudakz 0:91392e1f8551 540
hudakz 0:91392e1f8551 541 //Returns a timespec struct with the time elapsed between start and end timespecs
hudakz 0:91392e1f8551 542 timespec Serial::timeDiff(timespec start, timespec end) {
hudakz 0:91392e1f8551 543 timespec temp;
hudakz 0:91392e1f8551 544 if((end.tv_nsec - start.tv_nsec) < 0) {
hudakz 0:91392e1f8551 545 temp.tv_sec = end.tv_sec - start.tv_sec - 1;
hudakz 0:91392e1f8551 546 temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
hudakz 0:91392e1f8551 547 }
hudakz 0:91392e1f8551 548 else {
hudakz 0:91392e1f8551 549 temp.tv_sec = end.tv_sec - start.tv_sec;
hudakz 0:91392e1f8551 550 temp.tv_nsec = end.tv_nsec - start.tv_nsec;
hudakz 0:91392e1f8551 551 }
hudakz 0:91392e1f8551 552
hudakz 0:91392e1f8551 553 return temp;
hudakz 0:91392e1f8551 554 }
hudakz 0:91392e1f8551 555
hudakz 0:91392e1f8551 556 //Constructor
hudakz 0:91392e1f8551 557 Peripheral::Peripheral(void) {
hudakz 0:91392e1f8551 558 REV = getBoardRev();
hudakz 0:91392e1f8551 559 if(map_peripheral(&gpio) == -1) {
hudakz 0:91392e1f8551 560 printf("Failed to map the physical GPIO registers into the virtual memory space.\n");
hudakz 0:91392e1f8551 561 }
hudakz 0:91392e1f8551 562
hudakz 0:91392e1f8551 563 memfd = -1;
hudakz 0:91392e1f8551 564
hudakz 0:91392e1f8551 565 //i2c_byte_wait_us = 0;
hudakz 0:91392e1f8551 566 // Open the master /dev/memory device
hudakz 0:91392e1f8551 567 if((memfd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
hudakz 0:91392e1f8551 568 fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n", strerror(errno));
hudakz 0:91392e1f8551 569 exit(1);
hudakz 0:91392e1f8551 570 }
hudakz 0:91392e1f8551 571
hudakz 0:91392e1f8551 572 bcm2835_bsc1 = mapmem("bsc1", BLOCK_SIZE, memfd, BCM2835_BSC1_BASE);
hudakz 0:91392e1f8551 573 if(bcm2835_bsc1 == MAP_FAILED)
hudakz 0:91392e1f8551 574 exit(1);
hudakz 0:91392e1f8551 575
hudakz 0:91392e1f8551 576 // start timer
hudakz 0:91392e1f8551 577 gettimeofday(&start_program, NULL);
hudakz 0:91392e1f8551 578 }
hudakz 0:91392e1f8551 579
hudakz 0:91392e1f8551 580 //Destructor
hudakz 0:91392e1f8551 581 Peripheral::~Peripheral(void) {
hudakz 0:91392e1f8551 582 unmap_peripheral(&gpio);
hudakz 0:91392e1f8551 583 }
hudakz 0:91392e1f8551 584
hudakz 0:91392e1f8551 585 /*******************
hudakz 0:91392e1f8551 586 * Private methods *
hudakz 0:91392e1f8551 587 *******************/
hudakz 0:91392e1f8551 588
hudakz 0:91392e1f8551 589 // Exposes the physical address defined in the passed structure using mmap on /dev/mem
hudakz 0:91392e1f8551 590 int Peripheral::map_peripheral(struct bcm2835_peripheral* p) {
hudakz 0:91392e1f8551 591
hudakz 0:91392e1f8551 592 // Open /dev/mem
hudakz 0:91392e1f8551 593 if((p->mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
hudakz 0:91392e1f8551 594 printf("Failed to open /dev/mem, try checking permissions.\n");
hudakz 0:91392e1f8551 595 return -1;
hudakz 0:91392e1f8551 596 }
hudakz 0:91392e1f8551 597
hudakz 0:91392e1f8551 598 p->map = mmap
hudakz 0:91392e1f8551 599 (
hudakz 0:91392e1f8551 600 NULL,
hudakz 0:91392e1f8551 601 BLOCK_SIZE,
hudakz 0:91392e1f8551 602 PROT_READ | PROT_WRITE,
hudakz 0:91392e1f8551 603 MAP_SHARED,
hudakz 0:91392e1f8551 604 p->mem_fd, // File descriptor to physical memory virtual file '/dev/mem'
hudakz 0:91392e1f8551 605 p->addr_p // Address in physical map that we want this memory block to expose
hudakz 0:91392e1f8551 606 );
hudakz 0:91392e1f8551 607
hudakz 0:91392e1f8551 608 if(p->map == MAP_FAILED) {
hudakz 0:91392e1f8551 609 perror("mmap");
hudakz 0:91392e1f8551 610 return -1;
hudakz 0:91392e1f8551 611 }
hudakz 0:91392e1f8551 612
hudakz 0:91392e1f8551 613 p->addr = (volatile unsigned int*)p->map;
hudakz 0:91392e1f8551 614
hudakz 0:91392e1f8551 615 return 0;
hudakz 0:91392e1f8551 616 }
hudakz 0:91392e1f8551 617
hudakz 0:91392e1f8551 618 /**
hudakz 0:91392e1f8551 619 * @brief
hudakz 0:91392e1f8551 620 * @note
hudakz 0:91392e1f8551 621 * @param
hudakz 0:91392e1f8551 622 * @retval
hudakz 0:91392e1f8551 623 */
hudakz 0:91392e1f8551 624 void Peripheral::unmap_peripheral(struct bcm2835_peripheral* p) {
hudakz 0:91392e1f8551 625 munmap(p->map, BLOCK_SIZE);
hudakz 0:91392e1f8551 626 unistd::close(p->mem_fd);
hudakz 0:91392e1f8551 627 }
hudakz 0:91392e1f8551 628
hudakz 0:91392e1f8551 629 //Constructor
hudakz 0:91392e1f8551 630 I2C::I2C(void) {
hudakz 0:91392e1f8551 631
hudakz 0:91392e1f8551 632 // REV = getBoardRev();
hudakz 0:91392e1f8551 633 // if(map_peripheral(&gpio) == -1) {
hudakz 0:91392e1f8551 634 // printf("Failed to map the physical GPIO registers into the virtual memory space.\n");
hudakz 0:91392e1f8551 635 // }
hudakz 0:91392e1f8551 636 // memfd = -1;
hudakz 0:91392e1f8551 637 i2c_byte_wait_us = 0;
hudakz 0:91392e1f8551 638
hudakz 0:91392e1f8551 639 // // Open the master /dev/memory device
hudakz 0:91392e1f8551 640 // if((memfd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
hudakz 0:91392e1f8551 641 // fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n", strerror(errno));
hudakz 0:91392e1f8551 642 // exit(1);
hudakz 0:91392e1f8551 643 // }
hudakz 0:91392e1f8551 644 // bcm2835_bsc1 = mapmem("bsc1", BLOCK_SIZE, memfd, BCM2835_BSC1_BASE);
hudakz 0:91392e1f8551 645 // if(bcm2835_bsc1 == MAP_FAILED)
hudakz 0:91392e1f8551 646 // exit(1);
hudakz 0:91392e1f8551 647 // // start timer
hudakz 0:91392e1f8551 648 // gettimeofday(&start_program, NULL);
hudakz 0:91392e1f8551 649 }
hudakz 0:91392e1f8551 650
hudakz 0:91392e1f8551 651 //Initiate the Wire library and join the I2C bus.
hudakz 0:91392e1f8551 652 void I2C::begin(void) {
hudakz 0:91392e1f8551 653 volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV / 4;
hudakz 0:91392e1f8551 654
hudakz 0:91392e1f8551 655 // Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them
hudakz 0:91392e1f8551 656 bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); // SDA
hudakz 0:91392e1f8551 657 bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); // SCL
hudakz 0:91392e1f8551 658
hudakz 0:91392e1f8551 659 // Read the clock divider register
hudakz 0:91392e1f8551 660 uint16_t cdiv = bcm2835_peri_read(paddr);
hudakz 0:91392e1f8551 661
hudakz 0:91392e1f8551 662 // Calculate time for transmitting one byte
hudakz 0:91392e1f8551 663 // 1000000 = micros seconds in a second
hudakz 0:91392e1f8551 664 // 9 = Clocks per byte : 8 bits + ACK
hudakz 0:91392e1f8551 665 i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9;
hudakz 0:91392e1f8551 666 }
hudakz 0:91392e1f8551 667
hudakz 0:91392e1f8551 668 //Begin a transmission to the I2C slave device with the given address
hudakz 0:91392e1f8551 669 void I2C::beginTransmission(unsigned char address) {
hudakz 0:91392e1f8551 670
hudakz 0:91392e1f8551 671 // Set I2C Device Address
hudakz 0:91392e1f8551 672 volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A / 4;
hudakz 0:91392e1f8551 673 bcm2835_peri_write(paddr, address);
hudakz 0:91392e1f8551 674 }
hudakz 0:91392e1f8551 675
hudakz 0:91392e1f8551 676 //Writes data to the I2C.
hudakz 0:91392e1f8551 677 void I2C::write(char data) {
hudakz 0:91392e1f8551 678 char i2cdata[1];
hudakz 0:91392e1f8551 679 i2cdata[0] = data;
hudakz 0:91392e1f8551 680
hudakz 0:91392e1f8551 681 write(i2cdata, 1);
hudakz 0:91392e1f8551 682 }
hudakz 0:91392e1f8551 683
hudakz 0:91392e1f8551 684 //Writes data to the I2C.
hudakz 0:91392e1f8551 685 uint8_t I2C::write(const char* buf, uint32_t len) {
hudakz 0:91392e1f8551 686 volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN / 4;
hudakz 0:91392e1f8551 687 volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO / 4;
hudakz 0:91392e1f8551 688 volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S / 4;
hudakz 0:91392e1f8551 689 volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C / 4;
hudakz 0:91392e1f8551 690
hudakz 0:91392e1f8551 691 uint32_t remaining = len;
hudakz 0:91392e1f8551 692 uint32_t i = 0;
hudakz 0:91392e1f8551 693 uint8_t reason = BCM2835_I2C_REASON_OK;
hudakz 0:91392e1f8551 694
hudakz 0:91392e1f8551 695 // Clear FIFO
hudakz 0:91392e1f8551 696 bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1, BCM2835_BSC_C_CLEAR_1);
hudakz 0:91392e1f8551 697
hudakz 0:91392e1f8551 698 // Clear Status
hudakz 0:91392e1f8551 699 bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE);
hudakz 0:91392e1f8551 700
hudakz 0:91392e1f8551 701 // Set Data Length
hudakz 0:91392e1f8551 702 bcm2835_peri_write_nb(dlen, len);
hudakz 0:91392e1f8551 703
hudakz 0:91392e1f8551 704 // pre populate FIFO with max buffer
hudakz 0:91392e1f8551 705 while(remaining && (i < BCM2835_BSC_FIFO_SIZE)) {
hudakz 0:91392e1f8551 706 bcm2835_peri_write_nb(fifo, buf[i]);
hudakz 0:91392e1f8551 707 i++;
hudakz 0:91392e1f8551 708 remaining--;
hudakz 0:91392e1f8551 709 }
hudakz 0:91392e1f8551 710
hudakz 0:91392e1f8551 711 // Enable device and start transfer
hudakz 0:91392e1f8551 712 bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST);
hudakz 0:91392e1f8551 713
hudakz 0:91392e1f8551 714 // Transfer is over when BCM2835_BSC_S_DONE
hudakz 0:91392e1f8551 715 while(!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) {
hudakz 0:91392e1f8551 716 while(remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_TXD)) {
hudakz 0:91392e1f8551 717
hudakz 0:91392e1f8551 718 // Write to FIFO, no barrier
hudakz 0:91392e1f8551 719 bcm2835_peri_write_nb(fifo, buf[i]);
hudakz 0:91392e1f8551 720 i++;
hudakz 0:91392e1f8551 721 remaining--;
hudakz 0:91392e1f8551 722 }
hudakz 0:91392e1f8551 723 }
hudakz 0:91392e1f8551 724
hudakz 0:91392e1f8551 725 // Received a NACK
hudakz 0:91392e1f8551 726 if(bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) {
hudakz 0:91392e1f8551 727 reason = BCM2835_I2C_REASON_ERROR_NACK;
hudakz 0:91392e1f8551 728 }
hudakz 0:91392e1f8551 729
hudakz 0:91392e1f8551 730 // Received Clock Stretch Timeout
hudakz 0:91392e1f8551 731 else
hudakz 0:91392e1f8551 732 if(bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) {
hudakz 0:91392e1f8551 733 reason = BCM2835_I2C_REASON_ERROR_CLKT;
hudakz 0:91392e1f8551 734 }
hudakz 0:91392e1f8551 735
hudakz 0:91392e1f8551 736 // Not all data is sent
hudakz 0:91392e1f8551 737 else
hudakz 0:91392e1f8551 738 if(remaining) {
hudakz 0:91392e1f8551 739 reason = BCM2835_I2C_REASON_ERROR_DATA;
hudakz 0:91392e1f8551 740 }
hudakz 0:91392e1f8551 741
hudakz 0:91392e1f8551 742 bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE, BCM2835_BSC_S_DONE);
hudakz 0:91392e1f8551 743
hudakz 0:91392e1f8551 744 return reason;
hudakz 0:91392e1f8551 745 }
hudakz 0:91392e1f8551 746
hudakz 0:91392e1f8551 747 /**
hudakz 0:91392e1f8551 748 * @brief
hudakz 0:91392e1f8551 749 * @note
hudakz 0:91392e1f8551 750 * @param
hudakz 0:91392e1f8551 751 * @retval
hudakz 0:91392e1f8551 752 */
hudakz 0:91392e1f8551 753 void I2C::endTransmission(void) {
hudakz 0:91392e1f8551 754
hudakz 0:91392e1f8551 755 // Set all the I2C/BSC1 pins back to input
hudakz 0:91392e1f8551 756 bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); // SDA
hudakz 0:91392e1f8551 757 bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); // SCL
hudakz 0:91392e1f8551 758 }
hudakz 0:91392e1f8551 759
hudakz 0:91392e1f8551 760 //Used by the master to request bytes from a slave device
hudakz 0:91392e1f8551 761 void I2C::requestFrom(unsigned char address, int quantity) {
hudakz 0:91392e1f8551 762
hudakz 0:91392e1f8551 763 // Set I2C Device Address
hudakz 0:91392e1f8551 764 volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A / 4;
hudakz 0:91392e1f8551 765 bcm2835_peri_write(paddr, address);
hudakz 0:91392e1f8551 766
hudakz 0:91392e1f8551 767 i2c_bytes_to_read = quantity;
hudakz 0:91392e1f8551 768 }
hudakz 0:91392e1f8551 769
hudakz 0:91392e1f8551 770 //Reads a byte that was transmitted from a slave device to a master after a call to WirePi::requestFrom()
hudakz 0:91392e1f8551 771 unsigned char I2C::read(void) {
hudakz 0:91392e1f8551 772 char buf;
hudakz 0:91392e1f8551 773 i2c_bytes_to_read = 1;
hudakz 0:91392e1f8551 774 read(&buf);
hudakz 0:91392e1f8551 775 return (unsigned char)buf;
hudakz 0:91392e1f8551 776 }
hudakz 0:91392e1f8551 777
hudakz 0:91392e1f8551 778 /**
hudakz 0:91392e1f8551 779 * @brief
hudakz 0:91392e1f8551 780 * @note
hudakz 0:91392e1f8551 781 * @param
hudakz 0:91392e1f8551 782 * @retval
hudakz 0:91392e1f8551 783 */
hudakz 0:91392e1f8551 784 uint8_t I2C::read(char* buf) {
hudakz 0:91392e1f8551 785 volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN / 4;
hudakz 0:91392e1f8551 786 volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO / 4;
hudakz 0:91392e1f8551 787 volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S / 4;
hudakz 0:91392e1f8551 788 volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C / 4;
hudakz 0:91392e1f8551 789
hudakz 0:91392e1f8551 790 uint32_t remaining = i2c_bytes_to_read;
hudakz 0:91392e1f8551 791 uint32_t i = 0;
hudakz 0:91392e1f8551 792 uint8_t reason = BCM2835_I2C_REASON_OK;
hudakz 0:91392e1f8551 793
hudakz 0:91392e1f8551 794 // Clear FIFO
hudakz 0:91392e1f8551 795 bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1, BCM2835_BSC_C_CLEAR_1);
hudakz 0:91392e1f8551 796
hudakz 0:91392e1f8551 797 // Clear Status
hudakz 0:91392e1f8551 798 bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE);
hudakz 0:91392e1f8551 799
hudakz 0:91392e1f8551 800 // Set Data Length
hudakz 0:91392e1f8551 801 bcm2835_peri_write_nb(dlen, i2c_bytes_to_read);
hudakz 0:91392e1f8551 802
hudakz 0:91392e1f8551 803 // Start read
hudakz 0:91392e1f8551 804 bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ);
hudakz 0:91392e1f8551 805
hudakz 0:91392e1f8551 806 // wait for transfer to complete
hudakz 0:91392e1f8551 807 while(!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) {
hudakz 0:91392e1f8551 808
hudakz 0:91392e1f8551 809 // we must empty the FIFO as it is populated and not use any delay
hudakz 0:91392e1f8551 810 while(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) {
hudakz 0:91392e1f8551 811
hudakz 0:91392e1f8551 812 // Read from FIFO, no barrier
hudakz 0:91392e1f8551 813 buf[i] = bcm2835_peri_read_nb(fifo);
hudakz 0:91392e1f8551 814 i++;
hudakz 0:91392e1f8551 815 remaining--;
hudakz 0:91392e1f8551 816 }
hudakz 0:91392e1f8551 817 }
hudakz 0:91392e1f8551 818
hudakz 0:91392e1f8551 819 // transfer has finished - grab any remaining stuff in FIFO
hudakz 0:91392e1f8551 820 while(remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) {
hudakz 0:91392e1f8551 821
hudakz 0:91392e1f8551 822 // Read from FIFO, no barrier
hudakz 0:91392e1f8551 823 buf[i] = bcm2835_peri_read_nb(fifo);
hudakz 0:91392e1f8551 824 i++;
hudakz 0:91392e1f8551 825 remaining--;
hudakz 0:91392e1f8551 826 }
hudakz 0:91392e1f8551 827
hudakz 0:91392e1f8551 828 // Received a NACK
hudakz 0:91392e1f8551 829 if(bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) {
hudakz 0:91392e1f8551 830 reason = BCM2835_I2C_REASON_ERROR_NACK;
hudakz 0:91392e1f8551 831 }
hudakz 0:91392e1f8551 832
hudakz 0:91392e1f8551 833 // Received Clock Stretch Timeout
hudakz 0:91392e1f8551 834 else
hudakz 0:91392e1f8551 835 if(bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) {
hudakz 0:91392e1f8551 836 reason = BCM2835_I2C_REASON_ERROR_CLKT;
hudakz 0:91392e1f8551 837 }
hudakz 0:91392e1f8551 838
hudakz 0:91392e1f8551 839 // Not all data is received
hudakz 0:91392e1f8551 840 else
hudakz 0:91392e1f8551 841 if(remaining) {
hudakz 0:91392e1f8551 842 reason = BCM2835_I2C_REASON_ERROR_DATA;
hudakz 0:91392e1f8551 843 }
hudakz 0:91392e1f8551 844
hudakz 0:91392e1f8551 845 bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE, BCM2835_BSC_S_DONE);
hudakz 0:91392e1f8551 846
hudakz 0:91392e1f8551 847 return reason;
hudakz 0:91392e1f8551 848 }
hudakz 0:91392e1f8551 849
hudakz 0:91392e1f8551 850 // Read an number of bytes from I2C sending a repeated start after writing
hudakz 0:91392e1f8551 851
hudakz 0:91392e1f8551 852 // the required register. Only works if your device supports this mode
hudakz 0:91392e1f8551 853 uint8_t I2C::read_rs(char* regaddr, char* buf, uint32_t len) {
hudakz 0:91392e1f8551 854 volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN / 4;
hudakz 0:91392e1f8551 855 volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO / 4;
hudakz 0:91392e1f8551 856 volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S / 4;
hudakz 0:91392e1f8551 857 volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C / 4;
hudakz 0:91392e1f8551 858
hudakz 0:91392e1f8551 859 uint32_t remaining = len;
hudakz 0:91392e1f8551 860 uint32_t i = 0;
hudakz 0:91392e1f8551 861 uint8_t reason = BCM2835_I2C_REASON_OK;
hudakz 0:91392e1f8551 862
hudakz 0:91392e1f8551 863 // Clear FIFO
hudakz 0:91392e1f8551 864 bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1, BCM2835_BSC_C_CLEAR_1);
hudakz 0:91392e1f8551 865
hudakz 0:91392e1f8551 866 // Clear Status
hudakz 0:91392e1f8551 867 bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE);
hudakz 0:91392e1f8551 868
hudakz 0:91392e1f8551 869 // Set Data Length
hudakz 0:91392e1f8551 870 bcm2835_peri_write_nb(dlen, 1);
hudakz 0:91392e1f8551 871
hudakz 0:91392e1f8551 872 // Enable device and start transfer
hudakz 0:91392e1f8551 873 bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN);
hudakz 0:91392e1f8551 874 bcm2835_peri_write_nb(fifo, regaddr[0]);
hudakz 0:91392e1f8551 875 bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST);
hudakz 0:91392e1f8551 876
hudakz 0:91392e1f8551 877 // poll for transfer has started
hudakz 0:91392e1f8551 878 while(!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_TA)) {
hudakz 0:91392e1f8551 879
hudakz 0:91392e1f8551 880 // Linux may cause us to miss entire transfer stage
hudakz 0:91392e1f8551 881 if(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE)
hudakz 0:91392e1f8551 882 break;
hudakz 0:91392e1f8551 883 }
hudakz 0:91392e1f8551 884
hudakz 0:91392e1f8551 885 // Send a repeated start with read bit set in address
hudakz 0:91392e1f8551 886 bcm2835_peri_write_nb(dlen, len);
hudakz 0:91392e1f8551 887 bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ);
hudakz 0:91392e1f8551 888
hudakz 0:91392e1f8551 889 // Wait for write to complete and first byte back.
hudakz 0:91392e1f8551 890 wait_us(i2c_byte_wait_us * 3);
hudakz 0:91392e1f8551 891
hudakz 0:91392e1f8551 892 // wait for transfer to complete
hudakz 0:91392e1f8551 893 while(!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) {
hudakz 0:91392e1f8551 894
hudakz 0:91392e1f8551 895 // we must empty the FIFO as it is populated and not use any delay
hudakz 0:91392e1f8551 896 while(remaining && bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) {
hudakz 0:91392e1f8551 897
hudakz 0:91392e1f8551 898 // Read from FIFO, no barrier
hudakz 0:91392e1f8551 899 buf[i] = bcm2835_peri_read_nb(fifo);
hudakz 0:91392e1f8551 900 i++;
hudakz 0:91392e1f8551 901 remaining--;
hudakz 0:91392e1f8551 902 }
hudakz 0:91392e1f8551 903 }
hudakz 0:91392e1f8551 904
hudakz 0:91392e1f8551 905 // transfer has finished - grab any remaining stuff in FIFO
hudakz 0:91392e1f8551 906 while(remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) {
hudakz 0:91392e1f8551 907
hudakz 0:91392e1f8551 908 // Read from FIFO, no barrier
hudakz 0:91392e1f8551 909 buf[i] = bcm2835_peri_read_nb(fifo);
hudakz 0:91392e1f8551 910 i++;
hudakz 0:91392e1f8551 911 remaining--;
hudakz 0:91392e1f8551 912 }
hudakz 0:91392e1f8551 913
hudakz 0:91392e1f8551 914 // Received a NACK
hudakz 0:91392e1f8551 915 if(bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) {
hudakz 0:91392e1f8551 916 reason = BCM2835_I2C_REASON_ERROR_NACK;
hudakz 0:91392e1f8551 917 }
hudakz 0:91392e1f8551 918
hudakz 0:91392e1f8551 919 // Received Clock Stretch Timeout
hudakz 0:91392e1f8551 920 else
hudakz 0:91392e1f8551 921 if(bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) {
hudakz 0:91392e1f8551 922 reason = BCM2835_I2C_REASON_ERROR_CLKT;
hudakz 0:91392e1f8551 923 }
hudakz 0:91392e1f8551 924
hudakz 0:91392e1f8551 925 // Not all data is sent
hudakz 0:91392e1f8551 926 else
hudakz 0:91392e1f8551 927 if(remaining) {
hudakz 0:91392e1f8551 928 reason = BCM2835_I2C_REASON_ERROR_DATA;
hudakz 0:91392e1f8551 929 }
hudakz 0:91392e1f8551 930
hudakz 0:91392e1f8551 931 bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE, BCM2835_BSC_S_DONE);
hudakz 0:91392e1f8551 932
hudakz 0:91392e1f8551 933 return reason;
hudakz 0:91392e1f8551 934 }
hudakz 0:91392e1f8551 935
hudakz 0:91392e1f8551 936 /*******************
hudakz 0:91392e1f8551 937 * Private methods *
hudakz 0:91392e1f8551 938 *******************/
hudakz 0:91392e1f8551 939
hudakz 0:91392e1f8551 940 /**
hudakz 0:91392e1f8551 941 * @brief
hudakz 0:91392e1f8551 942 * @note
hudakz 0:91392e1f8551 943 * @param
hudakz 0:91392e1f8551 944 * @retval
hudakz 0:91392e1f8551 945 */
hudakz 0:91392e1f8551 946 void I2C::wait_i2c_done(void) {
hudakz 0:91392e1f8551 947
hudakz 0:91392e1f8551 948 //Wait till done, let's use a timeout just in case
hudakz 0:91392e1f8551 949 int timeout = 50;
hudakz 0:91392e1f8551 950 while((!((BSC0_S) & BSC_S_DONE)) && --timeout) {
hudakz 0:91392e1f8551 951 unistd::usleep(1000);
hudakz 0:91392e1f8551 952 }
hudakz 0:91392e1f8551 953
hudakz 0:91392e1f8551 954 if(timeout == 0)
hudakz 0:91392e1f8551 955 printf("wait_i2c_done() timeout. Something went wrong.\n");
hudakz 0:91392e1f8551 956 }
hudakz 0:91392e1f8551 957
hudakz 0:91392e1f8551 958 /*******************************
hudakz 0:91392e1f8551 959 * *
hudakz 0:91392e1f8551 960 * SPIPi Class implementation *
hudakz 0:91392e1f8551 961 * --------------------------- *
hudakz 0:91392e1f8551 962 *******************************/
hudakz 0:91392e1f8551 963
hudakz 0:91392e1f8551 964 /******************
hudakz 0:91392e1f8551 965 * Public methods *
hudakz 0:91392e1f8551 966 ******************/
hudakz 0:91392e1f8551 967 SPI::SPI(void) {
hudakz 0:91392e1f8551 968 REV = getBoardRev();
hudakz 0:91392e1f8551 969
hudakz 0:91392e1f8551 970 uint8_t* mapaddr;
hudakz 0:91392e1f8551 971
hudakz 0:91392e1f8551 972 if((spi0Mem = (uint8_t*)malloc(BLOCK_SIZE + (PAGESIZE - 1))) == NULL) {
hudakz 0:91392e1f8551 973 fprintf(stderr, "bcm2835_init: spi0Mem malloc failed: %s\n", strerror(errno));
hudakz 0:91392e1f8551 974 exit(1);
hudakz 0:91392e1f8551 975 }
hudakz 0:91392e1f8551 976
hudakz 0:91392e1f8551 977 mapaddr = spi0Mem;
hudakz 0:91392e1f8551 978 if(((uint32_t) mapaddr % PAGESIZE) != 0)
hudakz 0:91392e1f8551 979 mapaddr += PAGESIZE - ((uint32_t) mapaddr % PAGESIZE);
hudakz 0:91392e1f8551 980
hudakz 0:91392e1f8551 981 spi0 = (uint32_t*)mmap
hudakz 0:91392e1f8551 982 (
hudakz 0:91392e1f8551 983 mapaddr,
hudakz 0:91392e1f8551 984 BLOCK_SIZE,
hudakz 0:91392e1f8551 985 PROT_READ | PROT_WRITE,
hudakz 0:91392e1f8551 986 MAP_SHARED | MAP_FIXED,
hudakz 0:91392e1f8551 987 gpio.mem_fd,
hudakz 0:91392e1f8551 988 BCM2835_SPI0_BASE
hudakz 0:91392e1f8551 989 );
hudakz 0:91392e1f8551 990
hudakz 0:91392e1f8551 991 if((int32_t) spi0 < 0) {
hudakz 0:91392e1f8551 992 fprintf(stderr, "bcm2835_init: mmap failed (spi0): %s\n", strerror(errno));
hudakz 0:91392e1f8551 993 exit(1);
hudakz 0:91392e1f8551 994 }
hudakz 0:91392e1f8551 995 }
hudakz 0:91392e1f8551 996
hudakz 0:91392e1f8551 997 /**
hudakz 0:91392e1f8551 998 * @brief
hudakz 0:91392e1f8551 999 * @note
hudakz 0:91392e1f8551 1000 * @param
hudakz 0:91392e1f8551 1001 * @retval
hudakz 0:91392e1f8551 1002 */
hudakz 0:91392e1f8551 1003 void SPI::begin(void) {
hudakz 0:91392e1f8551 1004
hudakz 0:91392e1f8551 1005 // Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them
hudakz 0:91392e1f8551 1006 bcm2835_gpio_fsel(7, BCM2835_GPIO_FSEL_ALT0); // CE1
hudakz 0:91392e1f8551 1007 bcm2835_gpio_fsel(8, BCM2835_GPIO_FSEL_ALT0); // CE0
hudakz 0:91392e1f8551 1008 bcm2835_gpio_fsel(9, BCM2835_GPIO_FSEL_ALT0); // MISO
hudakz 0:91392e1f8551 1009 bcm2835_gpio_fsel(10, BCM2835_GPIO_FSEL_ALT0); // MOSI
hudakz 0:91392e1f8551 1010 bcm2835_gpio_fsel(11, BCM2835_GPIO_FSEL_ALT0); // CLK
hudakz 0:91392e1f8551 1011
hudakz 0:91392e1f8551 1012 // Set the SPI CS register to the some sensible defaults
hudakz 0:91392e1f8551 1013 volatile uint32_t* paddr = (volatile uint32_t*)spi0 + BCM2835_SPI0_CS / 4;
hudakz 0:91392e1f8551 1014 bcm2835_peri_write(paddr, 0); // All 0s
hudakz 0:91392e1f8551 1015
hudakz 0:91392e1f8551 1016 // Clear TX and RX fifos
hudakz 0:91392e1f8551 1017 bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR);
hudakz 0:91392e1f8551 1018 }
hudakz 0:91392e1f8551 1019
hudakz 0:91392e1f8551 1020 /**
hudakz 0:91392e1f8551 1021 * @brief
hudakz 0:91392e1f8551 1022 * @note
hudakz 0:91392e1f8551 1023 * @param
hudakz 0:91392e1f8551 1024 * @retval
hudakz 0:91392e1f8551 1025 */
hudakz 0:91392e1f8551 1026 void SPI::end(void) {
hudakz 0:91392e1f8551 1027
hudakz 0:91392e1f8551 1028 // Set all the SPI0 pins back to input
hudakz 0:91392e1f8551 1029 bcm2835_gpio_fsel(7, BCM2835_GPIO_FSEL_INPT); // CE1
hudakz 0:91392e1f8551 1030 bcm2835_gpio_fsel(8, BCM2835_GPIO_FSEL_INPT); // CE0
hudakz 0:91392e1f8551 1031 bcm2835_gpio_fsel(9, BCM2835_GPIO_FSEL_INPT); // MISO
hudakz 0:91392e1f8551 1032 bcm2835_gpio_fsel(10, BCM2835_GPIO_FSEL_INPT); // MOSI
hudakz 0:91392e1f8551 1033 bcm2835_gpio_fsel(11, BCM2835_GPIO_FSEL_INPT); // CLK
hudakz 0:91392e1f8551 1034 }
hudakz 0:91392e1f8551 1035
hudakz 0:91392e1f8551 1036 /**
hudakz 0:91392e1f8551 1037 * @brief
hudakz 0:91392e1f8551 1038 * @note
hudakz 0:91392e1f8551 1039 * @param
hudakz 0:91392e1f8551 1040 * @retval
hudakz 0:91392e1f8551 1041 */
hudakz 0:91392e1f8551 1042 void SPI::setBitOrder(uint8_t order) {
hudakz 0:91392e1f8551 1043
hudakz 0:91392e1f8551 1044 // BCM2835_SPI_BIT_ORDER_MSBFIRST is the only one suported by SPI0
hudakz 0:91392e1f8551 1045 }
hudakz 0:91392e1f8551 1046
hudakz 0:91392e1f8551 1047 // defaults to 0, which means a divider of 65536.
hudakz 0:91392e1f8551 1048 // The divisor must be a power of 2. Odd numbers
hudakz 0:91392e1f8551 1049 // rounded down. The maximum SPI clock rate is
hudakz 0:91392e1f8551 1050
hudakz 0:91392e1f8551 1051 // of the APB clock
hudakz 0:91392e1f8551 1052 void SPI::setClockDivider(uint16_t divider) {
hudakz 0:91392e1f8551 1053 volatile uint32_t* paddr = (volatile uint32_t*)spi0 + BCM2835_SPI0_CLK / 4;
hudakz 0:91392e1f8551 1054 bcm2835_peri_write(paddr, divider);
hudakz 0:91392e1f8551 1055 }
hudakz 0:91392e1f8551 1056
hudakz 0:91392e1f8551 1057 /**
hudakz 0:91392e1f8551 1058 * @brief
hudakz 0:91392e1f8551 1059 * @note
hudakz 0:91392e1f8551 1060 * @param
hudakz 0:91392e1f8551 1061 * @retval
hudakz 0:91392e1f8551 1062 */
hudakz 0:91392e1f8551 1063 void SPI::setDataMode(uint8_t mode) {
hudakz 0:91392e1f8551 1064 volatile uint32_t* paddr = (volatile uint32_t*)spi0 + BCM2835_SPI0_CS / 4;
hudakz 0:91392e1f8551 1065
hudakz 0:91392e1f8551 1066 // Mask in the CPO and CPHA bits of CS
hudakz 0:91392e1f8551 1067 bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA);
hudakz 0:91392e1f8551 1068 }
hudakz 0:91392e1f8551 1069
hudakz 0:91392e1f8551 1070 // Writes (and reads) a single byte to SPI
hudakz 0:91392e1f8551 1071 uint8_t SPI::transfer(uint8_t value) {
hudakz 0:91392e1f8551 1072 volatile uint32_t* paddr = (volatile uint32_t*)spi0 + BCM2835_SPI0_CS / 4;
hudakz 0:91392e1f8551 1073 volatile uint32_t* fifo = (volatile uint32_t*)spi0 + BCM2835_SPI0_FIFO / 4;
hudakz 0:91392e1f8551 1074
hudakz 0:91392e1f8551 1075 bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR);
hudakz 0:91392e1f8551 1076
hudakz 0:91392e1f8551 1077 bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA);
hudakz 0:91392e1f8551 1078
hudakz 0:91392e1f8551 1079 while(!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))
hudakz 0:91392e1f8551 1080 wait_us(10);
hudakz 0:91392e1f8551 1081
hudakz 0:91392e1f8551 1082 bcm2835_peri_write_nb(fifo, value);
hudakz 0:91392e1f8551 1083
hudakz 0:91392e1f8551 1084 while(!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
hudakz 0:91392e1f8551 1085 wait_us(10);
hudakz 0:91392e1f8551 1086
hudakz 0:91392e1f8551 1087 uint32_t ret = bcm2835_peri_read_nb(fifo);
hudakz 0:91392e1f8551 1088
hudakz 0:91392e1f8551 1089 bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
hudakz 0:91392e1f8551 1090
hudakz 0:91392e1f8551 1091 return ret;
hudakz 0:91392e1f8551 1092 }
hudakz 0:91392e1f8551 1093
hudakz 0:91392e1f8551 1094 // Writes (and reads) a number of bytes to SPI
hudakz 0:91392e1f8551 1095 void SPI::transfernb(char* tbuf, char* rbuf, uint32_t len) {
hudakz 0:91392e1f8551 1096 volatile uint32_t* paddr = (volatile uint32_t*)spi0 + BCM2835_SPI0_CS / 4;
hudakz 0:91392e1f8551 1097 volatile uint32_t* fifo = (volatile uint32_t*)spi0 + BCM2835_SPI0_FIFO / 4;
hudakz 0:91392e1f8551 1098
hudakz 0:91392e1f8551 1099 // This is Polled transfer as per section 10.6.1
hudakz 0:91392e1f8551 1100 // BUG ALERT: what happens if we get interupted in this section, and someone else
hudakz 0:91392e1f8551 1101 // accesses a different peripheral?
hudakz 0:91392e1f8551 1102 // Clear TX and RX fifos
hudakz 0:91392e1f8551 1103 bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR);
hudakz 0:91392e1f8551 1104
hudakz 0:91392e1f8551 1105 // Set TA = 1
hudakz 0:91392e1f8551 1106 bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA);
hudakz 0:91392e1f8551 1107
hudakz 0:91392e1f8551 1108 uint32_t i;
hudakz 0:91392e1f8551 1109 for(i = 0; i < len; i++) {
hudakz 0:91392e1f8551 1110
hudakz 0:91392e1f8551 1111 // Maybe wait for TXD
hudakz 0:91392e1f8551 1112 while(!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))
hudakz 0:91392e1f8551 1113 wait_us(10);
hudakz 0:91392e1f8551 1114
hudakz 0:91392e1f8551 1115 // Write to FIFO, no barrier
hudakz 0:91392e1f8551 1116 bcm2835_peri_write_nb(fifo, tbuf[i]);
hudakz 0:91392e1f8551 1117
hudakz 0:91392e1f8551 1118 // Wait for RXD
hudakz 0:91392e1f8551 1119 while(!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))
hudakz 0:91392e1f8551 1120 wait_us(10);
hudakz 0:91392e1f8551 1121
hudakz 0:91392e1f8551 1122 // then read the data byte
hudakz 0:91392e1f8551 1123 rbuf[i] = bcm2835_peri_read_nb(fifo);
hudakz 0:91392e1f8551 1124 }
hudakz 0:91392e1f8551 1125
hudakz 0:91392e1f8551 1126 // Wait for DONE to be set
hudakz 0:91392e1f8551 1127 while(!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
hudakz 0:91392e1f8551 1128 wait_us(10);
hudakz 0:91392e1f8551 1129
hudakz 0:91392e1f8551 1130 // Set TA = 0, and also set the barrier
hudakz 0:91392e1f8551 1131 bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
hudakz 0:91392e1f8551 1132 }
hudakz 0:91392e1f8551 1133
hudakz 0:91392e1f8551 1134 /**
hudakz 0:91392e1f8551 1135 * @brief
hudakz 0:91392e1f8551 1136 * @note
hudakz 0:91392e1f8551 1137 * @param
hudakz 0:91392e1f8551 1138 * @retval
hudakz 0:91392e1f8551 1139 */
hudakz 0:91392e1f8551 1140 void SPI::chipSelect(uint8_t cs) {
hudakz 0:91392e1f8551 1141 volatile uint32_t* paddr = (volatile uint32_t*)spi0 + BCM2835_SPI0_CS / 4;
hudakz 0:91392e1f8551 1142
hudakz 0:91392e1f8551 1143 // Mask in the CS bits of CS
hudakz 0:91392e1f8551 1144 bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS);
hudakz 0:91392e1f8551 1145 }
hudakz 0:91392e1f8551 1146
hudakz 0:91392e1f8551 1147 /**
hudakz 0:91392e1f8551 1148 * @brief
hudakz 0:91392e1f8551 1149 * @note
hudakz 0:91392e1f8551 1150 * @param
hudakz 0:91392e1f8551 1151 * @retval
hudakz 0:91392e1f8551 1152 */
hudakz 0:91392e1f8551 1153 void SPI::setChipSelectPolarity(uint8_t cs, uint8_t active) {
hudakz 0:91392e1f8551 1154 volatile uint32_t* paddr = (volatile uint32_t*)spi0 + BCM2835_SPI0_CS / 4;
hudakz 0:91392e1f8551 1155 uint8_t shift = 21 + cs;
hudakz 0:91392e1f8551 1156
hudakz 0:91392e1f8551 1157 // Mask in the appropriate CSPOLn bit
hudakz 0:91392e1f8551 1158 bcm2835_peri_set_bits(paddr, active << shift, 1 << shift);
hudakz 0:91392e1f8551 1159 }
hudakz 0:91392e1f8551 1160
hudakz 0:91392e1f8551 1161 /********** FUNCTIONS OUTSIDE CLASSES **********/
hudakz 0:91392e1f8551 1162
hudakz 0:91392e1f8551 1163 // Write a HIGH or a LOW value to a digital pin
hudakz 0:91392e1f8551 1164 void gpio_write(PinName pin, int value) {
hudakz 0:91392e1f8551 1165 if(value == HIGH)
hudakz 0:91392e1f8551 1166 GPSET0 = (1 << pin);
hudakz 0:91392e1f8551 1167 else
hudakz 0:91392e1f8551 1168 if(value == LOW)
hudakz 0:91392e1f8551 1169 GPCLR0 = (1 << pin);
hudakz 0:91392e1f8551 1170
hudakz 0:91392e1f8551 1171 wait_us(1); // Delay to allow any change in state to be reflected in the LEVn, register bit.
hudakz 0:91392e1f8551 1172 }
hudakz 0:91392e1f8551 1173
hudakz 0:91392e1f8551 1174 // Reads the value from a specified digital pin, either HIGH or LOW.
hudakz 0:91392e1f8551 1175 int gpio_read(PinName pin) {
hudakz 0:91392e1f8551 1176 Digivalue value;
hudakz 0:91392e1f8551 1177 if(GPLEV0 & (1 << pin))
hudakz 0:91392e1f8551 1178 value = HIGH;
hudakz 0:91392e1f8551 1179 else
hudakz 0:91392e1f8551 1180 value = LOW;
hudakz 0:91392e1f8551 1181
hudakz 0:91392e1f8551 1182 return value;
hudakz 0:91392e1f8551 1183 }
hudakz 0:91392e1f8551 1184
hudakz 0:91392e1f8551 1185 /**
hudakz 0:91392e1f8551 1186 * @brief
hudakz 0:91392e1f8551 1187 * @note
hudakz 0:91392e1f8551 1188 * @param
hudakz 0:91392e1f8551 1189 * @retval
hudakz 0:91392e1f8551 1190 */
hudakz 0:91392e1f8551 1191 long us_ticker_read(void) {
hudakz 0:91392e1f8551 1192 long elapsedTime;
hudakz 0:91392e1f8551 1193
hudakz 0:91392e1f8551 1194 // stop timer
hudakz 0:91392e1f8551 1195 gettimeofday(&end_point, NULL);
hudakz 0:91392e1f8551 1196
hudakz 0:91392e1f8551 1197 // compute and print the elapsed time in microseconds
hudakz 0:91392e1f8551 1198 //elapsedTime = (end_point.tv_sec - start_program.tv_sec) * 1000000.0; // sec to us
hudakz 0:91392e1f8551 1199 elapsedTime += (end_point.tv_usec - start_program.tv_usec);
hudakz 0:91392e1f8551 1200 return elapsedTime;
hudakz 0:91392e1f8551 1201 }
hudakz 0:91392e1f8551 1202
hudakz 0:91392e1f8551 1203 /* Some helper functions */
hudakz 0:91392e1f8551 1204 int getBoardRev(void) {
hudakz 0:91392e1f8551 1205 FILE* cpu_info;
hudakz 0:91392e1f8551 1206 char line[120];
hudakz 0:91392e1f8551 1207 char* c, finalChar;
hudakz 0:91392e1f8551 1208 static int rev = 0;
hudakz 0:91392e1f8551 1209
hudakz 0:91392e1f8551 1210 if(REV != 0)
hudakz 0:91392e1f8551 1211 return REV;
hudakz 0:91392e1f8551 1212
hudakz 0:91392e1f8551 1213 if((cpu_info = fopen("/proc/cpuinfo", "r")) == NULL) {
hudakz 0:91392e1f8551 1214 fprintf(stderr, "Unable to open /proc/cpuinfo. Cannot determine board reivision.\n");
hudakz 0:91392e1f8551 1215 exit(1);
hudakz 0:91392e1f8551 1216 }
hudakz 0:91392e1f8551 1217
hudakz 0:91392e1f8551 1218 while(fgets(line, 120, cpu_info) != NULL) {
hudakz 0:91392e1f8551 1219 if(strncmp(line, "Revision", 8) == 0)
hudakz 0:91392e1f8551 1220 break;
hudakz 0:91392e1f8551 1221 }
hudakz 0:91392e1f8551 1222
hudakz 0:91392e1f8551 1223 fclose(cpu_info);
hudakz 0:91392e1f8551 1224
hudakz 0:91392e1f8551 1225 if(line == NULL) {
hudakz 0:91392e1f8551 1226 fprintf(stderr, "Unable to determine board revision from /proc/cpuinfo.\n");
hudakz 0:91392e1f8551 1227 exit(1);
hudakz 0:91392e1f8551 1228 }
hudakz 0:91392e1f8551 1229
hudakz 0:91392e1f8551 1230 for(c = line; *c; ++c)
hudakz 0:91392e1f8551 1231 if(isdigit(*c))
hudakz 0:91392e1f8551 1232 break;
hudakz 0:91392e1f8551 1233
hudakz 0:91392e1f8551 1234 if(!isdigit(*c)) {
hudakz 0:91392e1f8551 1235 fprintf(stderr, "Unable to determine board revision from /proc/cpuinfo\n");
hudakz 0:91392e1f8551 1236 fprintf(stderr, " (Info not found in: %s\n", line);
hudakz 0:91392e1f8551 1237 exit(1);
hudakz 0:91392e1f8551 1238 }
hudakz 0:91392e1f8551 1239
hudakz 0:91392e1f8551 1240 finalChar = c[strlen(c) - 2];
hudakz 0:91392e1f8551 1241
hudakz 0:91392e1f8551 1242 if((finalChar == '2') || (finalChar == '3')) {
hudakz 0:91392e1f8551 1243 bsc0 = bsc_rev1;
hudakz 0:91392e1f8551 1244 return 1;
hudakz 0:91392e1f8551 1245 }
hudakz 0:91392e1f8551 1246 else {
hudakz 0:91392e1f8551 1247 bsc0 = bsc_rev2;
hudakz 0:91392e1f8551 1248 return 2;
hudakz 0:91392e1f8551 1249 }
hudakz 0:91392e1f8551 1250 }
hudakz 0:91392e1f8551 1251
hudakz 0:91392e1f8551 1252 /**
hudakz 0:91392e1f8551 1253 * @brief
hudakz 0:91392e1f8551 1254 * @note
hudakz 0:91392e1f8551 1255 * @param
hudakz 0:91392e1f8551 1256 * @retval
hudakz 0:91392e1f8551 1257 */
hudakz 0:91392e1f8551 1258 uint32_t* mapmem(const char* msg, size_t size, int fd, off_t off) {
hudakz 0:91392e1f8551 1259 uint32_t* map = (uint32_t*)mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off);
hudakz 0:91392e1f8551 1260 if(MAP_FAILED == map)
hudakz 0:91392e1f8551 1261 fprintf(stderr, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno));
hudakz 0:91392e1f8551 1262 return map;
hudakz 0:91392e1f8551 1263 }
hudakz 0:91392e1f8551 1264
hudakz 0:91392e1f8551 1265 // safe read from peripheral
hudakz 0:91392e1f8551 1266 uint32_t bcm2835_peri_read(volatile uint32_t* paddr) {
hudakz 0:91392e1f8551 1267 uint32_t ret = *paddr;
hudakz 0:91392e1f8551 1268 ret = *paddr;
hudakz 0:91392e1f8551 1269 return ret;
hudakz 0:91392e1f8551 1270 }
hudakz 0:91392e1f8551 1271
hudakz 0:91392e1f8551 1272 // read from peripheral without the read barrier
hudakz 0:91392e1f8551 1273 uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr) {
hudakz 0:91392e1f8551 1274 return *paddr;
hudakz 0:91392e1f8551 1275 }
hudakz 0:91392e1f8551 1276
hudakz 0:91392e1f8551 1277 // safe write to peripheral
hudakz 0:91392e1f8551 1278 void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value) {
hudakz 0:91392e1f8551 1279 *paddr = value;
hudakz 0:91392e1f8551 1280 *paddr = value;
hudakz 0:91392e1f8551 1281 }
hudakz 0:91392e1f8551 1282
hudakz 0:91392e1f8551 1283 // write to peripheral without the write barrier
hudakz 0:91392e1f8551 1284 void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value) {
hudakz 0:91392e1f8551 1285 *paddr = value;
hudakz 0:91392e1f8551 1286 }
hudakz 0:91392e1f8551 1287
hudakz 0:91392e1f8551 1288 // Set/clear only the bits in value covered by the mask
hudakz 0:91392e1f8551 1289 void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask) {
hudakz 0:91392e1f8551 1290 uint32_t v = bcm2835_peri_read(paddr);
hudakz 0:91392e1f8551 1291 v = (v &~mask) | (value & mask);
hudakz 0:91392e1f8551 1292 bcm2835_peri_write(paddr, v);
hudakz 0:91392e1f8551 1293 }
hudakz 0:91392e1f8551 1294
hudakz 0:91392e1f8551 1295 //
hudakz 0:91392e1f8551 1296 // Low level convenience functions
hudakz 0:91392e1f8551 1297 //
hudakz 0:91392e1f8551 1298 // Function select
hudakz 0:91392e1f8551 1299 // pin is a BCM2835 GPIO pin number NOT RPi pin number
hudakz 0:91392e1f8551 1300 // There are 6 control registers, each control the functions of a block
hudakz 0:91392e1f8551 1301 // of 10 pins.
hudakz 0:91392e1f8551 1302 // Each control register has 10 sets of 3 bits per GPIO pin:
hudakz 0:91392e1f8551 1303 //
hudakz 0:91392e1f8551 1304 // 000 = GPIO Pin X is an input
hudakz 0:91392e1f8551 1305 // 001 = GPIO Pin X is an output
hudakz 0:91392e1f8551 1306 // 100 = GPIO Pin X takes alternate function 0
hudakz 0:91392e1f8551 1307 // 101 = GPIO Pin X takes alternate function 1
hudakz 0:91392e1f8551 1308 // 110 = GPIO Pin X takes alternate function 2
hudakz 0:91392e1f8551 1309 // 111 = GPIO Pin X takes alternate function 3
hudakz 0:91392e1f8551 1310 // 011 = GPIO Pin X takes alternate function 4
hudakz 0:91392e1f8551 1311 // 010 = GPIO Pin X takes alternate function 5
hudakz 0:91392e1f8551 1312 //
hudakz 0:91392e1f8551 1313 // So the 3 bits for port X are:
hudakz 0:91392e1f8551 1314
hudakz 0:91392e1f8551 1315 // X / 10 + ((X % 10) * 3)
hudakz 0:91392e1f8551 1316 void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode) {
hudakz 0:91392e1f8551 1317
hudakz 0:91392e1f8551 1318 // Function selects are 10 pins per 32 bit word, 3 bits per pin
hudakz 0:91392e1f8551 1319 volatile uint32_t* paddr = (volatile uint32_t*)gpio.map + BCM2835_GPFSEL0 / 4 + (pin / 10);
hudakz 0:91392e1f8551 1320 uint8_t shift = (pin % 10) * 3;
hudakz 0:91392e1f8551 1321 uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift;
hudakz 0:91392e1f8551 1322 uint32_t value = mode << shift;
hudakz 0:91392e1f8551 1323 bcm2835_peri_set_bits(paddr, value, mask);
hudakz 0:91392e1f8551 1324 }
hudakz 0:91392e1f8551 1325
hudakz 0:91392e1f8551 1326 /* This is the function that will be running in a thread if
hudakz 0:91392e1f8551 1327 * attachInterrupt() is called */
hudakz 0:91392e1f8551 1328 void* threadFunction(void* args) {
hudakz 0:91392e1f8551 1329 ThreadArg* arguments = (ThreadArg*)args;
hudakz 0:91392e1f8551 1330 int pin = arguments->pin;
hudakz 0:91392e1f8551 1331
hudakz 0:91392e1f8551 1332 int GPIO_FN_MAXLEN = 32;
hudakz 0:91392e1f8551 1333 int RDBUF_LEN = 5;
hudakz 0:91392e1f8551 1334
hudakz 0:91392e1f8551 1335 char fn[GPIO_FN_MAXLEN];
hudakz 0:91392e1f8551 1336 int fd, ret;
hudakz 0:91392e1f8551 1337 struct pollfd pfd;
hudakz 0:91392e1f8551 1338 char rdbuf[RDBUF_LEN];
hudakz 0:91392e1f8551 1339
hudakz 0:91392e1f8551 1340 memset(rdbuf, 0x00, RDBUF_LEN);
hudakz 0:91392e1f8551 1341 memset(fn, 0x00, GPIO_FN_MAXLEN);
hudakz 0:91392e1f8551 1342
hudakz 0:91392e1f8551 1343 snprintf(fn, GPIO_FN_MAXLEN - 1, "/sys/class/gpio/gpio%d/value", pin);
hudakz 0:91392e1f8551 1344 fd = open(fn, O_RDONLY);
hudakz 0:91392e1f8551 1345 if(fd < 0) {
hudakz 0:91392e1f8551 1346 perror(fn);
hudakz 0:91392e1f8551 1347 exit(1);
hudakz 0:91392e1f8551 1348 }
hudakz 0:91392e1f8551 1349
hudakz 0:91392e1f8551 1350 pfd.fd = fd;
hudakz 0:91392e1f8551 1351 pfd.events = POLLPRI;
hudakz 0:91392e1f8551 1352
hudakz 0:91392e1f8551 1353 ret = unistd::read(fd, rdbuf, RDBUF_LEN - 1);
hudakz 0:91392e1f8551 1354 if(ret < 0) {
hudakz 0:91392e1f8551 1355 perror("Error reading interrupt file\n");
hudakz 0:91392e1f8551 1356 exit(1);
hudakz 0:91392e1f8551 1357 }
hudakz 0:91392e1f8551 1358
hudakz 0:91392e1f8551 1359 while(1) {
hudakz 0:91392e1f8551 1360 memset(rdbuf, 0x00, RDBUF_LEN);
hudakz 0:91392e1f8551 1361 unistd::lseek(fd, 0, SEEK_SET);
hudakz 0:91392e1f8551 1362 ret = poll(&pfd, 1, -1);
hudakz 0:91392e1f8551 1363 if(ret < 0) {
hudakz 0:91392e1f8551 1364 perror("Error waiting for interrupt\n");
hudakz 0:91392e1f8551 1365 unistd::close(fd);
hudakz 0:91392e1f8551 1366 exit(1);
hudakz 0:91392e1f8551 1367 }
hudakz 0:91392e1f8551 1368
hudakz 0:91392e1f8551 1369 if(ret == 0) {
hudakz 0:91392e1f8551 1370 printf("Timeout\n");
hudakz 0:91392e1f8551 1371 continue;
hudakz 0:91392e1f8551 1372 }
hudakz 0:91392e1f8551 1373
hudakz 0:91392e1f8551 1374 ret = unistd::read(fd, rdbuf, RDBUF_LEN - 1);
hudakz 0:91392e1f8551 1375 if(ret < 0) {
hudakz 0:91392e1f8551 1376 perror("Error reading interrupt file\n");
hudakz 0:91392e1f8551 1377 exit(1);
hudakz 0:91392e1f8551 1378 }
hudakz 0:91392e1f8551 1379
hudakz 0:91392e1f8551 1380 //Interrupt. We call user function.
hudakz 0:91392e1f8551 1381 arguments->func();
hudakz 0:91392e1f8551 1382 }
hudakz 0:91392e1f8551 1383 }
hudakz 0:91392e1f8551 1384
hudakz 0:91392e1f8551 1385 /**
hudakz 0:91392e1f8551 1386 * @brief
hudakz 0:91392e1f8551 1387 * @note
hudakz 0:91392e1f8551 1388 * @param
hudakz 0:91392e1f8551 1389 * @retval
hudakz 0:91392e1f8551 1390 */
hudakz 0:91392e1f8551 1391 pthread_t* getThreadIdFromPin(int pin) {
hudakz 0:91392e1f8551 1392 int i = pin - 2;
hudakz 0:91392e1f8551 1393 if((0 <= i) && (i <= 25))
hudakz 0:91392e1f8551 1394 return idThreads[i];
hudakz 0:91392e1f8551 1395 else
hudakz 0:91392e1f8551 1396 return NULL;
hudakz 0:91392e1f8551 1397 }
hudakz 0:91392e1f8551 1398
hudakz 0:91392e1f8551 1399 /**
hudakz 0:91392e1f8551 1400 * @brief
hudakz 0:91392e1f8551 1401 * @note
hudakz 0:91392e1f8551 1402 * @param
hudakz 0:91392e1f8551 1403 * @retval
hudakz 0:91392e1f8551 1404 */
hudakz 0:91392e1f8551 1405 void gpio_dir(PinName pin, PinDirection direction) {
hudakz 0:91392e1f8551 1406 uint8_t gpfsel = pin / 10;
hudakz 0:91392e1f8551 1407 uint8_t shift = (pin % 10) * 3;
hudakz 0:91392e1f8551 1408 uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift;
hudakz 0:91392e1f8551 1409 uint32_t outp = BCM2835_GPIO_FSEL_OUTP << shift;
hudakz 0:91392e1f8551 1410
hudakz 0:91392e1f8551 1411 if(direction == PIN_OUTPUT) {
hudakz 0:91392e1f8551 1412 *(gpio.addr + gpfsel) &= ~mask;
hudakz 0:91392e1f8551 1413 *(gpio.addr + gpfsel) |= outp;
hudakz 0:91392e1f8551 1414 }
hudakz 0:91392e1f8551 1415 else
hudakz 0:91392e1f8551 1416 if(direction == PIN_INPUT) {
hudakz 0:91392e1f8551 1417 *(gpio.addr + gpfsel) &= ~mask;
hudakz 0:91392e1f8551 1418 }
hudakz 0:91392e1f8551 1419 }
hudakz 0:91392e1f8551 1420
hudakz 0:91392e1f8551 1421 /**
hudakz 0:91392e1f8551 1422 * @brief
hudakz 0:91392e1f8551 1423 * @note
hudakz 0:91392e1f8551 1424 * @param
hudakz 0:91392e1f8551 1425 * @retval
hudakz 0:91392e1f8551 1426 */
hudakz 0:91392e1f8551 1427 void gpio_mode(PinName pin, PinMode mode) {
hudakz 0:91392e1f8551 1428 mode == PullUp ? gpio_write(pin, HIGH) : gpio_write(pin, LOW);
hudakz 0:91392e1f8551 1429 }
hudakz 0:91392e1f8551 1430
hudakz 0:91392e1f8551 1431 /**
hudakz 0:91392e1f8551 1432 * @brief
hudakz 0:91392e1f8551 1433 * @note
hudakz 0:91392e1f8551 1434 * @param
hudakz 0:91392e1f8551 1435 * @retval
hudakz 0:91392e1f8551 1436 */
hudakz 0:91392e1f8551 1437 uint8_t shiftIn(PinName dPin, PinName cPin, bcm2835SPIBitOrder order) {
hudakz 0:91392e1f8551 1438 uint8_t value = 0;
hudakz 0:91392e1f8551 1439 int8_t i;
hudakz 0:91392e1f8551 1440
hudakz 0:91392e1f8551 1441 if(order == MSBFIRST)
hudakz 0:91392e1f8551 1442 for(i = 7; i >= 0; --i) {
hudakz 0:91392e1f8551 1443 gpio_write(cPin, HIGH);
hudakz 0:91392e1f8551 1444 value |= gpio_read(dPin) << i;
hudakz 0:91392e1f8551 1445 gpio_write(cPin, LOW);
hudakz 0:91392e1f8551 1446 }
hudakz 0:91392e1f8551 1447 else
hudakz 0:91392e1f8551 1448 for(i = 0; i < 8; ++i) {
hudakz 0:91392e1f8551 1449 gpio_write(cPin, HIGH);
hudakz 0:91392e1f8551 1450 value |= gpio_read(dPin) << i;
hudakz 0:91392e1f8551 1451 gpio_write(cPin, LOW);
hudakz 0:91392e1f8551 1452 }
hudakz 0:91392e1f8551 1453
hudakz 0:91392e1f8551 1454 return value;
hudakz 0:91392e1f8551 1455 }
hudakz 0:91392e1f8551 1456
hudakz 0:91392e1f8551 1457 /**
hudakz 0:91392e1f8551 1458 * @brief
hudakz 0:91392e1f8551 1459 * @note
hudakz 0:91392e1f8551 1460 * @param
hudakz 0:91392e1f8551 1461 * @retval
hudakz 0:91392e1f8551 1462 */
hudakz 0:91392e1f8551 1463 void shiftOut(PinName dPin, PinName cPin, bcm2835SPIBitOrder order, uint8_t val) {
hudakz 0:91392e1f8551 1464 int8_t i;
hudakz 0:91392e1f8551 1465
hudakz 0:91392e1f8551 1466 if(order == MSBFIRST)
hudakz 0:91392e1f8551 1467 for(i = 7; i >= 0; --i) {
hudakz 0:91392e1f8551 1468 gpio_write(dPin, val & (1 << i));
hudakz 0:91392e1f8551 1469 gpio_write(cPin, HIGH);
hudakz 0:91392e1f8551 1470 gpio_write(cPin, LOW);
hudakz 0:91392e1f8551 1471 }
hudakz 0:91392e1f8551 1472 else
hudakz 0:91392e1f8551 1473 for(i = 0; i < 8; ++i) {
hudakz 0:91392e1f8551 1474 gpio_write(dPin, val & (1 << i));
hudakz 0:91392e1f8551 1475 gpio_write(cPin, HIGH);
hudakz 0:91392e1f8551 1476 gpio_write(cPin, LOW);
hudakz 0:91392e1f8551 1477 }
hudakz 0:91392e1f8551 1478 }
hudakz 0:91392e1f8551 1479
hudakz 0:91392e1f8551 1480 /**
hudakz 0:91392e1f8551 1481 * @brief
hudakz 0:91392e1f8551 1482 * @note
hudakz 0:91392e1f8551 1483 * @param
hudakz 0:91392e1f8551 1484 * @retval
hudakz 0:91392e1f8551 1485 */
hudakz 0:91392e1f8551 1486 void attachInterrupt(PinName p, void (*f) (), Digivalue m) {
hudakz 0:91392e1f8551 1487 int GPIOPin = p;
hudakz 0:91392e1f8551 1488 pthread_t* threadId = getThreadIdFromPin(p);
hudakz 0:91392e1f8551 1489 struct ThreadArg* threadArgs = (ThreadArg*)malloc(sizeof(ThreadArg));
hudakz 0:91392e1f8551 1490 threadArgs->func = f;
hudakz 0:91392e1f8551 1491 threadArgs->pin = GPIOPin;
hudakz 0:91392e1f8551 1492
hudakz 0:91392e1f8551 1493 //Export pin for interrupt
hudakz 0:91392e1f8551 1494 FILE* fp = fopen("/sys/class/gpio/export", "w");
hudakz 0:91392e1f8551 1495 if(fp == NULL) {
hudakz 0:91392e1f8551 1496 fprintf(stderr, "Unable to export pin %d for interrupt\n", p);
hudakz 0:91392e1f8551 1497 exit(1);
hudakz 0:91392e1f8551 1498 }
hudakz 0:91392e1f8551 1499 else {
hudakz 0:91392e1f8551 1500 fprintf(fp, "%d", GPIOPin);
hudakz 0:91392e1f8551 1501 }
hudakz 0:91392e1f8551 1502
hudakz 0:91392e1f8551 1503 fclose(fp);
hudakz 0:91392e1f8551 1504
hudakz 0:91392e1f8551 1505 //The system to create the file /sys/class/gpio/gpio<GPIO number>
hudakz 0:91392e1f8551 1506 //So we wait a bit
hudakz 0:91392e1f8551 1507 wait_ms(1);
hudakz 0:91392e1f8551 1508
hudakz 0:91392e1f8551 1509 char* interruptFile = NULL;
hudakz 0:91392e1f8551 1510 asprintf(&interruptFile, "/sys/class/gpio/gpio%d/edge", GPIOPin);
hudakz 0:91392e1f8551 1511
hudakz 0:91392e1f8551 1512 //Set detection condition
hudakz 0:91392e1f8551 1513 fp = fopen(interruptFile, "w");
hudakz 0:91392e1f8551 1514 if(fp == NULL) {
hudakz 0:91392e1f8551 1515 fprintf(stderr, "Unable to set detection type on pin %d\n", p);
hudakz 0:91392e1f8551 1516 exit(1);
hudakz 0:91392e1f8551 1517 }
hudakz 0:91392e1f8551 1518 else {
hudakz 0:91392e1f8551 1519 switch(m) {
hudakz 0:91392e1f8551 1520 case RISING:
hudakz 0:91392e1f8551 1521 fprintf(fp, "rising");
hudakz 0:91392e1f8551 1522 break;
hudakz 0:91392e1f8551 1523
hudakz 0:91392e1f8551 1524 case FALLING:
hudakz 0:91392e1f8551 1525 fprintf(fp, "falling");
hudakz 0:91392e1f8551 1526 break;
hudakz 0:91392e1f8551 1527
hudakz 0:91392e1f8551 1528 default:
hudakz 0:91392e1f8551 1529 fprintf(fp, "both");
hudakz 0:91392e1f8551 1530 break;
hudakz 0:91392e1f8551 1531 }
hudakz 0:91392e1f8551 1532 }
hudakz 0:91392e1f8551 1533
hudakz 0:91392e1f8551 1534 fclose(fp);
hudakz 0:91392e1f8551 1535
hudakz 0:91392e1f8551 1536 if(*threadId == 0) {
hudakz 0:91392e1f8551 1537
hudakz 0:91392e1f8551 1538 //Create a thread passing the pin and function
hudakz 0:91392e1f8551 1539 pthread_create(threadId, NULL, threadFunction, (void*)threadArgs);
hudakz 0:91392e1f8551 1540 }
hudakz 0:91392e1f8551 1541 else {
hudakz 0:91392e1f8551 1542
hudakz 0:91392e1f8551 1543 //First cancel the existing thread for that pin
hudakz 0:91392e1f8551 1544 pthread_cancel(*threadId);
hudakz 0:91392e1f8551 1545
hudakz 0:91392e1f8551 1546 //Create a thread passing the pin, function and mode
hudakz 0:91392e1f8551 1547 pthread_create(threadId, NULL, threadFunction, (void*)threadArgs);
hudakz 0:91392e1f8551 1548 }
hudakz 0:91392e1f8551 1549 }
hudakz 0:91392e1f8551 1550
hudakz 0:91392e1f8551 1551 /**
hudakz 0:91392e1f8551 1552 * @brief
hudakz 0:91392e1f8551 1553 * @note
hudakz 0:91392e1f8551 1554 * @param
hudakz 0:91392e1f8551 1555 * @retval
hudakz 0:91392e1f8551 1556 */
hudakz 0:91392e1f8551 1557 void detachInterrupt(PinName p) {
hudakz 0:91392e1f8551 1558 int GPIOPin = p;
hudakz 0:91392e1f8551 1559
hudakz 0:91392e1f8551 1560 FILE* fp = fopen("/sys/class/gpio/unexport", "w");
hudakz 0:91392e1f8551 1561 if(fp == NULL) {
hudakz 0:91392e1f8551 1562 fprintf(stderr, "Unable to unexport pin %d for interrupt\n", p);
hudakz 0:91392e1f8551 1563 exit(1);
hudakz 0:91392e1f8551 1564 }
hudakz 0:91392e1f8551 1565 else {
hudakz 0:91392e1f8551 1566 fprintf(fp, "%d", GPIOPin);
hudakz 0:91392e1f8551 1567 }
hudakz 0:91392e1f8551 1568
hudakz 0:91392e1f8551 1569 fclose(fp);
hudakz 0:91392e1f8551 1570
hudakz 0:91392e1f8551 1571 pthread_t* threadId = getThreadIdFromPin(p);
hudakz 0:91392e1f8551 1572 pthread_cancel(*threadId);
hudakz 0:91392e1f8551 1573 }
hudakz 0:91392e1f8551 1574
hudakz 0:91392e1f8551 1575 Peripheral peripheral = Peripheral();