Zoltan Hudak / mbedPi
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Peripheral.cpp Source File

Peripheral.cpp

00001 //#include "mbed.h"
00002 #include "BCM2835.h"
00003 #include "Thread.h"
00004 #include "ThisThread.h"
00005 #include "Peripheral.h"
00006 
00007 struct bcm2835_peripheral   bsc_rev1 = { BCM2835_PERI_BASE + 0X205000, 0, 0, 0 };
00008 struct bcm2835_peripheral   bsc_rev2 = { BCM2835_PERI_BASE + 0X804000, 0, 0, 0 };
00009 struct bcm2835_peripheral   bsc0;
00010 struct bcm2835_peripheral   gpio = { BCM2835_PERI_BASE + 0x200000, 0, 0, 0 };
00011 
00012 timeval  start_program, end_point;
00013 
00014 off_t                       bcm2835_peripherals_base = BCM2835_PERI_BASE;
00015 size_t                      bcm2835_peripherals_size = BCM2835_PERI_SIZE;
00016 volatile uint32_t*          bcm2835_peripherals;
00017 volatile uint32_t*          bcm2835_pwm  = (uint32_t *)MAP_FAILED;
00018 volatile uint32_t*          bcm2835_clk  = (uint32_t *)MAP_FAILED;
00019 volatile uint32_t*          bcm2835_bsc1 = (uint32_t *)MAP_FAILED;
00020 volatile uint32_t*          bcm2835_spi0 = (uint32_t *)MAP_FAILED;
00021 volatile uint32_t*          bcm2835_st  = (uint32_t *)MAP_FAILED;
00022 
00023 
00024 //Constructor
00025 Peripheral::Peripheral()
00026 {
00027     REV = getBoardRev();
00028     if (map_peripheral(&gpio) == -1) {
00029         printf("Failed to map the physical GPIO registers into the virtual memory space.\n");
00030     }
00031 
00032     memfd = -1;
00033 
00034     // Open the master /dev/memory device
00035     if ((memfd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
00036         fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n", strerror(errno));
00037         exit(1);
00038     }
00039 
00040     bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, bcm2835_peripherals_base);
00041     if (bcm2835_peripherals == MAP_FAILED)
00042         exit(1);
00043 
00044     /* Now compute the base addresses of various peripherals,
00045     // which are at fixed offsets within the mapped peripherals block
00046     // Caution: bcm2835_peripherals is uint32_t*, so divide offsets by 4
00047     */
00048     bcm2835_pwm  = bcm2835_peripherals + BCM2835_GPIO_PWM/4;
00049     bcm2835_clk  = bcm2835_peripherals + BCM2835_CLOCK_BASE/4;
00050     bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4;
00051     bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; /* I2C */
00052     bcm2835_st   = bcm2835_peripherals + BCM2835_ST_BASE/4;
00053 
00054     // start timer
00055     gettimeofday(&start_program, NULL);
00056 }
00057 
00058 //Destructor
00059 Peripheral::~Peripheral()
00060 {
00061     unmap_peripheral(&gpio);
00062 
00063     bcm2835_pwm  = (uint32_t *)MAP_FAILED;
00064     bcm2835_clk  = (uint32_t *)MAP_FAILED;
00065     bcm2835_spi0 = (uint32_t *)MAP_FAILED;
00066     bcm2835_bsc1 = (uint32_t *)MAP_FAILED;
00067 }
00068 
00069 /*******************
00070  * Private methods *
00071  *******************/
00072 
00073 // Exposes the physical address defined in the passed structure using mmap on /dev/mem
00074 int Peripheral::map_peripheral(struct bcm2835_peripheral* p)
00075 {
00076     // Open /dev/mem
00077 
00078     if ((p->mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
00079         printf("Failed to open /dev/mem, try checking permissions.\n");
00080         return -1;
00081     }
00082 
00083     p->map = mmap
00084         (
00085             NULL,
00086             BLOCK_SIZE,
00087             PROT_READ | PROT_WRITE,
00088             MAP_SHARED,
00089             p->mem_fd,  // File descriptor to physical memory virtual file '/dev/mem'
00090             p->addr_p   // Address in physical map that we want this memory block to expose
00091         );
00092 
00093     if (p->map == MAP_FAILED) {
00094         perror("mmap");
00095         return -1;
00096     }
00097 
00098     p->addr = (volatile unsigned int*)p->map;
00099 
00100     return 0;
00101 }
00102 
00103 /**
00104  * @brief
00105  * @note
00106  * @param
00107  * @retval
00108  */
00109 void Peripheral::unmap_peripheral(struct bcm2835_peripheral* p)
00110 {
00111     munmap(p->map, BLOCK_SIZE);
00112     unistd::close(p->mem_fd);
00113 }
00114 
00115 //
00116 // Low level convenience functions
00117 //
00118 
00119 /**
00120  * @brief
00121  * @note
00122  * @param
00123  * @retval
00124  */
00125 uint32_t* mapmem(const char* msg, size_t size, int fd, off_t off)
00126 {
00127     uint32_t*   map = (uint32_t*)mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off);
00128     if (MAP_FAILED == map)
00129         fprintf(stderr, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno));
00130     return map;
00131 }
00132 
00133 // safe read from peripheral
00134 uint32_t bcm2835_peri_read(volatile uint32_t* paddr)
00135 {
00136     uint32_t    ret = *paddr;
00137     ret = *paddr;
00138     return ret;
00139 }
00140 
00141 // read from peripheral without the read barrier
00142 uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr)
00143 {
00144     return *paddr;
00145 }
00146 
00147 // safe write to peripheral
00148 void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value)
00149 {
00150     *paddr = value;
00151     *paddr = value;
00152 }
00153 
00154 // write to peripheral without the write barrier
00155 void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value)
00156 {
00157     *paddr = value;
00158 }
00159 
00160 // Set/clear only the bits in value covered by the mask
00161 void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask)
00162 {
00163     uint32_t    v = bcm2835_peri_read(paddr);
00164     v = (v &~mask) | (value & mask);
00165     bcm2835_peri_write(paddr, v);
00166 }
00167 
00168 /**
00169  * @brief
00170  * @note
00171  * @param
00172  * @retval
00173  */
00174 int getBoardRev()
00175 {
00176     FILE*       cpu_info;
00177     char        line[120];
00178     char*       c, finalChar;
00179     //static int  rev = 0;
00180 
00181     if (REV != 0)
00182         return REV;
00183 
00184     if ((cpu_info = fopen("/proc/cpuinfo", "r")) == NULL) {
00185         fprintf(stderr, "Unable to open /proc/cpuinfo. Cannot determine board reivision.\n");
00186         exit(1);
00187     }
00188 
00189     while (fgets(line, 120, cpu_info) != NULL) {
00190         if (strncmp(line, "Revision", 8) == 0)
00191             break;
00192     }
00193 
00194     fclose(cpu_info);
00195 
00196     if (line == NULL) {
00197         fprintf(stderr, "Unable to determine board revision from /proc/cpuinfo.\n");
00198         exit(1);
00199     }
00200 
00201     for (c = line; *c; ++c)
00202         if (isdigit(*c))
00203             break;
00204 
00205     if (!isdigit(*c)) {
00206         fprintf(stderr, "Unable to determine board revision from /proc/cpuinfo\n");
00207         fprintf(stderr, "  (Info not found in: %s\n", line);
00208         exit(1);
00209     }
00210 
00211     finalChar = c[strlen(c) - 2];
00212 
00213     if ((finalChar == '2') || (finalChar == '3')) {
00214         bsc0 = bsc_rev1;
00215         return 1;
00216     }
00217     else {
00218         bsc0 = bsc_rev2;
00219         return 2;
00220     }
00221 }
00222 
00223 /**
00224  * @brief
00225  * @note
00226  * @param
00227  * @retval
00228  */
00229 void attachInterrupt(PinName p, void (*f) (), Digivalue m)
00230 {
00231     int                 GPIOPin = p;
00232     pthread_t*          threadId = getThreadIdFromPin(p);
00233     struct ThreadArg*   threadArgs = (ThreadArg*)malloc(sizeof(ThreadArg));
00234     threadArgs->func = f;
00235     threadArgs->pin = GPIOPin;
00236 
00237     //Export pin for interrupt
00238     FILE*   fp = fopen("/sys/class/gpio/export", "w");
00239     if (fp == NULL) {
00240         fprintf(stderr, "Unable to export pin %d for interrupt\n", p);
00241         exit(1);
00242     }
00243     else {
00244         fprintf(fp, "%d", GPIOPin);
00245     }
00246 
00247     fclose(fp);
00248 
00249     //The system to create the file /sys/class/gpio/gpio<GPIO number>
00250     //So we wait a bit
00251     ThisThread::sleep_for_ms(1);
00252 
00253     char*   interruptFile = NULL;
00254     asprintf(&interruptFile, "/sys/class/gpio/gpio%d/edge", GPIOPin);
00255 
00256     //Set detection condition
00257     fp = fopen(interruptFile, "w");
00258     if (fp == NULL) {
00259         fprintf(stderr, "Unable to set detection type on pin %d\n", p);
00260         exit(1);
00261     }
00262     else {
00263         switch (m) {
00264             case RISING:
00265                 fprintf(fp, "rising");
00266                 break;
00267 
00268             case FALLING:
00269                 fprintf(fp, "falling");
00270                 break;
00271 
00272             default:
00273                 fprintf(fp, "both");
00274                 break;
00275         }
00276     }
00277 
00278     fclose(fp);
00279 
00280     if (*threadId == 0) {
00281 
00282         //Create a thread passing the pin and function
00283         pthread_create(threadId, NULL, threadFunction, (void*)threadArgs);
00284     }
00285     else {
00286 
00287         //First cancel the existing thread for that pin
00288         pthread_cancel(*threadId);
00289 
00290         //Create a thread passing the pin, function and mode
00291         pthread_create(threadId, NULL, threadFunction, (void*)threadArgs);
00292     }
00293 }
00294 
00295 /**
00296  * @brief
00297  * @note
00298  * @param
00299  * @retval
00300  */
00301 void detachInterrupt(PinName p)
00302 {
00303     int     GPIOPin = p;
00304 
00305     FILE*   fp = fopen("/sys/class/gpio/unexport", "w");
00306     if (fp == NULL) {
00307         fprintf(stderr, "Unable to unexport pin %d for interrupt\n", p);
00308         exit(1);
00309     }
00310     else {
00311         fprintf(fp, "%d", GPIOPin);
00312     }
00313 
00314     fclose(fp);
00315 
00316     pthread_t*  threadId = getThreadIdFromPin(p);
00317     pthread_cancel(*threadId);
00318 }
00319 
00320 Peripheral  peripheral = Peripheral();
00321 
00322