I'm having some trouble with some test code that I threw together that tries to run SPI through the /dev/mem device by manually manipulating the registers. The program always returns with a Bus Error as soon as I try to manipulate any registers in the SPI peripheral. I did some searching and found out that the peripheral clock may not be initialized so I added a few lines of code to try and do that. But unfortunately the Bus Error was still there. I'll post the code I'm using as well as the output at the end of the question here.
I also wanted to ask for some advice on my application, maybe someone here has some more experience with the 3359 than I do. I'm using a Beagle Bone and I've got to update 16 LED drivers every 150 microseconds. Is this a goal that can be realized with this platform or am I barking up the wrong tree here? It all seems possible to me in theory... If I was able to get each SPI port to chuck data at 24Mhz simultaneously it would only take 96 microseconds, and if I can run the LED drivers beyond the 33MHz spec (Ti TLC5951) and do 48Mhz, then I'd have even more headroom. I suspect DMA->SPI would be a necessity but I don't know if I should head down that path until someone wiser than me tells me I'm crazy for even trying ;)
Thanks a lot in advance for *any* insight you might have for me!
Source: Note register definitions come from AM335x StarterWare headers
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "mcspi.h"
#include "soc_AM335x.h"
#include "hw_cm_per.h"
int main()
{
static volatile uint32_t * spi0_base_addr;
static volatile uint32_t * clocks_base_addr;
printf("Opening raw memory...\n");
int memfd = open("/dev/mem", O_RDWR | O_SYNC);
if(memfd < 0) {
printf("Error opening memory!\n");
return -1;
}
printf("Mapping registers to user space...\n");
spi0_base_addr = (uint32_t *)mmap(0,getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, memfd, SOC_SPI_0_REGS);
clocks_base_addr = (uint32_t *)mmap(0,getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, memfd, SOC_CM_PER_REGS);
if((int32_t) spi0_base_addr < 0 || (int32_t) clocks_base_addr < 0) {
printf("mmap failed: %s\n", strerror(errno));
return -1;
}
//Turn on clocks
clocks_base_addr[CM_PER_L4LS_CLKCTRL] |= CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE;
clocks_base_addr[CM_PER_SPI0_CLKCTRL] |= CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE;
//Wait to make sure there isn't a race condition
sleep(1);
//Check the SPI_GCLK status bit, should be non-zero
printf("CLock status: %08x\n", clocks_base_addr[CM_PER_L4LS_CLKSTCTRL] & (CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_SPI_GCLK_ACT << CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_SPI_GCLK_SHIFT));
//Read back the two clock registers that were enabled before
printf("clock registers %08x %08x \nWriting spi register...\n", clocks_base_addr[CM_PER_L4LS_CLKCTRL], clocks_base_addr[CM_PER_SPI0_CLKCTRL]);
//Soft reset of the SPI peripheral --------- BUS ERROR HAPPENS AFTER THIS STATEMENT ---------------
spi0_base_addr[MCSPI_SYSCONFIG] |= MCSPI_SYSCONFIG_SOFTRESET;
//McSPIReset((unsigned int)spi0_base_addr);
spi0_base_addr[MCSPI_TX(0)] = 1337;
//McSPITransmitData((unsigned int)spi0_base_addr, 1337, MCSPI_CHANNEL_1);
//McSPIClkConfig(spi0_base_addr, 24000000, 24000000, MCSPI_CHANNEL_0, MCSPI_CLK_MODE_0);
printf("Done.\n");
return 0;
}
Here'e the output:
root@beaglebone:~/early_testing/dspi# ./mem
Opening raw memory...
Mapping registers to user space...
CLock status: 00000000
clock registers 00000000 00040002
Writing spi register...
Bus error