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.
source/I2C.cpp@1:1f2d9982fa8c, 22 months ago (annotated)
- Committer:
- hudakz
- Date:
- Tue Dec 20 12:08:07 2022 +0000
- Revision:
- 1:1f2d9982fa8c
mbed API for Raspberry Pi boards equipped with BCM2836 SoC.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 1:1f2d9982fa8c | 1 | #include "mbed.h" |
hudakz | 1:1f2d9982fa8c | 2 | |
hudakz | 1:1f2d9982fa8c | 3 | extern struct bcm2835_peripheral bsc0; |
hudakz | 1:1f2d9982fa8c | 4 | extern timeval start_program, end_point; |
hudakz | 1:1f2d9982fa8c | 5 | extern volatile uint32_t *bcm2835_bsc1; |
hudakz | 1:1f2d9982fa8c | 6 | |
hudakz | 1:1f2d9982fa8c | 7 | I2C::I2C() |
hudakz | 1:1f2d9982fa8c | 8 | { |
hudakz | 1:1f2d9982fa8c | 9 | // start timer |
hudakz | 1:1f2d9982fa8c | 10 | gettimeofday(&start_program, NULL); |
hudakz | 1:1f2d9982fa8c | 11 | |
hudakz | 1:1f2d9982fa8c | 12 | //Initiate the Wire library and join the I2C bus. |
hudakz | 1:1f2d9982fa8c | 13 | volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV / 4; |
hudakz | 1:1f2d9982fa8c | 14 | |
hudakz | 1:1f2d9982fa8c | 15 | // Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them |
hudakz | 1:1f2d9982fa8c | 16 | |
hudakz | 1:1f2d9982fa8c | 17 | bcm2835_gpio_fsel(SDA, BCM2835_GPIO_FSEL_ALT0); |
hudakz | 1:1f2d9982fa8c | 18 | bcm2835_gpio_fsel(SCL, BCM2835_GPIO_FSEL_ALT0); |
hudakz | 1:1f2d9982fa8c | 19 | |
hudakz | 1:1f2d9982fa8c | 20 | // Read the clock divider register |
hudakz | 1:1f2d9982fa8c | 21 | uint16_t cdiv = bcm2835_peri_read(paddr); |
hudakz | 1:1f2d9982fa8c | 22 | // Calculate time for transmitting one byte |
hudakz | 1:1f2d9982fa8c | 23 | |
hudakz | 1:1f2d9982fa8c | 24 | // 1000000 = micros seconds in a second |
hudakz | 1:1f2d9982fa8c | 25 | // 9 = Clocks per byte : 8 bits + ACK |
hudakz | 1:1f2d9982fa8c | 26 | _i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9; |
hudakz | 1:1f2d9982fa8c | 27 | } |
hudakz | 1:1f2d9982fa8c | 28 | |
hudakz | 1:1f2d9982fa8c | 29 | /** |
hudakz | 1:1f2d9982fa8c | 30 | * @brief |
hudakz | 1:1f2d9982fa8c | 31 | * @note |
hudakz | 1:1f2d9982fa8c | 32 | * @param |
hudakz | 1:1f2d9982fa8c | 33 | * @retval |
hudakz | 1:1f2d9982fa8c | 34 | */ |
hudakz | 1:1f2d9982fa8c | 35 | I2C::~I2C() |
hudakz | 1:1f2d9982fa8c | 36 | { |
hudakz | 1:1f2d9982fa8c | 37 | // Set all the I2C/BSC1 pins back to input |
hudakz | 1:1f2d9982fa8c | 38 | |
hudakz | 1:1f2d9982fa8c | 39 | bcm2835_gpio_fsel(SDA, BCM2835_GPIO_FSEL_INPT); // SDA |
hudakz | 1:1f2d9982fa8c | 40 | bcm2835_gpio_fsel(SCL, BCM2835_GPIO_FSEL_INPT); // SCL |
hudakz | 1:1f2d9982fa8c | 41 | } |
hudakz | 1:1f2d9982fa8c | 42 | |
hudakz | 1:1f2d9982fa8c | 43 | /** |
hudakz | 1:1f2d9982fa8c | 44 | * @brief |
hudakz | 1:1f2d9982fa8c | 45 | * @note |
hudakz | 1:1f2d9982fa8c | 46 | * @param |
hudakz | 1:1f2d9982fa8c | 47 | * @retval |
hudakz | 1:1f2d9982fa8c | 48 | */ |
hudakz | 1:1f2d9982fa8c | 49 | uint8_t I2C::read(uint8_t address, char* buf, int len, bool repeat) |
hudakz | 1:1f2d9982fa8c | 50 | { |
hudakz | 1:1f2d9982fa8c | 51 | if (repeat) { |
hudakz | 1:1f2d9982fa8c | 52 | _addr = address; |
hudakz | 1:1f2d9982fa8c | 53 | return read_repeat(buf, len); |
hudakz | 1:1f2d9982fa8c | 54 | } |
hudakz | 1:1f2d9982fa8c | 55 | else { |
hudakz | 1:1f2d9982fa8c | 56 | requestFrom(address, len); |
hudakz | 1:1f2d9982fa8c | 57 | return read(buf); |
hudakz | 1:1f2d9982fa8c | 58 | } |
hudakz | 1:1f2d9982fa8c | 59 | } |
hudakz | 1:1f2d9982fa8c | 60 | |
hudakz | 1:1f2d9982fa8c | 61 | /** |
hudakz | 1:1f2d9982fa8c | 62 | * @brief |
hudakz | 1:1f2d9982fa8c | 63 | * @note |
hudakz | 1:1f2d9982fa8c | 64 | * @param |
hudakz | 1:1f2d9982fa8c | 65 | * @retval |
hudakz | 1:1f2d9982fa8c | 66 | */ |
hudakz | 1:1f2d9982fa8c | 67 | uint8_t I2C::read(bool ack) |
hudakz | 1:1f2d9982fa8c | 68 | { |
hudakz | 1:1f2d9982fa8c | 69 | char buf[1] = { 0 }; |
hudakz | 1:1f2d9982fa8c | 70 | |
hudakz | 1:1f2d9982fa8c | 71 | if (ack) { |
hudakz | 1:1f2d9982fa8c | 72 | _i2c_bytes_to_read = 1; |
hudakz | 1:1f2d9982fa8c | 73 | read(buf); |
hudakz | 1:1f2d9982fa8c | 74 | } |
hudakz | 1:1f2d9982fa8c | 75 | else { |
hudakz | 1:1f2d9982fa8c | 76 | read_repeat(buf, 1); |
hudakz | 1:1f2d9982fa8c | 77 | } |
hudakz | 1:1f2d9982fa8c | 78 | |
hudakz | 1:1f2d9982fa8c | 79 | return buf[0]; |
hudakz | 1:1f2d9982fa8c | 80 | } |
hudakz | 1:1f2d9982fa8c | 81 | |
hudakz | 1:1f2d9982fa8c | 82 | /** |
hudakz | 1:1f2d9982fa8c | 83 | * @brief |
hudakz | 1:1f2d9982fa8c | 84 | * @note |
hudakz | 1:1f2d9982fa8c | 85 | * @param |
hudakz | 1:1f2d9982fa8c | 86 | * @retval |
hudakz | 1:1f2d9982fa8c | 87 | */ |
hudakz | 1:1f2d9982fa8c | 88 | int I2C::write(uint8_t address, const char* buf, int len, bool repeat) |
hudakz | 1:1f2d9982fa8c | 89 | { |
hudakz | 1:1f2d9982fa8c | 90 | setAddress(address); |
hudakz | 1:1f2d9982fa8c | 91 | return write(buf, len); |
hudakz | 1:1f2d9982fa8c | 92 | } |
hudakz | 1:1f2d9982fa8c | 93 | |
hudakz | 1:1f2d9982fa8c | 94 | /** |
hudakz | 1:1f2d9982fa8c | 95 | * @brief |
hudakz | 1:1f2d9982fa8c | 96 | * @note |
hudakz | 1:1f2d9982fa8c | 97 | * @param |
hudakz | 1:1f2d9982fa8c | 98 | * @retval |
hudakz | 1:1f2d9982fa8c | 99 | */ |
hudakz | 1:1f2d9982fa8c | 100 | int I2C::write(uint8_t data) |
hudakz | 1:1f2d9982fa8c | 101 | { |
hudakz | 1:1f2d9982fa8c | 102 | char i2cdata[1] = { data }; |
hudakz | 1:1f2d9982fa8c | 103 | |
hudakz | 1:1f2d9982fa8c | 104 | return write(i2cdata, 1); |
hudakz | 1:1f2d9982fa8c | 105 | } |
hudakz | 1:1f2d9982fa8c | 106 | |
hudakz | 1:1f2d9982fa8c | 107 | /******************* |
hudakz | 1:1f2d9982fa8c | 108 | * Private methods * |
hudakz | 1:1f2d9982fa8c | 109 | *******************/ |
hudakz | 1:1f2d9982fa8c | 110 | |
hudakz | 1:1f2d9982fa8c | 111 | /** |
hudakz | 1:1f2d9982fa8c | 112 | * @brief |
hudakz | 1:1f2d9982fa8c | 113 | * @note |
hudakz | 1:1f2d9982fa8c | 114 | * @param |
hudakz | 1:1f2d9982fa8c | 115 | * @retval |
hudakz | 1:1f2d9982fa8c | 116 | */ |
hudakz | 1:1f2d9982fa8c | 117 | void I2C::setAddress(uint8_t address) |
hudakz | 1:1f2d9982fa8c | 118 | { |
hudakz | 1:1f2d9982fa8c | 119 | _addr = address; |
hudakz | 1:1f2d9982fa8c | 120 | |
hudakz | 1:1f2d9982fa8c | 121 | volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A / 4; |
hudakz | 1:1f2d9982fa8c | 122 | bcm2835_peri_write(paddr, _addr); |
hudakz | 1:1f2d9982fa8c | 123 | } |
hudakz | 1:1f2d9982fa8c | 124 | |
hudakz | 1:1f2d9982fa8c | 125 | /** |
hudakz | 1:1f2d9982fa8c | 126 | * @brief |
hudakz | 1:1f2d9982fa8c | 127 | * @note Used by the master to request bytes from a slave device |
hudakz | 1:1f2d9982fa8c | 128 | * @param |
hudakz | 1:1f2d9982fa8c | 129 | * @retval |
hudakz | 1:1f2d9982fa8c | 130 | */ |
hudakz | 1:1f2d9982fa8c | 131 | void I2C::requestFrom(unsigned char address, int len) |
hudakz | 1:1f2d9982fa8c | 132 | { |
hudakz | 1:1f2d9982fa8c | 133 | setAddress(address); |
hudakz | 1:1f2d9982fa8c | 134 | _i2c_bytes_to_read = len; |
hudakz | 1:1f2d9982fa8c | 135 | } |
hudakz | 1:1f2d9982fa8c | 136 | |
hudakz | 1:1f2d9982fa8c | 137 | /** |
hudakz | 1:1f2d9982fa8c | 138 | * @brief Reads bytes from slave after a call to WirePi::requestFrom(address, len) |
hudakz | 1:1f2d9982fa8c | 139 | * @note |
hudakz | 1:1f2d9982fa8c | 140 | * @param |
hudakz | 1:1f2d9982fa8c | 141 | * @retval |
hudakz | 1:1f2d9982fa8c | 142 | */ |
hudakz | 1:1f2d9982fa8c | 143 | uint8_t I2C::read(char* buf) |
hudakz | 1:1f2d9982fa8c | 144 | { |
hudakz | 1:1f2d9982fa8c | 145 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN / 4; |
hudakz | 1:1f2d9982fa8c | 146 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO / 4; |
hudakz | 1:1f2d9982fa8c | 147 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S / 4; |
hudakz | 1:1f2d9982fa8c | 148 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C / 4; |
hudakz | 1:1f2d9982fa8c | 149 | |
hudakz | 1:1f2d9982fa8c | 150 | uint32_t remaining = _i2c_bytes_to_read; |
hudakz | 1:1f2d9982fa8c | 151 | uint32_t i = 0; |
hudakz | 1:1f2d9982fa8c | 152 | uint8_t reason = BCM2835_I2C_REASON_OK; |
hudakz | 1:1f2d9982fa8c | 153 | |
hudakz | 1:1f2d9982fa8c | 154 | // |
hudakz | 1:1f2d9982fa8c | 155 | |
hudakz | 1:1f2d9982fa8c | 156 | // Clear FIFO |
hudakz | 1:1f2d9982fa8c | 157 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1, BCM2835_BSC_C_CLEAR_1); |
hudakz | 1:1f2d9982fa8c | 158 | |
hudakz | 1:1f2d9982fa8c | 159 | // Clear Status |
hudakz | 1:1f2d9982fa8c | 160 | bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); |
hudakz | 1:1f2d9982fa8c | 161 | |
hudakz | 1:1f2d9982fa8c | 162 | // Set Data Length |
hudakz | 1:1f2d9982fa8c | 163 | bcm2835_peri_write_nb(dlen, _i2c_bytes_to_read); |
hudakz | 1:1f2d9982fa8c | 164 | |
hudakz | 1:1f2d9982fa8c | 165 | // Start read |
hudakz | 1:1f2d9982fa8c | 166 | bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ); |
hudakz | 1:1f2d9982fa8c | 167 | |
hudakz | 1:1f2d9982fa8c | 168 | // wait for transfer to complete |
hudakz | 1:1f2d9982fa8c | 169 | while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) { |
hudakz | 1:1f2d9982fa8c | 170 | |
hudakz | 1:1f2d9982fa8c | 171 | // we must empty the FIFO as it is populated and not use any delay |
hudakz | 1:1f2d9982fa8c | 172 | while (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) { |
hudakz | 1:1f2d9982fa8c | 173 | |
hudakz | 1:1f2d9982fa8c | 174 | // Read from FIFO, no barrier |
hudakz | 1:1f2d9982fa8c | 175 | buf[i] = bcm2835_peri_read_nb(fifo); |
hudakz | 1:1f2d9982fa8c | 176 | i++; |
hudakz | 1:1f2d9982fa8c | 177 | remaining--; |
hudakz | 1:1f2d9982fa8c | 178 | } |
hudakz | 1:1f2d9982fa8c | 179 | } |
hudakz | 1:1f2d9982fa8c | 180 | |
hudakz | 1:1f2d9982fa8c | 181 | // transfer has finished - grab any remaining stuff in FIFO |
hudakz | 1:1f2d9982fa8c | 182 | while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) { |
hudakz | 1:1f2d9982fa8c | 183 | |
hudakz | 1:1f2d9982fa8c | 184 | // Read from FIFO, no barrier |
hudakz | 1:1f2d9982fa8c | 185 | buf[i] = bcm2835_peri_read_nb(fifo); |
hudakz | 1:1f2d9982fa8c | 186 | i++; |
hudakz | 1:1f2d9982fa8c | 187 | remaining--; |
hudakz | 1:1f2d9982fa8c | 188 | } |
hudakz | 1:1f2d9982fa8c | 189 | |
hudakz | 1:1f2d9982fa8c | 190 | // Received a NACK |
hudakz | 1:1f2d9982fa8c | 191 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { |
hudakz | 1:1f2d9982fa8c | 192 | reason = BCM2835_I2C_REASON_ERROR_NACK; |
hudakz | 1:1f2d9982fa8c | 193 | } |
hudakz | 1:1f2d9982fa8c | 194 | |
hudakz | 1:1f2d9982fa8c | 195 | // Received Clock Stretch Timeout |
hudakz | 1:1f2d9982fa8c | 196 | else |
hudakz | 1:1f2d9982fa8c | 197 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { |
hudakz | 1:1f2d9982fa8c | 198 | reason = BCM2835_I2C_REASON_ERROR_CLKT; |
hudakz | 1:1f2d9982fa8c | 199 | } |
hudakz | 1:1f2d9982fa8c | 200 | |
hudakz | 1:1f2d9982fa8c | 201 | // Not all data is received |
hudakz | 1:1f2d9982fa8c | 202 | else |
hudakz | 1:1f2d9982fa8c | 203 | if (remaining) { |
hudakz | 1:1f2d9982fa8c | 204 | reason = BCM2835_I2C_REASON_ERROR_DATA; |
hudakz | 1:1f2d9982fa8c | 205 | } |
hudakz | 1:1f2d9982fa8c | 206 | |
hudakz | 1:1f2d9982fa8c | 207 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE, BCM2835_BSC_S_DONE); |
hudakz | 1:1f2d9982fa8c | 208 | |
hudakz | 1:1f2d9982fa8c | 209 | return reason; |
hudakz | 1:1f2d9982fa8c | 210 | } |
hudakz | 1:1f2d9982fa8c | 211 | |
hudakz | 1:1f2d9982fa8c | 212 | /** |
hudakz | 1:1f2d9982fa8c | 213 | * @brief Read len bytes from I2C sending a repeated start after writing the required register. |
hudakz | 1:1f2d9982fa8c | 214 | * @note |
hudakz | 1:1f2d9982fa8c | 215 | * @param |
hudakz | 1:1f2d9982fa8c | 216 | * @retval |
hudakz | 1:1f2d9982fa8c | 217 | */ |
hudakz | 1:1f2d9982fa8c | 218 | uint8_t I2C::read_repeat(char* buf, int len) |
hudakz | 1:1f2d9982fa8c | 219 | { |
hudakz | 1:1f2d9982fa8c | 220 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN / 4; |
hudakz | 1:1f2d9982fa8c | 221 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO / 4; |
hudakz | 1:1f2d9982fa8c | 222 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S / 4; |
hudakz | 1:1f2d9982fa8c | 223 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C / 4; |
hudakz | 1:1f2d9982fa8c | 224 | |
hudakz | 1:1f2d9982fa8c | 225 | uint32_t remaining = len; |
hudakz | 1:1f2d9982fa8c | 226 | uint32_t i = 0; |
hudakz | 1:1f2d9982fa8c | 227 | uint8_t reason = BCM2835_I2C_REASON_OK; |
hudakz | 1:1f2d9982fa8c | 228 | |
hudakz | 1:1f2d9982fa8c | 229 | // Clear FIFO |
hudakz | 1:1f2d9982fa8c | 230 | |
hudakz | 1:1f2d9982fa8c | 231 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1, BCM2835_BSC_C_CLEAR_1); |
hudakz | 1:1f2d9982fa8c | 232 | |
hudakz | 1:1f2d9982fa8c | 233 | // Clear Status |
hudakz | 1:1f2d9982fa8c | 234 | bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); |
hudakz | 1:1f2d9982fa8c | 235 | |
hudakz | 1:1f2d9982fa8c | 236 | // Set Data Length |
hudakz | 1:1f2d9982fa8c | 237 | bcm2835_peri_write_nb(dlen, 1); |
hudakz | 1:1f2d9982fa8c | 238 | |
hudakz | 1:1f2d9982fa8c | 239 | // Enable device and start transfer |
hudakz | 1:1f2d9982fa8c | 240 | bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN); |
hudakz | 1:1f2d9982fa8c | 241 | bcm2835_peri_write_nb(fifo, (uint32_t) _addr); |
hudakz | 1:1f2d9982fa8c | 242 | bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); |
hudakz | 1:1f2d9982fa8c | 243 | |
hudakz | 1:1f2d9982fa8c | 244 | // poll for transfer has started |
hudakz | 1:1f2d9982fa8c | 245 | while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_TA)) { |
hudakz | 1:1f2d9982fa8c | 246 | |
hudakz | 1:1f2d9982fa8c | 247 | // Linux may cause us to miss entire transfer stage |
hudakz | 1:1f2d9982fa8c | 248 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_DONE) |
hudakz | 1:1f2d9982fa8c | 249 | break; |
hudakz | 1:1f2d9982fa8c | 250 | } |
hudakz | 1:1f2d9982fa8c | 251 | |
hudakz | 1:1f2d9982fa8c | 252 | // Send a repeated start with read bit set in address |
hudakz | 1:1f2d9982fa8c | 253 | bcm2835_peri_write_nb(dlen, len); |
hudakz | 1:1f2d9982fa8c | 254 | bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ); |
hudakz | 1:1f2d9982fa8c | 255 | |
hudakz | 1:1f2d9982fa8c | 256 | // Wait for write to complete and first byte back. |
hudakz | 1:1f2d9982fa8c | 257 | wait_us(_i2c_byte_wait_us * 3); |
hudakz | 1:1f2d9982fa8c | 258 | |
hudakz | 1:1f2d9982fa8c | 259 | // wait for transfer to complete |
hudakz | 1:1f2d9982fa8c | 260 | while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) { |
hudakz | 1:1f2d9982fa8c | 261 | |
hudakz | 1:1f2d9982fa8c | 262 | // we must empty the FIFO as it is populated and not use any delay |
hudakz | 1:1f2d9982fa8c | 263 | while (remaining && bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) { |
hudakz | 1:1f2d9982fa8c | 264 | |
hudakz | 1:1f2d9982fa8c | 265 | // Read from FIFO, no barrier |
hudakz | 1:1f2d9982fa8c | 266 | buf[i] = bcm2835_peri_read_nb(fifo); |
hudakz | 1:1f2d9982fa8c | 267 | i++; |
hudakz | 1:1f2d9982fa8c | 268 | remaining--; |
hudakz | 1:1f2d9982fa8c | 269 | } |
hudakz | 1:1f2d9982fa8c | 270 | } |
hudakz | 1:1f2d9982fa8c | 271 | |
hudakz | 1:1f2d9982fa8c | 272 | // transfer has finished - grab any remaining stuff in FIFO |
hudakz | 1:1f2d9982fa8c | 273 | while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) { |
hudakz | 1:1f2d9982fa8c | 274 | |
hudakz | 1:1f2d9982fa8c | 275 | // Read from FIFO, no barrier |
hudakz | 1:1f2d9982fa8c | 276 | buf[i] = bcm2835_peri_read_nb(fifo); |
hudakz | 1:1f2d9982fa8c | 277 | i++; |
hudakz | 1:1f2d9982fa8c | 278 | remaining--; |
hudakz | 1:1f2d9982fa8c | 279 | } |
hudakz | 1:1f2d9982fa8c | 280 | |
hudakz | 1:1f2d9982fa8c | 281 | // Received a NACK |
hudakz | 1:1f2d9982fa8c | 282 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { |
hudakz | 1:1f2d9982fa8c | 283 | reason = BCM2835_I2C_REASON_ERROR_NACK; |
hudakz | 1:1f2d9982fa8c | 284 | } |
hudakz | 1:1f2d9982fa8c | 285 | |
hudakz | 1:1f2d9982fa8c | 286 | // Received Clock Stretch Timeout |
hudakz | 1:1f2d9982fa8c | 287 | else |
hudakz | 1:1f2d9982fa8c | 288 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { |
hudakz | 1:1f2d9982fa8c | 289 | reason = BCM2835_I2C_REASON_ERROR_CLKT; |
hudakz | 1:1f2d9982fa8c | 290 | } |
hudakz | 1:1f2d9982fa8c | 291 | |
hudakz | 1:1f2d9982fa8c | 292 | // Not all data is sent |
hudakz | 1:1f2d9982fa8c | 293 | else |
hudakz | 1:1f2d9982fa8c | 294 | if (remaining) { |
hudakz | 1:1f2d9982fa8c | 295 | reason = BCM2835_I2C_REASON_ERROR_DATA; |
hudakz | 1:1f2d9982fa8c | 296 | } |
hudakz | 1:1f2d9982fa8c | 297 | |
hudakz | 1:1f2d9982fa8c | 298 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE, BCM2835_BSC_S_DONE); |
hudakz | 1:1f2d9982fa8c | 299 | |
hudakz | 1:1f2d9982fa8c | 300 | return reason; |
hudakz | 1:1f2d9982fa8c | 301 | } |
hudakz | 1:1f2d9982fa8c | 302 | |
hudakz | 1:1f2d9982fa8c | 303 | /** |
hudakz | 1:1f2d9982fa8c | 304 | * @brief |
hudakz | 1:1f2d9982fa8c | 305 | * @note |
hudakz | 1:1f2d9982fa8c | 306 | * @param |
hudakz | 1:1f2d9982fa8c | 307 | * @retval |
hudakz | 1:1f2d9982fa8c | 308 | */ |
hudakz | 1:1f2d9982fa8c | 309 | int I2C::write(const char* buf, int len) |
hudakz | 1:1f2d9982fa8c | 310 | { |
hudakz | 1:1f2d9982fa8c | 311 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN / 4; |
hudakz | 1:1f2d9982fa8c | 312 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO / 4; |
hudakz | 1:1f2d9982fa8c | 313 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S / 4; |
hudakz | 1:1f2d9982fa8c | 314 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C / 4; |
hudakz | 1:1f2d9982fa8c | 315 | |
hudakz | 1:1f2d9982fa8c | 316 | uint32_t remaining = len; |
hudakz | 1:1f2d9982fa8c | 317 | uint32_t i = 0; |
hudakz | 1:1f2d9982fa8c | 318 | uint8_t reason = BCM2835_I2C_REASON_OK; |
hudakz | 1:1f2d9982fa8c | 319 | |
hudakz | 1:1f2d9982fa8c | 320 | // Clear FIFO |
hudakz | 1:1f2d9982fa8c | 321 | |
hudakz | 1:1f2d9982fa8c | 322 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1, BCM2835_BSC_C_CLEAR_1); |
hudakz | 1:1f2d9982fa8c | 323 | |
hudakz | 1:1f2d9982fa8c | 324 | // Clear Status |
hudakz | 1:1f2d9982fa8c | 325 | bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); |
hudakz | 1:1f2d9982fa8c | 326 | |
hudakz | 1:1f2d9982fa8c | 327 | // Set Data Length |
hudakz | 1:1f2d9982fa8c | 328 | bcm2835_peri_write_nb(dlen, len); |
hudakz | 1:1f2d9982fa8c | 329 | |
hudakz | 1:1f2d9982fa8c | 330 | // pre populate FIFO with max buffer |
hudakz | 1:1f2d9982fa8c | 331 | while (remaining && (i < BCM2835_BSC_FIFO_SIZE)) { |
hudakz | 1:1f2d9982fa8c | 332 | bcm2835_peri_write_nb(fifo, buf[i]); |
hudakz | 1:1f2d9982fa8c | 333 | i++; |
hudakz | 1:1f2d9982fa8c | 334 | remaining--; |
hudakz | 1:1f2d9982fa8c | 335 | } |
hudakz | 1:1f2d9982fa8c | 336 | |
hudakz | 1:1f2d9982fa8c | 337 | // Enable device and start transfer |
hudakz | 1:1f2d9982fa8c | 338 | bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); |
hudakz | 1:1f2d9982fa8c | 339 | |
hudakz | 1:1f2d9982fa8c | 340 | // Transfer is over when BCM2835_BSC_S_DONE |
hudakz | 1:1f2d9982fa8c | 341 | while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) { |
hudakz | 1:1f2d9982fa8c | 342 | while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_TXD)) { |
hudakz | 1:1f2d9982fa8c | 343 | |
hudakz | 1:1f2d9982fa8c | 344 | // Write to FIFO, no barrier |
hudakz | 1:1f2d9982fa8c | 345 | bcm2835_peri_write_nb(fifo, buf[i]); |
hudakz | 1:1f2d9982fa8c | 346 | i++; |
hudakz | 1:1f2d9982fa8c | 347 | remaining--; |
hudakz | 1:1f2d9982fa8c | 348 | } |
hudakz | 1:1f2d9982fa8c | 349 | } |
hudakz | 1:1f2d9982fa8c | 350 | |
hudakz | 1:1f2d9982fa8c | 351 | // Received a NACK |
hudakz | 1:1f2d9982fa8c | 352 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { |
hudakz | 1:1f2d9982fa8c | 353 | reason = BCM2835_I2C_REASON_ERROR_NACK; |
hudakz | 1:1f2d9982fa8c | 354 | } |
hudakz | 1:1f2d9982fa8c | 355 | |
hudakz | 1:1f2d9982fa8c | 356 | // Received Clock Stretch Timeout |
hudakz | 1:1f2d9982fa8c | 357 | else |
hudakz | 1:1f2d9982fa8c | 358 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { |
hudakz | 1:1f2d9982fa8c | 359 | reason = BCM2835_I2C_REASON_ERROR_CLKT; |
hudakz | 1:1f2d9982fa8c | 360 | } |
hudakz | 1:1f2d9982fa8c | 361 | |
hudakz | 1:1f2d9982fa8c | 362 | // Not all data is sent |
hudakz | 1:1f2d9982fa8c | 363 | else |
hudakz | 1:1f2d9982fa8c | 364 | if (remaining) { |
hudakz | 1:1f2d9982fa8c | 365 | reason = BCM2835_I2C_REASON_ERROR_DATA; |
hudakz | 1:1f2d9982fa8c | 366 | } |
hudakz | 1:1f2d9982fa8c | 367 | |
hudakz | 1:1f2d9982fa8c | 368 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE, BCM2835_BSC_S_DONE); |
hudakz | 1:1f2d9982fa8c | 369 | |
hudakz | 1:1f2d9982fa8c | 370 | return reason; |
hudakz | 1:1f2d9982fa8c | 371 | } |
hudakz | 1:1f2d9982fa8c | 372 | |
hudakz | 1:1f2d9982fa8c | 373 | // Exposes the physical address defined in the passed structure using mmap on /dev/mem |
hudakz | 1:1f2d9982fa8c | 374 | int I2C::map_peripheral(struct bcm2835_peripheral* p) |
hudakz | 1:1f2d9982fa8c | 375 | { |
hudakz | 1:1f2d9982fa8c | 376 | // Open /dev/mem |
hudakz | 1:1f2d9982fa8c | 377 | |
hudakz | 1:1f2d9982fa8c | 378 | if ((p->mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) { |
hudakz | 1:1f2d9982fa8c | 379 | printf("Failed to open /dev/mem, try checking permissions.\n"); |
hudakz | 1:1f2d9982fa8c | 380 | return -1; |
hudakz | 1:1f2d9982fa8c | 381 | } |
hudakz | 1:1f2d9982fa8c | 382 | |
hudakz | 1:1f2d9982fa8c | 383 | p->map = mmap |
hudakz | 1:1f2d9982fa8c | 384 | ( |
hudakz | 1:1f2d9982fa8c | 385 | NULL, |
hudakz | 1:1f2d9982fa8c | 386 | BLOCK_SIZE, |
hudakz | 1:1f2d9982fa8c | 387 | PROT_READ | PROT_WRITE, |
hudakz | 1:1f2d9982fa8c | 388 | MAP_SHARED, |
hudakz | 1:1f2d9982fa8c | 389 | p->mem_fd, // File descriptor to physical memory virtual file '/dev/mem' |
hudakz | 1:1f2d9982fa8c | 390 | p->addr_p // Address in physical map that we want this memory block to expose |
hudakz | 1:1f2d9982fa8c | 391 | ); |
hudakz | 1:1f2d9982fa8c | 392 | |
hudakz | 1:1f2d9982fa8c | 393 | if (p->map == MAP_FAILED) { |
hudakz | 1:1f2d9982fa8c | 394 | perror("mmap"); |
hudakz | 1:1f2d9982fa8c | 395 | return -1; |
hudakz | 1:1f2d9982fa8c | 396 | } |
hudakz | 1:1f2d9982fa8c | 397 | |
hudakz | 1:1f2d9982fa8c | 398 | p->addr = (volatile unsigned int*)p->map; |
hudakz | 1:1f2d9982fa8c | 399 | |
hudakz | 1:1f2d9982fa8c | 400 | return 0; |
hudakz | 1:1f2d9982fa8c | 401 | } |
hudakz | 1:1f2d9982fa8c | 402 | |
hudakz | 1:1f2d9982fa8c | 403 | /** |
hudakz | 1:1f2d9982fa8c | 404 | * @brief |
hudakz | 1:1f2d9982fa8c | 405 | * @note |
hudakz | 1:1f2d9982fa8c | 406 | * @param |
hudakz | 1:1f2d9982fa8c | 407 | * @retval |
hudakz | 1:1f2d9982fa8c | 408 | */ |
hudakz | 1:1f2d9982fa8c | 409 | void I2C::unmap_peripheral(struct bcm2835_peripheral* p) |
hudakz | 1:1f2d9982fa8c | 410 | { |
hudakz | 1:1f2d9982fa8c | 411 | munmap(p->map, BLOCK_SIZE); |
hudakz | 1:1f2d9982fa8c | 412 | unistd::close(p->mem_fd); |
hudakz | 1:1f2d9982fa8c | 413 | } |
hudakz | 1:1f2d9982fa8c | 414 | |
hudakz | 1:1f2d9982fa8c | 415 | /** |
hudakz | 1:1f2d9982fa8c | 416 | * @brief |
hudakz | 1:1f2d9982fa8c | 417 | * @note |
hudakz | 1:1f2d9982fa8c | 418 | * @param |
hudakz | 1:1f2d9982fa8c | 419 | * @retval |
hudakz | 1:1f2d9982fa8c | 420 | */ |
hudakz | 1:1f2d9982fa8c | 421 | void I2C::wait_i2c_done() |
hudakz | 1:1f2d9982fa8c | 422 | { |
hudakz | 1:1f2d9982fa8c | 423 | //Wait till done, let's use a timeout just in case |
hudakz | 1:1f2d9982fa8c | 424 | int timeout = 50; |
hudakz | 1:1f2d9982fa8c | 425 | while ((!((BSC0_S) & BSC_S_DONE)) && --timeout) { |
hudakz | 1:1f2d9982fa8c | 426 | unistd::usleep(1000); |
hudakz | 1:1f2d9982fa8c | 427 | } |
hudakz | 1:1f2d9982fa8c | 428 | |
hudakz | 1:1f2d9982fa8c | 429 | if (timeout == 0) |
hudakz | 1:1f2d9982fa8c | 430 | printf("wait_i2c_done() timeout. Something went wrong.\n"); |
hudakz | 1:1f2d9982fa8c | 431 | } |