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.
mbedPi.cpp@0:91392e1f8551, 2016-10-18 (annotated)
- Committer:
- hudakz
- Date:
- Tue Oct 18 18:18:37 2016 +0000
- Revision:
- 0:91392e1f8551
Initial issue.
Who changed what in which revision?
User | Revision | Line number | New 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(); |