Minor reformat of code to match hyperion-style. Added ws2812b as option to disable for devices without dma-pwm

Former-commit-id: 579f4426285fb537706a22af446f5280748f2ab7
This commit is contained in:
T. van der Zwan 2014-09-19 16:37:58 +02:00
parent c0f0837b92
commit 8ad0e88e2f
6 changed files with 143 additions and 154 deletions

View File

@ -13,6 +13,9 @@ message(STATUS "ENABLE_DISPMANX = " ${ENABLE_DISPMANX})
option(ENABLE_SPIDEV "Enable the SPIDEV device" ON)
message(STATUS "ENABLE_SPIDEV = " ${ENABLE_SPIDEV})
option(ENABLE_WS2812BPWM "Enable the WS2812b-PWM device" ON)
message(STATUS "ENABLE_WS2812BPWM = " ${ENABLE_WS2812BPWM})
option(ENABLE_V4L2 "Enable the V4L2 grabber" ON)
message(STATUS "ENABLE_V4L2 = " ${ENABLE_V4L2})
@ -22,9 +25,9 @@ message(STATUS "ENABLE_TINKERFORGE = " ${ENABLE_TINKERFORGE})
option(ENABLE_PROTOBUF "Enable PROTOBUF server" ON)
message(STATUS "ENABLE_PROTOBUF = " ${ENABLE_PROTOBUF})
if (ENABLE_V4L2 AND NOT ENABLE_PROTOBUF)
if(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF)
message(FATAL_ERROR "V4L2 grabber requires PROTOBUF. Disable V4L2 or enable PROTOBUF")
endif (ENABLE_V4L2 AND NOT ENABLE_PROTOBUF)
endif(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF)
# Createt the configuration file
# configure a header file to pass some of the CMake settings

View File

@ -9,6 +9,9 @@
// Define to enable the spi-device
#cmakedefine ENABLE_SPIDEV
// Define to enable the ws2812b-pwm-device
#cmakedefine ENABLE_WS2812BPWM
// Define to enable the spi-device
#cmakedefine ENABLE_TINKERFORGE

View File

