You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
395 lines
13 KiB
395 lines
13 KiB
/*
|
|
* bbb-gpmc-test
|
|
*
|
|
* Copyright (C) 2014 Timothy Pearson <kb9vqf@pearsoncomputing.net> (Beaglebone Black)
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
|
|
/** BEGIN: Low-Level I/O Implementation **/
|
|
|
|
// Beaglebone Black GPMC driver
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
#include <fcntl.h>
|
|
|
|
#define MEMORY_SPACE_ADDRESS_BITS 16
|
|
|
|
#define GPMC_BASE 0x50000000
|
|
#define GPMC_REGLEN 0x10000000
|
|
|
|
#define GPMC_CHIPSELECTCONFIGDISPLACEMENT (0x30 / 4)
|
|
|
|
#define GPMC_CONFIG (0x50 / 4)
|
|
#define GPMC_CONFIG1 (0x60 / 4)
|
|
#define GPMC_CONFIG2 (0x64 / 4)
|
|
#define GPMC_CONFIG3 (0x68 / 4)
|
|
#define GPMC_CONFIG4 (0x6c / 4)
|
|
#define GPMC_CONFIG5 (0x70 / 4)
|
|
#define GPMC_CONFIG6 (0x74 / 4)
|
|
#define GPMC_CONFIG7 (0x78 / 4)
|
|
|
|
#define MEMORY_SIZE (1 << MEMORY_SPACE_ADDRESS_BITS)
|
|
|
|
int mem_fd = 0;
|
|
int gpmc_mem_fd = 0;
|
|
char *gpio_mem, *gpio_map, *gpmc_map;
|
|
|
|
// I/O access
|
|
static volatile unsigned int *gpio = NULL;
|
|
static volatile unsigned char *gpio_char = NULL;
|
|
static volatile unsigned long long *gpio_longlong = NULL;
|
|
static volatile unsigned int *gpmc = NULL;
|
|
|
|
static void gpmc_mapregisters()
|
|
{
|
|
/* open /dev/mem */
|
|
if ((gpmc_mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
|
|
printf("can't open /dev/mem \n");
|
|
exit (-1);
|
|
}
|
|
|
|
/* mmap GPMC */
|
|
gpmc_map = (char *)mmap(
|
|
0,
|
|
GPMC_REGLEN,
|
|
PROT_READ|PROT_WRITE,
|
|
MAP_SHARED,
|
|
gpmc_mem_fd,
|
|
GPMC_BASE
|
|
);
|
|
|
|
if (gpmc_map == MAP_FAILED) {
|
|
printf("mmap error %d\n", (int)gpmc_map);
|
|
exit (-1);
|
|
}
|
|
|
|
// Always use volatile pointer!
|
|
gpmc = (volatile unsigned *)gpmc_map;
|
|
}
|
|
|
|
static void gpmc_unmapregisters()
|
|
{
|
|
munmap((void*) gpmc, GPMC_REGLEN);
|
|
if (gpmc_mem_fd != -1) {
|
|
close(gpmc_mem_fd);
|
|
}
|
|
}
|
|
|
|
static void gpmc_setup(void)
|
|
{
|
|
// WARNING: The GPMC runs at the L3 clock frequency!
|
|
// It is not well documented, but that frequency seems to be 200MHz on the AM335x series of chips
|
|
|
|
gpmc_mapregisters();
|
|
|
|
if (gpmc != NULL) {
|
|
int chipselect = 0;
|
|
int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect;
|
|
|
|
// disable before playing with the registers
|
|
*(gpmc + displacement + GPMC_CONFIG7) = 0x00000000;
|
|
|
|
*(gpmc + displacement + GPMC_CONFIG) = 0x00000000; // Unlimited address space
|
|
*(gpmc + displacement + GPMC_CONFIG1) = 0x00000000; // No burst, async, 8-bit, non multiplexed
|
|
// *(gpmc + displacement + GPMC_CONFIG1) = 0x00000010; // No burst, async, 8-bit, non multiplexed, x2 slowed cycle timing
|
|
|
|
// // 200MHz compatible SRAM device
|
|
// *(gpmc + displacement + GPMC_CONFIG2) = 0x00000800; // Assert CS on fclk 0, deassert CS on fclk 8
|
|
// *(gpmc + displacement + GPMC_CONFIG3) = 0x00000200; // Assert ADV on fclk0, deassert ADV on fclk2
|
|
// *(gpmc + displacement + GPMC_CONFIG4) = 0x06020802; // Assert WE on fclk2, deassert WE on fclk6, assert OE on fclk2, deassert OE on fclk8
|
|
// *(gpmc + displacement + GPMC_CONFIG5) = 0x00060808; // Data valid on fclk 6, cycle time 8 fclks
|
|
|
|
// // 100MHz compatible SRAM device
|
|
// *(gpmc + displacement + GPMC_CONFIG2) = 0x00001000; // Assert CS on fclk0, deassert CS on fclk16
|
|
// *(gpmc + displacement + GPMC_CONFIG3) = 0x00000400; // Assert ADV on fclk 0, deassert ADV on fclk 4
|
|
// *(gpmc + displacement + GPMC_CONFIG4) = 0x0c041004; // Assert WE on fclk4, deassert WE on fclk12, assert OE on fclk4, deassert OE on fclk16
|
|
// *(gpmc + displacement + GPMC_CONFIG5) = 0x000c1010; // Data valid on fclk 12, cycle time 16 fclks
|
|
|
|
// 50MHz compatible SRAM device
|
|
*(gpmc + displacement + GPMC_CONFIG2) = 0x00001f00; // Assert CS on fclk0, deassert CS on fclk31
|
|
*(gpmc + displacement + GPMC_CONFIG3) = 0x00000400; // Assert ADV on fclk 0, deassert ADV on fclk 4
|
|
*(gpmc + displacement + GPMC_CONFIG4) = 0x1f041f04; // Assert WE on fclk4, deassert WE on fclk31, assert OE on fclk4, deassert OE on fclk31
|
|
*(gpmc + displacement + GPMC_CONFIG5) = 0x00101f1f; // Data valid on fclk 16, cycle time 31 fclks
|
|
|
|
*(gpmc + displacement + GPMC_CONFIG6) = 0x00000000; // No back to back cycle restrictions
|
|
*(gpmc + displacement + GPMC_CONFIG7) = 0x00000e50; // CS0: Set base address 0x10000000, 32MB region, and enable CS
|
|
|
|
gpmc_unmapregisters();
|
|
}
|
|
}
|
|
|
|
void gpmc_dump_registers(void)
|
|
{
|
|
gpmc_mapregisters();
|
|
|
|
if (gpmc != NULL) {
|
|
int chipselect = 0;
|
|
int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect;
|
|
|
|
printf("GPMC_CONFIG0: %08x\n", *(gpmc + displacement + GPMC_CONFIG));
|
|
printf("GPMC_CONFIG1: %08x\n", *(gpmc + displacement + GPMC_CONFIG1));
|
|
printf("GPMC_CONFIG2: %08x\n", *(gpmc + displacement + GPMC_CONFIG2));
|
|
printf("GPMC_CONFIG3: %08x\n", *(gpmc + displacement + GPMC_CONFIG3));
|
|
printf("GPMC_CONFIG4: %08x\n", *(gpmc + displacement + GPMC_CONFIG4));
|
|
printf("GPMC_CONFIG5: %08x\n", *(gpmc + displacement + GPMC_CONFIG5));
|
|
printf("GPMC_CONFIG6: %08x\n", *(gpmc + displacement + GPMC_CONFIG6));
|
|
printf("GPMC_CONFIG7: %08x\n", *(gpmc + displacement + GPMC_CONFIG7));
|
|
}
|
|
|
|
gpmc_unmapregisters();
|
|
}
|
|
|
|
static void io_setup(void)
|
|
{
|
|
printf("sizeof int:\t%d\n", sizeof(int));
|
|
|
|
/* open /dev/mem */
|
|
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
|
|
printf("can't open /dev/mem \n");
|
|
exit (-1);
|
|
}
|
|
|
|
/* mmap GPIO */
|
|
gpio_map = (char *)mmap(
|
|
0,
|
|
MEMORY_SIZE,
|
|
PROT_READ|PROT_WRITE,
|
|
MAP_SHARED,
|
|
mem_fd,
|
|
0x10000000
|
|
);
|
|
|
|
if (gpio_map == MAP_FAILED) {
|
|
printf("mmap error %d\n", (int)gpio_map);
|
|
exit (-1);
|
|
}
|
|
|
|
// Always use volatile pointer!
|
|
gpio = (volatile unsigned *)gpio_map;
|
|
gpio_char = (volatile unsigned char *)gpio_map;
|
|
gpio_longlong =( volatile unsigned long long *)gpio_map;
|
|
|
|
// Select a test from the following blocks of code...
|
|
|
|
// // DEBUG ONLY
|
|
// // Clear out the mapped memory
|
|
// int i;
|
|
// for (i=0;i<0x3ff; i++) {
|
|
// *(gpio + i) = 0x00000000;
|
|
// }
|
|
|
|
// DEBUG ONLY
|
|
// Fill the mapped memory with a test pattern
|
|
// int j;
|
|
// for (j=0;j<0x00001000; j++) {
|
|
// *(gpio + j) = j;
|
|
// }
|
|
// int j;
|
|
// for (j=0;j<0x3ff; j++) {
|
|
// *(gpio + j) = j;
|
|
// }
|
|
|
|
#if 0
|
|
// DEBUG ONLY
|
|
// Looping memory test
|
|
unsigned int test_base = (MEMORY_SIZE/2);
|
|
unsigned int test_length = (MEMORY_SIZE/2);
|
|
unsigned int total_errors;
|
|
unsigned char error_count[MEMORY_SIZE];
|
|
int i;
|
|
int loop;
|
|
unsigned int overall_total_errors;
|
|
overall_total_errors = 0;
|
|
for (loop=0; loop<10;loop++) {
|
|
printf("Memory test loop %d\n", loop);
|
|
for (i=0; i<test_length; i++) {
|
|
error_count[i] = 0;
|
|
}
|
|
printf("\tTesting inversion pattern\n");
|
|
// Test with 0xaa
|
|
for (i=0;i<test_length; i++) {
|
|
*(gpio_char + test_base + i) = 0xaa;
|
|
}
|
|
for (i=0;i<test_length; i++) {
|
|
unsigned char result = *(gpio_char + test_base + i);
|
|
if ((result != 0xaa)) {
|
|
error_count[i] = error_count[i] + 1;
|
|
printf("\terror detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x)\n", i, result, 0xaa, (*(gpio_char + test_base + i)));
|
|
}
|
|
}
|
|
// Test with 0x55
|
|
for (i=0;i<test_length; i++) {
|
|
*(gpio_char + test_base + i) = 0x55;
|
|
}
|
|
for (i=0;i<test_length; i++) {
|
|
unsigned char result = *(gpio_char + test_base + i);
|
|
if ((result != 0x55)) {
|
|
error_count[i] = error_count[i] + 1;
|
|
printf("\terror detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x)\n", i, result, 0x55, (*(gpio_char + test_base + i)));
|
|
}
|
|
}
|
|
total_errors = 0;
|
|
for (i=0; i<test_length; i++) {
|
|
total_errors = total_errors + error_count[i];
|
|
if (error_count[i] > 0) {
|
|
printf("\t%d\terror(s) found at offset 0x%02x\n", error_count[i], i);
|
|
}
|
|
}
|
|
|
|
printf("\tTesting all ones/zeros\n");
|
|
// Test with 0xff
|
|
for (i=0;i<test_length; i++) {
|
|
*(gpio_char + test_base + i) = 0xff;
|
|
}
|
|
for (i=0;i<test_length; i++) {
|
|
unsigned char result = *(gpio_char + test_base + i);
|
|
if ((result != 0xff)) {
|
|
error_count[i] = error_count[i] + 1;
|
|
printf("\terror detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x)\n", i, result, 0xff, (*(gpio_char + test_base + i)));
|
|
}
|
|
}
|
|
// Test with 0x00
|
|
for (i=0;i<test_length; i++) {
|
|
*(gpio_char + test_base + i) = 0x00;
|
|
}
|
|
for (i=0;i<test_length; i++) {
|
|
unsigned char result = *(gpio_char + test_base + i);
|
|
if ((result != 0x00)) {
|
|
error_count[i] = error_count[i] + 1;
|
|
printf("\terror detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x)\n", i, result, 0x00, (*(gpio_char + test_base + i)));
|
|
}
|
|
}
|
|
|
|
printf("\tTesting alternating ones/zeros\n");
|
|
// Test with 0xff
|
|
for (i=0;i<test_length; i=i+2) {
|
|
*(gpio_char + test_base + i) = 0xff;
|
|
*(gpio_char + test_base + i + 1) = 0x00;
|
|
}
|
|
for (i=0;i<test_length; i=i+2) {
|
|
unsigned char result;
|
|
result = *(gpio_char + test_base + i);
|
|
if ((result != 0xff)) {
|
|
error_count[i] = error_count[i] + 1;
|
|
printf("\terror detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x)\n", i, result, 0xff, (*(gpio_char + test_base + i)));
|
|
}
|
|
result = *(gpio_char + test_base + i + 1);
|
|
if ((result != 0x00)) {
|
|
error_count[i] = error_count[i] + 1;
|
|
printf("\terror detected at offset 0x%02x (was 0x%02x, expected 0x%02x, second read attempt returned 0x%02x)\n", i, result, 0x00, (*(gpio_char + test_base + i)));
|
|
}
|
|
}
|
|
|
|
total_errors = 0;
|
|
for (i=0; i<test_length; i++) {
|
|
total_errors = total_errors + error_count[i];
|
|
if (error_count[i] > 0) {
|
|
printf("\t%d\terror(s) found at offset 0x%02x\n", error_count[i], i);
|
|
}
|
|
}
|
|
printf("\tTest region size:\t%d\n", test_length);
|
|
printf("\tTotal errors found:\t%d\n", total_errors);
|
|
fflush(stdout);
|
|
overall_total_errors = overall_total_errors + total_errors;
|
|
}
|
|
for (i=0;i<MEMORY_SIZE; i++) {
|
|
*(gpio_char + i) = 0;
|
|
}
|
|
printf("Total errors found over all loops:\t%d\n", overall_total_errors);
|
|
fflush(stdout);
|
|
return;
|
|
#endif
|
|
|
|
int j;
|
|
for (j=0;j<MEMORY_SIZE; j++) {
|
|
*(gpio_char + j) = ((unsigned char)j);
|
|
}
|
|
|
|
// // DEBUG ONLY
|
|
// // Prints the contents of the mapped memory
|
|
// int k;
|
|
// for (k=0;k<(MEMORY_SIZE/4); k++) {
|
|
// printf("0x%08x\t%08x\n", k, *(gpio + k));
|
|
// }
|
|
// fflush(stdout);
|
|
|
|
// DEBUG ONLY
|
|
// Prints the contents of the mapped memory
|
|
int k;
|
|
for (k=0;k<(MEMORY_SIZE/8); k++) {
|
|
printf("0x%08x\t%016llx\n", k, *(gpio_longlong + k));
|
|
}
|
|
fflush(stdout);
|
|
|
|
// // DEBUG ONLY
|
|
// // Excercise the memory space
|
|
// int l;
|
|
// while (1) {
|
|
// for (l=0;l<(MEMORY_SIZE/4); l++) {
|
|
// k = *(gpio + l);
|
|
// }
|
|
// }
|
|
|
|
// while (1) {
|
|
// printf("0x%08x\t0x%08x\t0x%08x\t0x%08x\r", *(gpio + 0), *(gpio + 1), *(gpio + 2), *(gpio + 3));
|
|
// usleep(1);
|
|
// }
|
|
|
|
// while (1) {
|
|
// printf("0x%08x\t0x%08x\t0x%08x\t0x%08x\r", *(gpio + 3), *(gpio + 2), *(gpio + 1), *(gpio + 0));
|
|
// usleep(1);
|
|
// }
|
|
|
|
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\n\r", *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0));
|
|
//
|
|
|
|
gpmc_dump_registers();
|
|
|
|
while (1) {
|
|
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 4), *(gpio_char + 5), *(gpio_char + 6), *(gpio_char + 7));
|
|
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 0x1000), *(gpio_char + 0x1001), *(gpio_char + 0x1002), *(gpio_char + 0x1003));
|
|
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 0x4000), *(gpio_char + 0x4001), *(gpio_char + 0x4002), *(gpio_char + 0x4003));
|
|
printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 0x0a), *(gpio_char + 0x0b), *(gpio_char + 0x0c), *(gpio_char + 0x0d));
|
|
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0x4000), *(gpio_char + 0x4001), *(gpio_char + 0x4002), *(gpio_char + 0x4003), *(gpio_char + 0x4004), *(gpio_char + 0x4005), *(gpio_char + 0x4006), *(gpio_char + 0x4007));
|
|
usleep(10);
|
|
}
|
|
}
|
|
|
|
static void io_shutdown(void)
|
|
{
|
|
//
|
|
}
|
|
|
|
/** END: Low-Level I/O Implementation **/
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
gpmc_setup();
|
|
printf("GPMC setup complete!\n"); fflush(stdout);
|
|
io_setup();
|
|
return 0;
|
|
}
|
|
|