#include <stdio.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <sys/mman.h> #include "bcm2835.h" struct bcm2835_peripheral gpio = {GPIO_BASE, 0}; struct bcm2835_peripheral bsc0 = {BSC0_BASE, 0}; struct bcm2835_peripheral bsc1 = {BSC1_BASE, 0}; struct bcm2835_peripheral timer_arm = {TIMER_ARM_BASE, 0}; // Exposes the physical address defined in the passed structure using mmap on /dev/mem int map_peripheral(struct bcm2835_peripheral *p) { if(p->init_count > 0) { p->init_count++; return 0; } // Open /dev/mem if ((p->mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { printf("Failed to open /dev/mem, try checking permissions.\n"); return -1; } p->map = mmap( NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, p->mem_fd, // File descriptor to physical memory virtual file '/dev/mem' p->addr_p // Address in physical map that we want this memory block to expose ); if (p->map == MAP_FAILED) { perror("mmap"); return -1; } p->addr = (volatile unsigned int *)p->map; p->init_count++; return 0; } void unmap_peripheral(struct bcm2835_peripheral *p) { p->init_count--; if(p->init_count == 0) { munmap(p->map, BLOCK_SIZE); close(p->mem_fd); } } // Function to wait for the I2C transaction to complete void wait_i2c_done() { while((!((BSC1_S) & BSC_S_DONE))) { usleep(100); } } // Function to write data to an I2C device via the FIFO. This doesn't refill the FIFO, so writes are limited to 16 bytes // including the register address. len specifies the number of bytes in the buffer. void i2c_write(char dev_addr, char reg_addr, char *buf, unsigned short len) { int idx; BSC1_A = dev_addr; BSC1_DLEN = len + 1; // one byte for the register address, plus the buffer length BSC1_FIFO = reg_addr; // start register address for(idx=0; idx < len; idx++) BSC1_FIFO = buf[idx]; BSC1_S = CLEAR_STATUS; // Reset status bits (see #define) BSC1_C = START_WRITE; // Start Write (see #define) wait_i2c_done(); } // Function to read a number of bytes into a buffer from the FIFO of the I2C controller void i2c_read(char dev_addr, char reg_addr, char *buf, unsigned short len) { i2c_write(dev_addr, reg_addr, NULL, 0); unsigned short bufidx = 0; memset(buf, 0, len); // clear the buffer BSC1_DLEN = len; BSC1_S = CLEAR_STATUS; // Reset status bits (see #define) BSC1_C = START_READ; // Start Read after clearing FIFO (see #define) do { // Wait for some data to appear in the FIFO while((BSC1_S & BSC_S_TA) && !(BSC1_S & BSC_S_RXD)); // Consume the FIFO while((BSC1_S & BSC_S_RXD) && (bufidx < len)) { buf[bufidx++] = BSC1_FIFO; } } while((!(BSC1_S & BSC_S_DONE))); } void dump_bsc_status() { unsigned int s = BSC1_S; printf("BSC0_S: ERR=%d RXF=%d TXE=%d RXD=%d TXD=%d RXR=%d TXW=%d DONE=%d TA=%d\n", (s & BSC_S_ERR) != 0, (s & BSC_S_RXF) != 0, (s & BSC_S_TXE) != 0, (s & BSC_S_RXD) != 0, (s & BSC_S_TXD) != 0, (s & BSC_S_RXR) != 0, (s & BSC_S_TXW) != 0, (s & BSC_S_DONE) != 0, (s & BSC_S_TA) != 0 ); }