@ -68,6 +68,7 @@ if(ENABLE_SPIDEV)
)
endif(ENABLE_SPIDEV)
if(ENABLE_WS2812BPWM)
SET(Leddevice_HEADERS
${Leddevice_HEADERS}
${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.h
@ -76,6 +77,7 @@ SET(Leddevice_SOURCES
${Leddevice_SOURCES}
${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.cpp
)
endif(ENABLE_WS2812BPWM)
if(ENABLE_TINKERFORGE)
SET(Leddevice_HEADERS

View File

@ -31,7 +31,9 @@
#include "LedDevicePhilipsHue.h"
#include "LedDeviceTpm2.h"
#include "LedDeviceWS2812b.h"
#ifdef ENABLE_WS2812BPWM
#include "LedDeviceWS2812b.h"
#endif
LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
{
@ -180,14 +182,17 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
const std::string output = deviceConfig["output"].asString();
const unsigned rate = deviceConfig["rate"].asInt();
LedDeviceTpm2* deviceTpm2 = new LedDeviceTpm2(output, rate);
LedDeviceTpm2 * deviceTpm2 = new LedDeviceTpm2(output, rate);
deviceTpm2->open();
device = deviceTpm2;
}else if (type == "ws2812b")
}
#ifdef ENABLE_WS2812BPWM
else if (type == "ws2812b")
{
LedDeviceWS2812b * ledDeviceWS2812b = new LedDeviceWS2812b();
device = ledDeviceWS2812b;
}
#endif
else
{
std::cout << "Unable to create device " << type << std::endl;

View File

@ -252,7 +252,8 @@ LedDeviceWS2812b::LedDeviceWS2812b() :
// init bit pattern, it is always 1X0
unsigned int wireBit = 0;
while ((wireBit + 3) < ((NUM_DATA_WORDS) * 4 * 8)){
while ((wireBit + 3) < ((NUM_DATA_WORDS) * 4 * 8))
{
setPWMBit(wireBit++, 1);
setPWMBit(wireBit++, 0); // just init it with 0
setPWMBit(wireBit++, 0);
@ -264,36 +265,36 @@ LedDeviceWS2812b::LedDeviceWS2812b() :
#ifdef WS2812_ASM_OPTI
// rotate register, used to move the 1 around :-)
static inline __attribute__((always_inline))
uint32_t arm_ror_imm(uint32_t v, uint32_t sh) {
uint32_t d;
asm ("ROR %[Rd], %[Rm], %[Is]" : [Rd] "=r" (d) : [Rm] "r" (v), [Is] "i" (sh));
return d;
static inline __attribute__((always_inline)) uint32_t arm_ror_imm(uint32_t v, uint32_t sh)
{
uint32_t d;
asm ("ROR %[Rd], %[Rm], %[Is]" : [Rd] "=r" (d) : [Rm] "r" (v), [Is] "i" (sh));
return d;
}
// rotate register, used to move the 1 around, add 1 to int counter on carry
static inline __attribute__((always_inline))
uint32_t arm_ror_imm_add_on_carry(uint32_t v, uint32_t sh, uint32_t inc) {
uint32_t d;
asm ("RORS %[Rd], %[Rm], %[Is]\n\t"
"ADDCS %[Rd1], %[Rd1], #1"
: [Rd] "=r" (d), [Rd1] "+r" (inc): [Rm] "r" (v), [Is] "i" (sh));
return d;
static inline __attribute__((always_inline)) uint32_t arm_ror_imm_add_on_carry(uint32_t v, uint32_t sh, uint32_t inc)
{
uint32_t d;
asm ("RORS %[Rd], %[Rm], %[Is]\n\t"
"ADDCS %[Rd1], %[Rd1], #1"
: [Rd] "=r" (d), [Rd1] "+r" (inc): [Rm] "r" (v), [Is] "i" (sh));
return d;
}
static inline __attribute__((always_inline))
uint32_t arm_ror(uint32_t v, uint32_t sh) {
uint32_t d;
asm ("ROR %[Rd], %[Rm], %[Rs]" : [Rd] "=r" (d) : [Rm] "r" (v), [Rs] "r" (sh));
return d;
static inline __attribute__((always_inline)) uint32_t arm_ror(uint32_t v, uint32_t sh)
{
uint32_t d;
asm ("ROR %[Rd], %[Rm], %[Rs]" : [Rd] "=r" (d) : [Rm] "r" (v), [Rs] "r" (sh));
return d;
}
static inline __attribute__((always_inline))
uint32_t arm_Bit_Clear_imm(uint32_t v, uint32_t v2) {
uint32_t d;
asm ("BIC %[Rd], %[Rm], %[Rs]" : [Rd] "=r" (d) : [Rm] "r" (v), [Rs] "r" (v2));
return d;
static inline __attribute__((always_inline)) uint32_t arm_Bit_Clear_imm(uint32_t v, uint32_t v2)
{
uint32_t d;
asm ("BIC %[Rd], %[Rm], %[Rs]" : [Rd] "=r" (d) : [Rm] "r" (v), [Rs] "r" (v2));
return d;
}
#endif
@ -306,10 +307,6 @@ int LedDeviceWS2812b::write(const std::vector<ColorRgb> &ledValues)
#endif
mLedCount = ledValues.size();
//printf("Set leds, number: %d\n", mLedCount);
// Clear out the PWM buffer
// Disabled, because we will overwrite the buffer anyway.
// Read data from LEDBuffer[], translate it into wire format, and write to PWMWaveform
unsigned int colorBits = 0; // Holds the GRB color before conversion to wire bit pattern
@ -323,11 +320,10 @@ int LedDeviceWS2812b::write(const std::vector<ColorRgb> &ledValues)
// 72 bits per pixel / 32 bits per word = 2.25 words per pixel
// Add 1 to make sure the PWM FIFO gets the message: "we're sending zeroes"
// Times 4 because DMA works in bytes, not words
// cbp->length = (mLedCount * 2.25) * 4;
cbp->length = ((mLedCount * 2.25) + 1) * 4;
if(cbp->length > NUM_DATA_WORDS * 4) {
if(cbp->length > NUM_DATA_WORDS * 4)
{
cbp->length = NUM_DATA_WORDS * 4;
// mLedCount = NUM_DATA_WORDS / 2.25;
mLedCount = (NUM_DATA_WORDS - 1) / 2.25;
}
@ -336,7 +332,8 @@ int LedDeviceWS2812b::write(const std::vector<ColorRgb> &ledValues)
#endif
for(size_t i=0; i<mLedCount; i++) {
for(size_t i=0; i<mLedCount; i++)
{
// Create bits necessary to represent one color triplet (in GRB, not RGB, order)
//printf("RGB: %d, %d, %d\n", ledValues[i].red, ledValues[i].green, ledValues[i].blue);
colorBits = ((unsigned int)ledValues[i].red << 8) | ((unsigned int)ledValues[i].green << 16) | ledValues[i].blue;
@ -347,19 +344,16 @@ int LedDeviceWS2812b::write(const std::vector<ColorRgb> &ledValues)
for(int j=23; j>=0; j--) {
#ifdef WS2812_ASM_OPTI
// Fetch word the bit is in
unsigned int wordOffset = (int)(wireBit / 32);
wireBit +=3;
unsigned int wordOffset = (int)(wireBit / 32);
wireBit +=3;
// printBinary(startbitPattern, 32);
// printf(" %d\n", j);
if (colorBits & (1 << j)) {
PWMWaveform[wordOffset] |= startbitPattern;
} else {
PWMWaveform[wordOffset] = arm_Bit_Clear_imm(PWMWaveform[wordOffset], startbitPattern);
}
startbitPattern = arm_ror_imm(startbitPattern, 3);
if (colorBits & (1 << j)) {
PWMWaveform[wordOffset] |= startbitPattern;
} else {
PWMWaveform[wordOffset] = arm_Bit_Clear_imm(PWMWaveform[wordOffset], startbitPattern);
}
startbitPattern = arm_ror_imm(startbitPattern, 3);
#else
unsigned char colorBit = (colorBits & (1 << j)) ? 1 : 0; // Holds current bit out of colorBits to be processed
setPWMBit(wireBit, colorBit);
@ -391,9 +385,6 @@ int LedDeviceWS2812b::write(const std::vector<ColorRgb> &ledValues)
//remove one to undo optimization
wireBit --;
// printBinary(PWMWaveform[(int)(wireBit / 32)], 32);
// printf(" pre\n");
#ifdef WS2812_ASM_OPTI
int rest = 32 - wireBit % 32; // 64: 32 - used Bits
startbitPattern = (1 << (rest-1)); // set new bitpattern to start at the benigining of one bit (3 bit in wave form)
@ -406,7 +397,8 @@ int LedDeviceWS2812b::write(const std::vector<ColorRgb> &ledValues)
unsigned int oldbitPattern = startbitPattern;
// zero rest of the 4 bytes / int so that output is 0 (no data is send)
for (int i = 0; i < rest; i += 3){
for (int i = 0; i < rest; i += 3)
{
unsigned int wordOffset = (int)(wireBit / 32);
wireBit += 3;
PWMWaveform[wordOffset] = arm_Bit_Clear_imm(PWMWaveform[wordOffset], startbitPattern);
@ -419,22 +411,14 @@ int LedDeviceWS2812b::write(const std::vector<ColorRgb> &ledValues)
unsigned int oldwireBitValue = wireBit;
// zero rest of the 4 bytes / int so that output is 0 (no data is send)
for (int i = 0; i < rest; i += 3){
for (int i = 0; i < rest; i += 3)
{
setPWMBit(wireBit, 0);
wireBit += 3;
}
#endif
// printBinary(PWMWaveform[(int)(oldwireBitValue / 32) -1 ], 32);
// printf(" post\n");
// printBinary(PWMWaveform[(int)(oldwireBitValue / 32)], 32);
// printf(" post\n");
// This block is a major CPU hog when there are lots of pixels to be transmitted.
// It would go quicker with DMA.
// for(unsigned int i = 0; i < (cbp->length / 4); i++) {
// ctl->sample[i] = PWMWaveform[i];
// }
memcpy ( ctl->sample, PWMWaveform, cbp->length ); // memcpy does the same and is potentially faster
memcpy ( ctl->sample, PWMWaveform, cbp->length );
// Enable DMA and PWM engines, which should now send the data
startTransfer();
@ -444,35 +428,29 @@ int LedDeviceWS2812b::write(const std::vector<ColorRgb> &ledValues)
#ifdef WS2812_ASM_OPTI
startbitPattern = oldbitPattern;
for (int i = 0; i < rest; i += 3){
for (int i = 0; i < rest; i += 3)
{
unsigned int wordOffset = (int)(wireBit / 32);
wireBit += 3;
PWMWaveform[wordOffset] |= startbitPattern;
startbitPattern = arm_ror_imm(startbitPattern, 3);
}
#else
for (int i = 0; i < rest; i += 3){
for (int i = 0; i < rest; i += 3)
{
setPWMBit(wireBit, 1);
wireBit += 3;
}
#endif
// printBinary(PWMWaveform[(int)(oldwireBitValue / 32)], 32);
// printf(" restored\n");
// Wait long enough for the DMA transfer to finish
// 3 RAM bits per wire bit, so 72 bits to send one color command.
//float bitTimeUSec = (float)(NUM_DATA_WORDS * 32) * 0.4; // Bits sent * time to transmit one bit, which is 0.4μSec
//printf("Delay for %d μSec\n", (int)bitTimeUSec);
//usleep((int)bitTimeUSec);
#ifdef BENCHMARK
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &timeEnd);
timespec result;
result.tv_sec = timeEnd.tv_sec - timeStart.tv_sec;
result.tv_nsec = timeEnd.tv_nsec - timeStart.tv_nsec;
if (result.tv_nsec < 0) {
if (result.tv_nsec < 0)
{
result.tv_nsec = 1e9 - result.tv_nsec;
result.tv_sec -= 1;
}
@ -491,8 +469,7 @@ int LedDeviceWS2812b::switchOff()
LedDeviceWS2812b::~LedDeviceWS2812b()
{
// Exit cleanly, freeing memory and stopping the DMA & PWM engines
// We trap all signals (including Ctrl+C), so even if you don't get here, it terminates correctly
terminate(0);
terminate(0);
#ifdef BENCHMARK
printf("WS2812b Benchmark results: Runs %d - Avarage %lu (n) - Minimum %ld (n)\n",
runCount, (runCount > 0 ? combinedNseconds / runCount : 0), shortestNseconds);
@ -512,47 +489,46 @@ LedDeviceWS2812b::~LedDeviceWS2812b()
// Convenience functions
// --------------------------------------------------------------------------------------------------
// Print some bits of a binary number (2nd arg is how many bits)
void LedDeviceWS2812b::printBinary(unsigned int i, unsigned int bits) {
void LedDeviceWS2812b::printBinary(unsigned int i, unsigned int bits)
{
int x;
for(x=bits-1; x>=0; x--) {
for(x=bits-1; x>=0; x--)
{
printf("%d", (i & (1 << x)) ? 1 : 0);
if(x % 16 == 0 && x > 0) {
if(x % 16 == 0 && x > 0)
{
printf(" ");
} else if(x % 4 == 0 && x > 0) {
}
else if(x % 4 == 0 && x > 0)
{
printf(":");
}
}
}
// Reverse the bits in a word
unsigned int reverseWord(unsigned int word) {
unsigned int reverseWord(unsigned int word)
{
unsigned int output = 0;
//unsigned char bit;
int i;
for(i=0; i<32; i++) {
//bit = word & (1 << i) ? 1 : 0;
for(i=0; i<32; i++)
{
output |= word & (1 << i) ? 1 : 0;
if(i<31) {
if(i<31)
{
output <<= 1;
}
}
return output;
}
// Not sure how this is better than usleep...?
/*
static void udelay(int us) {
struct timespec ts = { 0, us * 1000 };
nanosleep(&ts, NULL);
}
*/
// Shutdown functions
// --------------------------------------------------------------------------------------------------
void LedDeviceWS2812b::terminate(int dummy) {
// Shut down the DMA controller
if(dma_reg) {
if(dma_reg)
{
CLRBIT(dma_reg[DMA_CS], DMA_CS_ACTIVE);
usleep(100);
SETBIT(dma_reg[DMA_CS], DMA_CS_RESET);
@ -560,21 +536,22 @@ void LedDeviceWS2812b::terminate(int dummy) {
}
// Shut down PWM
if(pwm_reg) {
if(pwm_reg)
{
CLRBIT(pwm_reg[PWM_CTL], PWM_CTL_PWEN1);
usleep(100);
pwm_reg[PWM_CTL] = (1 << PWM_CTL_CLRF1);
}
// Free the allocated memory
if(page_map != 0) {
if(page_map != 0)
{
free(page_map);
}
//exit(1);
}
void LedDeviceWS2812b::fatal(const char *fmt, ...) {
void LedDeviceWS2812b::fatal(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
@ -586,18 +563,22 @@ void LedDeviceWS2812b::fatal(const char *fmt, ...) {
// Memory management
// --------------------------------------------------------------------------------------------------
// Translate from virtual address to physical
unsigned int LedDeviceWS2812b::mem_virt_to_phys(void *virt) {
unsigned int LedDeviceWS2812b::mem_virt_to_phys(void *virt)
{
unsigned int offset = (uint8_t *)virt - virtbase;
return page_map[offset >> PAGE_SHIFT].physaddr + (offset % PAGE_SIZE);
}
// Translate from physical address to virtual
unsigned int LedDeviceWS2812b::mem_phys_to_virt(uint32_t phys) {
unsigned int LedDeviceWS2812b::mem_phys_to_virt(uint32_t phys)
{
unsigned int pg_offset = phys & (PAGE_SIZE - 1);
unsigned int pg_addr = phys - pg_offset;
for (unsigned int i = 0; i < NUM_PAGES; i++) {
if (page_map[i].physaddr == pg_addr) {
for (unsigned int i = 0; i < NUM_PAGES; i++)
{
if (page_map[i].physaddr == pg_addr)
{
return (uint32_t)virtbase + i * PAGE_SIZE + pg_offset;
}
}
@ -607,22 +588,28 @@ unsigned int LedDeviceWS2812b::mem_phys_to_virt(uint32_t phys) {
}
// Map a peripheral's IO memory into our virtual memory, so we can read/write it directly
void * LedDeviceWS2812b::map_peripheral(uint32_t base, uint32_t len) {
void * LedDeviceWS2812b::map_peripheral(uint32_t base, uint32_t len)
{
int fd = open("/dev/mem", O_RDWR);
void * vaddr;
if (fd < 0)
{
fatal("Failed to open /dev/mem: %m\n");
}
vaddr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, base);
if (vaddr == MAP_FAILED)
{
fatal("Failed to map peripheral at 0x%08x: %m\n", base);
}
close(fd);
return vaddr;
}
// Zero out the PWM waveform buffer
void LedDeviceWS2812b::clearPWMBuffer() {
void LedDeviceWS2812b::clearPWMBuffer()
{
memset(PWMWaveform, 0, NUM_DATA_WORDS * 4); // Times four because memset deals in bytes.
}
@ -630,29 +617,26 @@ void LedDeviceWS2812b::clearPWMBuffer() {
// The (31 - bitIdx) is so that we write the data backwards, correcting its endianness
// This means getPWMBit will return something other than what was written, so it would be nice
// if the logic that calls this function would figure it out instead. (However, that's trickier)
void LedDeviceWS2812b::setPWMBit(unsigned int bitPos, unsigned char bit) {
void LedDeviceWS2812b::setPWMBit(unsigned int bitPos, unsigned char bit)
{
// Fetch word the bit is in
unsigned int wordOffset = (int)(bitPos / 32);
unsigned int bitIdx = bitPos - (wordOffset * 32);
//printf("bitPos=%d wordOffset=%d bitIdx=%d value=%d\n", bitPos, wordOffset, bitIdx, bit);
switch(bit) {
switch(bit)
{
case 1:
PWMWaveform[wordOffset] |= (1 << (31 - bitIdx));
// PWMWaveform[wordOffset] |= (1 << bitIdx);
break;
case 0:
PWMWaveform[wordOffset] &= ~(1 << (31 - bitIdx));
// PWMWaveform[wordOffset] &= ~(1 << bitIdx);
break;
}
}
// ==== Init Hardware ====
void LedDeviceWS2812b::initHardware() {
void LedDeviceWS2812b::initHardware()
{
int pid;
int fd;
char pagemap_fn[64];
@ -692,22 +676,24 @@ void LedDeviceWS2812b::initHardware() {
-1, // File descriptor
0); // Offset
if (virtbase == MAP_FAILED) {
if (virtbase == MAP_FAILED)
{
fatal("Failed to mmap physical pages: %m\n");
return;
}
if ((unsigned long)virtbase & (PAGE_SIZE-1)) {
if ((unsigned long)virtbase & (PAGE_SIZE-1))
{
fatal("Virtual address is not page aligned\n");
return;
}
//printf("virtbase mapped 0x%x bytes at 0x%x\n", NUM_PAGES * PAGE_SIZE, virtbase);
// Allocate page map (pointers to the control block(s) and data for each CB
page_map = (page_map_t *) malloc(NUM_PAGES * sizeof(*page_map));
if (page_map == 0) {
if (page_map == 0)
{
fatal("Failed to malloc page_map: %m\n");
} else {
//printf("Allocated 0x%x bytes for page_map at 0x%x\n", NUM_PAGES * sizeof(*page_map), page_map);
return;
}
// Use /proc/self/pagemap to figure out the mapping between virtual and physical addresses
@ -715,17 +701,20 @@ void LedDeviceWS2812b::initHardware() {
sprintf(pagemap_fn, "/proc/%d/pagemap", pid);
fd = open(pagemap_fn, O_RDONLY);
if (fd < 0) {
if (fd < 0)
{
fatal("Failed to open %s: %m\n", pagemap_fn);
}
off_t newOffset = (unsigned long)virtbase >> 9;
if (lseek(fd, newOffset, SEEK_SET) != newOffset) {
if (lseek(fd, newOffset, SEEK_SET) != newOffset)
{
fatal("Failed to seek on %s: %m\n", pagemap_fn);
}
printf("Page map: %d pages\n", NUM_PAGES);
for (unsigned int i = 0; i < NUM_PAGES; i++) {
for (unsigned int i = 0; i < NUM_PAGES; i++)
{
uint64_t pfn;
page_map[i].virtaddr = virtbase + i * PAGE_SIZE;
@ -766,7 +755,8 @@ void LedDeviceWS2812b::initHardware() {
// Add 1 to make sure the PWM FIFO gets the message: "we're sending zeroes"
// Times 4 because DMA works in bytes, not words
cbp->length = ((mLedCount * 2.25) + 1) * 4;
if(cbp->length > NUM_DATA_WORDS * 4) {
if(cbp->length > NUM_DATA_WORDS * 4)
{
cbp->length = NUM_DATA_WORDS * 4;
}
@ -780,19 +770,6 @@ void LedDeviceWS2812b::initHardware() {
// Pointer to next block - 0 shuts down the DMA channel when transfer is complete
cbp->next = 0;
// Testing
/*
ctl = (struct control_data_s *)virtbase;
ctl->sample[0] = 0x00000000;
ctl->sample[1] = 0x000000FA;
ctl->sample[2] = 0x0000FFFF;
ctl->sample[3] = 0xAAAAAAAA;
ctl->sample[4] = 0xF0F0F0F0;
ctl->sample[5] = 0x0A0A0A0A;
ctl->sample[6] = 0xF00F0000;
*/
// Stop any existing DMA transfers
// ---------------------------------------------------------------
dma_reg[DMA_CS] |= (1 << DMA_CS_ABORT);
@ -894,7 +871,8 @@ void LedDeviceWS2812b::initHardware() {
}
// Begin the transfer
void LedDeviceWS2812b::startTransfer() {
void LedDeviceWS2812b::startTransfer()
{
// Enable DMA
dma_reg[DMA_CONBLK_AD] = mem_virt_to_phys(((struct control_data_s *) virtbase)->cb);
dma_reg[DMA_CS] = DMA_CS_CONFIGWORD | (1 << DMA_CS_ACTIVE);
@ -902,7 +880,4 @@ void LedDeviceWS2812b::startTransfer() {
// Enable PWM
SETBIT(pwm_reg[PWM_CTL], PWM_CTL_PWEN1);
// dumpPWM();
// dumpDMA();
}

View File

@ -108,22 +108,23 @@
// per address. This is because the software (this program) deals only in virtual addresses,
// whereas the DMA controller can only access RAM via physical address. (If that's not confusing
// enough, it writes to peripherals by their bus addresses.)
typedef struct {
struct page_map_t
{
uint8_t *virtaddr;
uint32_t physaddr;
} page_map_t;
};
// Control Block (CB) - this tells the DMA controller what to do.
typedef struct {
unsigned int
info, // Transfer Information (TI)
src, // Source address (physical)
dst, // Destination address (bus)
length, // Length in bytes (not words!)
stride, // We don't care about this
next, // Pointer to next control block
pad[2]; // These are "reserved" (unused)
} dma_cb_t;
struct dma_cb_t
{
unsigned info; // Transfer Information (TI)
unsigned src; // Source address (physical)
unsigned dst; // Destination address (bus)
unsigned length; // Length in bytes (not words!)
unsigned stride; // We don't care about this
unsigned next; // Pointer to next control block
unsigned pad[2]; // These are "reserved" (unused)
};
///
/// Implementation of the LedDevice interface for writing to Ws2801 led device.