|
9 | 9 |
|
10 | 10 | // Linux includes
|
11 | 11 | #include <fcntl.h>
|
| 12 | +#include <stdarg.h> |
| 13 | +#include <sys/mman.h> |
| 14 | +//#include <sys/types.h> |
12 | 15 | //#include <sys/ioctl.h>
|
13 | 16 |
|
14 | 17 | // hyperion local includes
|
15 | 18 | #include "LedDeviceWS2812s.h"
|
16 | 19 |
|
| 20 | +// ==== Defines and Vars ==== |
| 21 | + |
| 22 | +// Base addresses for GPIO, PWM, PWM clock, and DMA controllers (physical, not bus!) |
| 23 | +// These will be "memory mapped" into virtual RAM so that they can be written and read directly. |
| 24 | +// ------------------------------------------------------------------------------------------------- |
| 25 | +#define DMA_BASE 0x20007000 |
| 26 | +#define DMA_LEN 0x24 |
| 27 | +#define PWM_BASE 0x2020C000 |
| 28 | +#define PWM_LEN 0x28 |
| 29 | +#define CLK_BASE 0x20101000 |
| 30 | +#define CLK_LEN 0xA8 |
| 31 | +#define GPIO_BASE 0x20200000 |
| 32 | +#define GPIO_LEN 0xB4 |
| 33 | + |
| 34 | +// GPIO |
| 35 | +// ------------------------------------------------------------------------------------------------- |
| 36 | +#define GPFSEL0 0x20200000 // GPIO function select, pins 0-9 (bits 30-31 reserved) |
| 37 | +#define GPFSEL1 0x20200004 // Pins 10-19 |
| 38 | +#define GPFSEL2 0x20200008 // Pins 20-29 |
| 39 | +#define GPFSEL3 0x2020000C // Pins 30-39 |
| 40 | +#define GPFSEL4 0x20200010 // Pins 40-49 |
| 41 | +#define GPFSEL5 0x20200014 // Pins 50-53 |
| 42 | +#define GPSET0 0x2020001C // Set (turn on) pin |
| 43 | +#define GPCLR0 0x20200028 // Clear (turn off) pin |
| 44 | +#define GPPUD 0x20200094 // Internal pullup/pulldown resistor control |
| 45 | +#define GPPUDCLK0 0x20200098 // PUD clock for pins 0-31 |
| 46 | +#define GPPUDCLK1 0x2020009C // PUD clock for pins 32-53 |
| 47 | + |
| 48 | +// Memory offsets for the PWM clock register, which is undocumented! Please fix that, Broadcom! |
| 49 | +// ------------------------------------------------------------------------------------------------- |
| 50 | +#define PWM_CLK_CNTL 40 // Control (on/off) |
| 51 | +#define PWM_CLK_DIV 41 // Divisor (bits 11:0 are *quantized* floating part, 31:12 integer part) |
| 52 | + |
| 53 | +// PWM Register Addresses (page 141) |
| 54 | +// These are divided by 4 because the register offsets in the guide are in bytes (8 bits) but |
| 55 | +// the pointers we use in this program are in words (32 bits). Buss' original defines are in |
| 56 | +// word offsets, e.g. PWM_RNG1 was 4 and PWM_DAT1 was 5. This is functionally the same, but it |
| 57 | +// matches the numbers supplied in the guide. |
| 58 | +// ------------------------------------------------------------------------------------------------- |
| 59 | +#define PWM_CTL 0x00 // Control Register |
| 60 | +#define PWM_STA (0x04 / 4) // Status Register |
| 61 | +#define PWM_DMAC (0x08 / 4) // DMA Control Register |
| 62 | +#define PWM_RNG1 (0x10 / 4) // Channel 1 Range |
| 63 | +#define PWM_DAT1 (0x14 / 4) // Channel 1 Data |
| 64 | +#define PWM_FIF1 (0x18 / 4) // FIFO (for both channels - bytes are interleaved if both active) |
| 65 | +#define PWM_RNG2 (0x20 / 4) // Channel 2 Range |
| 66 | +#define PWM_DAT2 (0x24 / 4) // Channel 2 Data |
| 67 | + |
| 68 | +// PWM_CTL register bit offsets |
| 69 | +// Note: Don't use MSEN1/2 for this purpose. It will screw things up. |
| 70 | +// ------------------------------------------------------------------------------------------------- |
| 71 | +#define PWM_CTL_MSEN2 15 // Channel 2 - 0: Use PWM algorithm. 1: Use M/S (serial) algorithm. |
| 72 | +#define PWM_CTL_USEF2 13 // Channel 2 - 0: Use PWM_DAT2. 1: Use FIFO. |
| 73 | +#define PWM_CTL_POLA2 12 // Channel 2 - Invert output polarity (if set, 0=high and 1=low) |
| 74 | +#define PWM_CTL_SBIT2 11 // Channel 2 - Silence bit (default line state when not transmitting) |
| 75 | +#define PWM_CTL_RPTL2 10 // Channel 2 - Repeat last data in FIFO |
| 76 | +#define PWM_CTL_MODE2 9 // Channel 2 - Mode. 0=PWM, 1=Serializer |
| 77 | +#define PWM_CTL_PWEN2 8 // Channel 2 - Enable PWM |
| 78 | +#define PWM_CTL_CLRF1 6 // Clear FIFO |
| 79 | +#define PWM_CTL_MSEN1 7 // Channel 1 - 0: Use PWM algorithm. 1: Use M/S (serial) algorithm. |
| 80 | +#define PWM_CTL_USEF1 5 // Channel 1 - 0: Use PWM_DAT1. 1: Use FIFO. |
| 81 | +#define PWM_CTL_POLA1 4 // Channel 1 - Invert output polarity (if set, 0=high and 1=low) |
| 82 | +#define PWM_CTL_SBIT1 3 // Channel 1 - Silence bit (default line state when not transmitting) |
| 83 | +#define PWM_CTL_RPTL1 2 // Channel 1 - Repeat last data in FIFO |
| 84 | +#define PWM_CTL_MODE1 1 // Channel 1 - Mode. 0=PWM, 1=Serializer |
| 85 | +#define PWM_CTL_PWEN1 0 // Channel 1 - Enable PWM |
| 86 | + |
| 87 | +// PWM_STA register bit offsets |
| 88 | +// ------------------------------------------------------------------------------------------------- |
| 89 | +#define PWM_STA_STA4 12 // Channel 4 State |
| 90 | +#define PWM_STA_STA3 11 // Channel 3 State |
| 91 | +#define PWM_STA_STA2 10 // Channel 2 State |
| 92 | +#define PWM_STA_STA1 9 // Channel 1 State |
| 93 | +#define PWM_STA_BERR 8 // Bus Error |
| 94 | +#define PWM_STA_GAPO4 7 // Gap Occurred on Channel 4 |
| 95 | +#define PWM_STA_GAPO3 6 // Gap Occurred on Channel 3 |
| 96 | +#define PWM_STA_GAPO2 5 // Gap Occurred on Channel 2 |
| 97 | +#define PWM_STA_GAPO1 4 // Gap Occurred on Channel 1 |
| 98 | +#define PWM_STA_RERR1 3 // FIFO Read Error |
| 99 | +#define PWM_STA_WERR1 2 // FIFO Write Error |
| 100 | +#define PWM_STA_EMPT1 1 // FIFO Empty |
| 101 | +#define PWM_STA_FULL1 0 // FIFO Full |
| 102 | + |
| 103 | +// PWM_DMAC bit offsets |
| 104 | +// ------------------------------------------------------------------------------------------------- |
| 105 | +#define PWM_DMAC_ENAB 31 // 0: DMA Disabled. 1: DMA Enabled. |
| 106 | +#define PWM_DMAC_PANIC 8 // Bits 15:8. Threshold for PANIC signal. Default 7. |
| 107 | +#define PWM_DMAC_DREQ 0 // Bits 7:0. Threshold for DREQ signal. Default 7. |
| 108 | + |
| 109 | +// PWM_RNG1, PWM_RNG2 |
| 110 | +// -------------------------------------------------------------------------------------------------- |
| 111 | +// Defines the transmission range. In PWM mode, evenly spaced pulses are sent within a period |
| 112 | +// of length defined in these registers. In serial mode, serialized data is sent within the |
| 113 | +// same period. The value is normally 32. If less, data will be truncated. If more, data will |
| 114 | +// be padded with zeros. |
| 115 | + |
| 116 | +// DAT1, DAT2 |
| 117 | +// -------------------------------------------------------------------------------------------------- |
| 118 | +// NOTE: These registers are not useful for our purposes - we will use the FIFO instead! |
| 119 | +// Stores 32 bits of data to be sent when USEF1/USEF2 is 0. In PWM mode, defines how many |
| 120 | +// pulses will be sent within the period specified in PWM_RNG1/PWM_RNG2. In serializer mode, |
| 121 | +// defines a 32-bit word to be transmitted. |
| 122 | + |
| 123 | +// FIF1 |
| 124 | +// -------------------------------------------------------------------------------------------------- |
| 125 | +// 32-bit-wide register used to "stuff" the FIFO, which has 16 32-bit words. (So, if you write |
| 126 | +// it 16 times, it will fill the FIFO.) |
| 127 | +// See also: PWM_STA_EMPT1 (FIFO empty) |
| 128 | +// PWM_STA_FULL1 (FIFO full) |
| 129 | +// PWM_CTL_CLRF1 (Clear FIFO) |
| 130 | + |
| 131 | +// DMA |
| 132 | +// -------------------------------------------------------------------------------------------------- |
| 133 | +// DMA registers (divided by four to convert form word to byte offsets, as with the PWM registers) |
| 134 | +#define DMA_CS (0x00 / 4) // Control & Status register |
| 135 | +#define DMA_CONBLK_AD (0x04 / 4) // Address of Control Block (must be 256-BYTE ALIGNED!!!) |
| 136 | +#define DMA_TI (0x08 / 4) // Transfer Information (populated from CB) |
| 137 | +#define DMA_SOURCE_AD (0x0C / 4) // Source address, populated from CB. Physical address. |
| 138 | +#define DMA_DEST_AD (0x10 / 4) // Destination address, populated from CB. Bus address. |
| 139 | +#define DMA_TXFR_LEN (0x14 / 4) // Transfer length, populated from CB |
| 140 | +#define DMA_STRIDE (0x18 / 4) // Stride, populated from CB |
| 141 | +#define DMA_NEXTCONBK (0x1C / 4) // Next control block address, populated from CB |
| 142 | +#define DMA_DEBUG (0x20 / 4) // Debug settings |
| 143 | + |
| 144 | +// DMA Control & Status register bit offsets |
| 145 | +#define DMA_CS_RESET 31 // Reset the controller for this channel |
| 146 | +#define DMA_CS_ABORT 30 // Set to abort transfer |
| 147 | +#define DMA_CS_DISDEBUG 29 // Disable debug pause signal |
| 148 | +#define DMA_CS_WAIT_FOR 28 // Wait for outstanding writes |
| 149 | +#define DMA_CS_PANIC_PRI 20 // Panic priority (bits 23:20), default 7 |
| 150 | +#define DMA_CS_PRIORITY 16 // AXI priority level (bits 19:16), default 7 |
| 151 | +#define DMA_CS_ERROR 8 // Set when there's been an error |
| 152 | +#define DMA_CS_WAITING_FOR 6 // Set when the channel's waiting for a write to be accepted |
| 153 | +#define DMA_CS_DREQ_STOPS_DMA 5 // Set when the DMA is paused because DREQ is inactive |
| 154 | +#define DMA_CS_PAUSED 4 // Set when the DMA is paused (active bit cleared, etc.) |
| 155 | +#define DMA_CS_DREQ 3 // Set when DREQ line is high |
| 156 | +#define DMA_CS_INT 2 // If INTEN is set, this will be set on CB transfer end |
| 157 | +#define DMA_CS_END 1 // Set when the current control block is finished |
| 158 | +#define DMA_CS_ACTIVE 0 // Enable DMA (CB_ADDR must not be 0) |
| 159 | +// Default CS word |
| 160 | +#define DMA_CS_CONFIGWORD (8 << DMA_CS_PANIC_PRI) | \ |
| 161 | + (8 << DMA_CS_PRIORITY) | \ |
| 162 | + (1 << DMA_CS_WAIT_FOR) |
| 163 | + |
| 164 | +// DREQ lines (page 61, most DREQs omitted) |
| 165 | +#define DMA_DREQ_ALWAYS 0 |
| 166 | +#define DMA_DREQ_PCM_TX 2 |
| 167 | +#define DMA_DREQ_PCM_RX 3 |
| 168 | +#define DMA_DREQ_PWM 5 |
| 169 | +#define DMA_DREQ_SPI_TX 6 |
| 170 | +#define DMA_DREQ_SPI_RX 7 |
| 171 | +#define DMA_DREQ_BSC_TX 8 |
| 172 | +#define DMA_DREQ_BSC_RX 9 |
| 173 | + |
| 174 | +// DMA Transfer Information register bit offsets |
| 175 | +// We don't write DMA_TI directly. It's populated from the TI field in a control block. |
| 176 | +#define DMA_TI_NO_WIDE_BURSTS 26 // Don't do wide writes in 2-beat bursts |
| 177 | +#define DMA_TI_WAITS 21 // Wait this many cycles after end of each read/write |
| 178 | +#define DMA_TI_PERMAP 16 // Peripheral # whose ready signal controls xfer rate (pwm=5) |
| 179 | +#define DMA_TI_BURST_LENGTH 12 // Length of burst in words (bits 15:12) |
| 180 | +#define DMA_TI_SRC_IGNORE 11 // Don't perform source reads (for fast cache fill) |
| 181 | +#define DMA_TI_SRC_DREQ 10 // Peripheral in PERMAP gates source reads |
| 182 | +#define DMA_TI_SRC_WIDTH 9 // Source transfer width - 0=32 bits, 1=128 bits |
| 183 | +#define DMA_TI_SRC_INC 8 // Source address += SRC_WITH after each read |
| 184 | +#define DMA_TI_DEST_IGNORE 7 // Don't perform destination writes |
| 185 | +#define DMA_TI_DEST_DREQ 6 // Peripheral in PERMAP gates destination writes |
| 186 | +#define DMA_TI_DEST_WIDTH 5 // Destination transfer width - 0=32 bits, 1=128 bits |
| 187 | +#define DMA_TI_DEST_INC 4 // Dest address += DEST_WIDTH after each read |
| 188 | +#define DMA_TI_WAIT_RESP 3 // Wait for write response |
| 189 | +#define DMA_TI_TDMODE 1 // 2D striding mode |
| 190 | +#define DMA_TI_INTEN 0 // Interrupt enable |
| 191 | +// Default TI word |
| 192 | +#define DMA_TI_CONFIGWORD (1 << DMA_TI_NO_WIDE_BURSTS) | \ |
| 193 | + (1 << DMA_TI_SRC_INC) | \ |
| 194 | + (1 << DMA_TI_DEST_DREQ) | \ |
| 195 | + (1 << DMA_TI_WAIT_RESP) | \ |
| 196 | + (1 << DMA_TI_INTEN) | \ |
| 197 | + (DMA_DREQ_PWM << DMA_TI_PERMAP) |
| 198 | + |
| 199 | +// DMA Debug register bit offsets |
| 200 | +#define DMA_DEBUG_LITE 28 // Whether the controller is "Lite" |
| 201 | +#define DMA_DEBUG_VERSION 25 // DMA Version (bits 27:25) |
| 202 | +#define DMA_DEBUG_DMA_STATE 16 // DMA State (bits 24:16) |
| 203 | +#define DMA_DEBUG_DMA_ID 8 // DMA controller's AXI bus ID (bits 15:8) |
| 204 | +#define DMA_DEBUG_OUTSTANDING_WRITES 4 // Outstanding writes (bits 7:4) |
| 205 | +#define DMA_DEBUG_READ_ERROR 2 // Slave read response error (clear by setting) |
| 206 | +#define DMA_DEBUG_FIFO_ERROR 1 // Operational read FIFO error (clear by setting) |
| 207 | +#define DMA_DEBUG_READ_LAST_NOT_SET 0 // AXI bus read last signal not set (clear by setting) |
| 208 | + |
| 209 | + |
| 210 | + |
| 211 | +#define PAGE_SIZE 4096 // Size of a RAM page to be allocated |
| 212 | +#define PAGE_SHIFT 12 // This is used for address translation |
| 213 | +#define NUM_PAGES ((sizeof(struct control_data_s) + PAGE_SIZE - 1) >> PAGE_SHIFT) |
| 214 | + |
| 215 | +#define SETBIT(word, bit) word |= 1<<bit |
| 216 | +#define CLRBIT(word, bit) word &= ~(1<<bit) |
| 217 | +#define GETBIT(word, bit) word & (1 << bit) ? 1 : 0 |
| 218 | +#define true 1 |
| 219 | +#define false 0 |
| 220 | + |
| 221 | +// GPIO |
| 222 | +#define INP_GPIO(g) *(gpio_reg+((g)/10)) &= ~(7<<(((g)%10)*3)) |
| 223 | +#define OUT_GPIO(g) *(gpio_reg+((g)/10)) |= (1<<(((g)%10)*3)) |
| 224 | +#define SET_GPIO_ALT(g,a) *(gpio_reg+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) |
| 225 | +#define GPIO_SET *(gpio_reg+7) // sets bits which are 1 ignores bits which are 0 |
| 226 | +#define GPIO_CLR *(gpio_reg+10) // clears bits which are 1 ignores bits which are 0 |
| 227 | + |
| 228 | + |
| 229 | + |
17 | 230 | LedDeviceWS2812s::LedDeviceWS2812s() :
|
18 | 231 | LedDevice(),
|
19 | 232 | mLedCount(0)
|
@@ -189,7 +402,7 @@ void LedDeviceWS2812s::terminate(int dummy) {
|
189 | 402 | //exit(1);
|
190 | 403 | }
|
191 | 404 |
|
192 |
| -void LedDeviceWS2812s::fatal(char *fmt, ...) { |
| 405 | +void LedDeviceWS2812s::fatal(const char *fmt, ...) { |
193 | 406 | va_list ap;
|
194 | 407 | va_start(ap, fmt);
|
195 | 408 | vfprintf(stderr, fmt, ap);
|
@@ -265,14 +478,7 @@ void LedDeviceWS2812s::setPWMBit(unsigned int bitPos, unsigned char bit) {
|
265 | 478 | }
|
266 | 479 | }
|
267 | 480 |
|
268 |
| -// ================================================================================================= |
269 |
| -// .___ .__ __ ___ ___ .___ |
270 |
| -// | | ____ |__|/ |_ / | \_____ _______ __| _/_ _ _______ _______ ____ |
271 |
| -// | |/ \| \ __\ / ~ \__ \\_ __ \/ __ |\ \/ \/ /\__ \\_ __ \_/ __ \ |
272 |
| -// | | | \ || | \ Y // __ \| | \/ /_/ | \ / / __ \| | \/\ ___/ |
273 |
| -// |___|___| /__||__| \___|_ /(____ /__| \____ | \/\_/ (____ /__| \___ > |
274 |
| -// \/ \/ \/ \/ \/ \/ |
275 |
| -// ================================================================================================= |
| 481 | +// ==== Init Hardware ==== |
276 | 482 |
|
277 | 483 | void LedDeviceWS2812s::initHardware() {
|
278 | 484 | int pid;
|
@@ -341,7 +547,8 @@ void LedDeviceWS2812s::initHardware() {
|
341 | 547 | fatal("Failed to open %s: %m\n", pagemap_fn);
|
342 | 548 | }
|
343 | 549 |
|
344 |
| - if (lseek(fd, (unsigned long)virtbase >> 9, SEEK_SET) != (unsigned long)virtbase >> 9) { |
| 550 | + off_t newOffset = (unsigned long)virtbase >> 9; |
| 551 | + if (lseek(fd, newOffset, SEEK_SET) != newOffset) { |
345 | 552 | fatal("Failed to seek on %s: %m\n", pagemap_fn);
|
346 | 553 | }
|
347 | 554 |
|
|
0 commit comments