Skip to content

Instantly share code, notes, and snippets.

@dpslwk
Created June 13, 2018 09:57
Show Gist options
  • Save dpslwk/607e6281ed98e765ea6db4d4ab25a0cd to your computer and use it in GitHub Desktop.
Save dpslwk/607e6281ed98e765ea6db4d4ab25a0cd to your computer and use it in GitHub Desktop.
//*****************************************************************************
//
// very hacked together WS2812 example for the MPS432E4
// baseed on https://github.com/joewa/WS2812-LED-Driver_ChibiOS
// and some bits to come from https://github.com/hubmartin/STM32F4_WS2812B
// and http://www.martinhubacek.cz/arm/improved-stm32-ws2812b-library
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include "ti/devices/msp432e4/driverlib/driverlib.h"
//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
/* The control table used by the uDMA controller. This table must be aligned
* to a 1024 byte boundary. */
#if defined(__ICCARM__)
#pragma data_alignment=1024
uint8_t pui8ControlTable[1024];
#elif defined(__TI_ARM__)
#pragma DATA_ALIGN(pui8ControlTable, 1024)
uint8_t pui8ControlTable[1024];
#else
uint8_t pui8ControlTable[1024] __attribute__ ((aligned(1024)));
#endif
#define WS2812_LED_N 2 // Number of LEDs
#define WS2812_RESET_BIT_N (30)
#define WS2812_COLOR_BIT_N (WS2812_LED_N*24) /**< Number of data bits */
#define WS2812_BIT_N (WS2812_COLOR_BIT_N + WS2812_RESET_BIT_N) /**< Total number of bits in a frame */
#define WS_800HZ 800000
#define WS_400HZ 400000
#define WS_FREQ WS_800HZ
#define SYSCLOCK 120000000
#define WS2812_TIMER_INTVAL (SYSCLOCK/WS_FREQ)
#define WS2812_DUTYCYCLE_0 ((10*WS2812_TIMER_INTVAL)/15)
#define WS2812_DUTYCYCLE_1 ((10*WS2812_TIMER_INTVAL)/36)
#define WS2812_DUTYCYCLE_RESET (WS2812_TIMER_INTVAL-1)
#define WS2812_BIT(led, byte, bit) (24*(led) + 8*(byte) + (7 - (bit)))
#define WS2812_RED_BIT(led, bit) WS2812_BIT((led), 1, (bit))
#define WS2812_GREEN_BIT(led, bit) WS2812_BIT((led), 0, (bit))
#define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 2, (bit))
static uint32_t ws2812_frame_buffer[WS2812_BIT_N];
volatile bool bWsDMADoneFlag;
void
TIMER3B_IRQHandler(void)
{
uint32_t getTimerIntStatus;
/* Get the timer interrupt status and clear the same */
getTimerIntStatus = MAP_TimerIntStatus(TIMER3_BASE, true);
MAP_TimerIntClear(TIMER3_BASE, getTimerIntStatus);
MAP_uDMAChannelTransferSet(UDMA_CH3_TIMER3B | UDMA_PRI_SELECT,
UDMA_MODE_BASIC,
(void *)&ws2812_frame_buffer, (void*)&TIMER3->TAMATCHR,
sizeof(ws2812_frame_buffer)/4);
MAP_uDMAChannelEnable(UDMA_CH3_TIMER3B);
}
int ws2812_write_led(uint32_t led_number, uint8_t r, uint8_t g, uint8_t b)
{
// Check for valid LED
if (led_number >= WS2812_LED_N) return 1;
// Write color to frame buffer
uint32_t bit;
for (bit = 0; bit < 8; bit++) {
ws2812_frame_buffer[WS2812_RED_BIT(led_number, bit)] = ((r >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
ws2812_frame_buffer[WS2812_GREEN_BIT(led_number, bit)] = ((g >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
}
// Success
return 0;
}
//*****************************************************************************
//
// This example application demonstrates the use of the timers to generate
// periodic interrupts.
//
//*****************************************************************************
int
main(void)
{
//
// Set the clocking to run directly from the crystal at 120MHz.
//
MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480), SYSCLOCK);
uint32_t i;
for (i = 0; i < WS2812_COLOR_BIT_N; i++) ws2812_frame_buffer[i] = WS2812_DUTYCYCLE_0; // All color bits are zero duty cycle
ws2812_frame_buffer[WS2812_COLOR_BIT_N] = WS2812_DUTYCYCLE_0; // stupid GMTP, just push out one more 0 before we start the reset latch
for (i = 1; i < WS2812_RESET_BIT_N; i++) ws2812_frame_buffer[i + WS2812_COLOR_BIT_N] = WS2812_DUTYCYCLE_RESET; // All reset bits are zero
//
// Enable processor interrupts.
//
MAP_IntMasterEnable();
// LWK neo
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
MAP_GPIOPinConfigure(GPIO_PD4_T3CCP0);
MAP_GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_4);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);
MAP_TimerConfigure(TIMER3_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM | TIMER_CFG_B_PERIODIC_UP);
MAP_TimerLoadSet(TIMER3_BASE, TIMER_BOTH, WS2812_TIMER_INTVAL);
MAP_TimerMatchSet(TIMER3_BASE, TIMER_A, WS2812_TIMER_INTVAL-1);
MAP_TimerIntEnable(TIMER3_BASE, TIMER_TIMB_DMA);
MAP_TimerDMAEventSet(TIMER3_BASE, TIMER_DMA_TIMEOUT_B);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
MAP_uDMAEnable();
MAP_uDMAControlBaseSet(pui8ControlTable);
MAP_uDMAChannelAssign(UDMA_CH3_TIMER3B);
MAP_uDMAChannelAttributeDisable(UDMA_CH3_TIMER3B,
UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK);
MAP_uDMAChannelAttributeEnable(UDMA_CH3_TIMER3B,
UDMA_ATTR_HIGH_PRIORITY
);
MAP_uDMAChannelControlSet(UDMA_CH3_TIMER3B | UDMA_PRI_SELECT,
UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_NONE |
UDMA_ARB_1);
MAP_uDMAChannelTransferSet(UDMA_CH3_TIMER3B | UDMA_PRI_SELECT,
UDMA_MODE_BASIC,
(void *)&ws2812_frame_buffer, (void*)&TIMER3->TAMATCHR,
sizeof(ws2812_frame_buffer)/4);
MAP_uDMAChannelEnable(UDMA_CH3_TIMER3B);
MAP_IntEnable(INT_TIMER3B);
bWsDMADoneFlag = 0;
MAP_TimerEnable(TIMER3_BASE, TIMER_BOTH);
int s = 0;
while(1)
{
for (int n = 0; n < WS2812_LED_N; n++) {
int s0 = s + 10*n;
ws2812_write_led(n, s0%255, (s0+85)%255, (s0+170)%255);
}
s += 10;
MAP_SysCtlDelay(g_ui32SysClock/2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment