324 lines
8.1 KiB
C
324 lines
8.1 KiB
C
//=============================================================================
|
|
//
|
|
//
|
|
// Gertboard Common code
|
|
//
|
|
// This file is part of the gertboard test suite
|
|
//
|
|
//
|
|
// Copyright (C) Gert Jan van Loo & Myra VanInwegen 2012
|
|
// No rights reserved
|
|
// You may treat this program as if it was in the public domain
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
//
|
|
// Notes:
|
|
// 1/ In some Linux systems (e.g. Debian) the UART is used by Linux.
|
|
// So for now do not demo the UART.
|
|
// 2/ At the moment (16-March-2012) there is no Linux driver for
|
|
// the audio yet so the PWM is free.
|
|
// This is likely to change and in that case the Linux
|
|
// audio/PWM driver must be disabled.
|
|
//
|
|
// This file contains code use by all the test programs for individual
|
|
// capabilities.
|
|
|
|
#include "gb_common.h"
|
|
|
|
#define BCM2708_PERI_BASE 0x20000000
|
|
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) /* Clocks */
|
|
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO */
|
|
#define PWM_BASE (BCM2708_PERI_BASE + 0x20C000) /* PWM */
|
|
#define SPI0_BASE (BCM2708_PERI_BASE + 0x204000) /* SPI0 controller */
|
|
#define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */
|
|
#define UART1_BASE (BCM2708_PERI_BASE + 0x215000) /* Uart 1 (not used) */
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <assert.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#define PAGE_SIZE (4*1024)
|
|
#define BLOCK_SIZE (4*1024)
|
|
|
|
int mem_fd;
|
|
char *clk_mem_orig, *clk_mem, *clk_map;
|
|
char *gpio_mem_orig, *gpio_mem, *gpio_map;
|
|
char *pwm_mem_orig, *pwm_mem, *pwm_map;
|
|
char *spi0_mem_orig, *spi0_mem, *spi0_map;
|
|
char *uart_mem_orig, *uart_mem, *uart_map;
|
|
|
|
// I/O access
|
|
volatile unsigned *gpio;
|
|
volatile unsigned *pwm;
|
|
volatile unsigned *clk;
|
|
volatile unsigned *spi0;
|
|
volatile unsigned *uart;
|
|
|
|
|
|
//
|
|
// GPIO
|
|
//
|
|
|
|
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
|
|
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
|
|
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
|
|
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
|
|
|
|
#define GPIO_SET0 *(gpio+7) // Set GPIO high bits 0-31
|
|
#define GPIO_SET1 *(gpio+8) // Set GPIO high bits 32-53
|
|
|
|
#define GPIO_CLR0 *(gpio+10) // Set GPIO low bits 0-31
|
|
#define GPIO_CLR1 *(gpio+11) // Set GPIO low bits 32-53
|
|
#define GPIO_PULL *(gpio+37) // Pull up/pull down
|
|
#define GPIO_PULLCLK0 *(gpio+38) // Pull up/pull down clock
|
|
|
|
|
|
//
|
|
// UART 0
|
|
//
|
|
|
|
#define UART0_BAUD_HI *(uart+9)
|
|
#define UART0_BAUD_LO *(uart+10)
|
|
|
|
|
|
void setup_io();
|
|
void restore_io();
|
|
|
|
//
|
|
// This is a software loop to wait
|
|
// a short while.
|
|
//
|
|
void short_wait()
|
|
{ int w;
|
|
for (w=0; w<100; w++)
|
|
{ w++;
|
|
w--;
|
|
}
|
|
} // short_wait
|
|
|
|
|
|
//
|
|
// Simple SW wait loop
|
|
//
|
|
void long_wait(int v)
|
|
{ int w;
|
|
while (v--)
|
|
for (w=-800000; w<800000; w++)
|
|
{ w++;
|
|
w--;
|
|
}
|
|
} // long_wait
|
|
|
|
|
|
//
|
|
// Set up memory regions to access the peripherals.
|
|
// This is a bit of 'magic' which you should not touch.
|
|
// It it also the part of the code which makes that
|
|
// you have to use 'sudo' to run this program.
|
|
//
|
|
void setup_io()
|
|
{ unsigned long extra;
|
|
|
|
/* open /dev/mem */
|
|
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
|
|
printf("Can't open /dev/mem\n");
|
|
printf("Did you forgot to use 'sudo .. ?'\n");
|
|
exit (-1);
|
|
}
|
|
|
|
/*
|
|
* mmap clock
|
|
*/
|
|
if ((clk_mem_orig = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
|
|
printf("allocation error \n");
|
|
exit (-1);
|
|
}
|
|
extra = (unsigned long)clk_mem_orig % PAGE_SIZE;
|
|
if (extra)
|
|
clk_mem = clk_mem_orig + PAGE_SIZE - extra;
|
|
else
|
|
clk_mem = clk_mem_orig;
|
|
|
|
clk_map = (unsigned char *)mmap(
|
|
(caddr_t)clk_mem,
|
|
BLOCK_SIZE,
|
|
PROT_READ|PROT_WRITE,
|
|
MAP_SHARED|MAP_FIXED,
|
|
mem_fd,
|
|
CLOCK_BASE
|
|
);
|
|
|
|
if ((long)clk_map < 0) {
|
|
printf("clk mmap error %d\n", (int)clk_map);
|
|
exit (-1);
|
|
}
|
|
clk = (volatile unsigned *)clk_map;
|
|
|
|
|
|
/*
|
|
* mmap GPIO
|
|
*/
|
|
if ((gpio_mem_orig = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
|
|
printf("allocation error \n");
|
|
exit (-1);
|
|
}
|
|
extra = (unsigned long)gpio_mem_orig % PAGE_SIZE;
|
|
if (extra)
|
|
gpio_mem = gpio_mem_orig + PAGE_SIZE - extra;
|
|
else
|
|
gpio_mem = gpio_mem_orig;
|
|
|
|
gpio_map = (unsigned char *)mmap(
|
|
(caddr_t)gpio_mem,
|
|
BLOCK_SIZE,
|
|
PROT_READ|PROT_WRITE,
|
|
MAP_SHARED|MAP_FIXED,
|
|
mem_fd,
|
|
GPIO_BASE
|
|
);
|
|
|
|
if ((long)gpio_map < 0) {
|
|
printf("gpio mmap error %d\n", (int)gpio_map);
|
|
exit (-1);
|
|
}
|
|
gpio = (volatile unsigned *)gpio_map;
|
|
|
|
/*
|
|
* mmap PWM
|
|
*/
|
|
if ((pwm_mem_orig = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
|
|
printf("allocation error \n");
|
|
exit (-1);
|
|
}
|
|
extra = (unsigned long)pwm_mem_orig % PAGE_SIZE;
|
|
if (extra)
|
|
pwm_mem = pwm_mem_orig + PAGE_SIZE - extra;
|
|
else
|
|
pwm_mem = pwm_mem_orig;
|
|
|
|
pwm_map = (unsigned char *)mmap(
|
|
(caddr_t)pwm_mem,
|
|
BLOCK_SIZE,
|
|
PROT_READ|PROT_WRITE,
|
|
MAP_SHARED|MAP_FIXED,
|
|
mem_fd,
|
|
PWM_BASE
|
|
);
|
|
|
|
if ((long)pwm_map < 0) {
|
|
printf("pwm mmap error %d\n", (int)pwm_map);
|
|
exit (-1);
|
|
}
|
|
pwm = (volatile unsigned *)pwm_map;
|
|
|
|
/*
|
|
* mmap SPI0
|
|
*/
|
|
if ((spi0_mem_orig = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
|
|
printf("allocation error \n");
|
|
exit (-1);
|
|
}
|
|
extra = (unsigned long)spi0_mem_orig % PAGE_SIZE;
|
|
if (extra)
|
|
spi0_mem = spi0_mem_orig + PAGE_SIZE - extra;
|
|
else
|
|
spi0_mem = spi0_mem_orig;
|
|
|
|
spi0_map = (unsigned char *)mmap(
|
|
(caddr_t)spi0_mem,
|
|
BLOCK_SIZE,
|
|
PROT_READ|PROT_WRITE,
|
|
MAP_SHARED|MAP_FIXED,
|
|
mem_fd,
|
|
SPI0_BASE
|
|
);
|
|
|
|
if ((long)spi0_map < 0) {
|
|
printf("spi0 mmap error %d\n", (int)spi0_map);
|
|
exit (-1);
|
|
}
|
|
spi0 = (volatile unsigned *)spi0_map;
|
|
|
|
/*
|
|
* mmap UART
|
|
*/
|
|
if ((uart_mem_orig = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
|
|
printf("allocation error \n");
|
|
exit (-1);
|
|
}
|
|
extra = (unsigned long)uart_mem_orig % PAGE_SIZE;
|
|
if (extra)
|
|
uart_mem = uart_mem_orig + PAGE_SIZE - extra;
|
|
else
|
|
uart_mem = uart_mem_orig;
|
|
|
|
uart_map = (unsigned char *)mmap(
|
|
(caddr_t)uart_mem,
|
|
BLOCK_SIZE,
|
|
PROT_READ|PROT_WRITE,
|
|
MAP_SHARED|MAP_FIXED,
|
|
mem_fd,
|
|
UART0_BASE
|
|
);
|
|
|
|
if ((long)uart_map < 0) {
|
|
printf("uart mmap error %d\n", (int)uart_map);
|
|
exit (-1);
|
|
}
|
|
uart = (volatile unsigned *)uart_map;
|
|
|
|
} // setup_io
|
|
|
|
//
|
|
// Undo what we did above
|
|
//
|
|
void restore_io()
|
|
{
|
|
munmap(uart_map,BLOCK_SIZE);
|
|
munmap(spi0_map,BLOCK_SIZE);
|
|
munmap(pwm_map,BLOCK_SIZE);
|
|
munmap(gpio_map,BLOCK_SIZE);
|
|
munmap(clk_map,BLOCK_SIZE);
|
|
// free memory
|
|
free(uart_mem_orig);
|
|
free(spi0_mem_orig);
|
|
free(pwm_mem_orig);
|
|
free(gpio_mem_orig);
|
|
free(clk_mem_orig);
|
|
} // restore_io
|
|
|
|
// simple routine to convert the last several bits of an integer to a string
|
|
// showing its binary value
|
|
// nbits is the number of bits in i to look at
|
|
// i is integer we want to show as a binary number
|
|
// we only look at the nbits least significant bits of i and we assume that
|
|
// s is at least nbits+1 characters long
|
|
void make_binary_string(int nbits, int i, char *s)
|
|
{ char *p;
|
|
int bit;
|
|
|
|
p = s;
|
|
for (bit = 1 << (nbits-1); bit > 0; bit = bit >> 1, p++)
|
|
*p = (i & bit) ? '1' : '0';
|
|
*p = '\0';
|
|
}
|