Skip to content

Instantly share code, notes, and snippets.

@devilholk
Created November 26, 2019 19:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devilholk/c22d1622e3cd2719bf9518b5adb9118a to your computer and use it in GitHub Desktop.
Save devilholk/c22d1622e3cd2719bf9518b5adb9118a to your computer and use it in GitHub Desktop.
Simple test application for LED driving
#define BIT_0 6
#define BIT_1 14
#define FREQ 800000
#define NUMBER_LEDS 6
#define HUE_RANGE 0x6000U
#define HUE_SPREAD (HUE_RANGE / NUMBER_LEDS)
#define HUE_SPEED 3
// #define BIT_0 8
// #define BIT_1 29
// #define FREQ 400000
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/timer.h>
#include <libopencm3/stm32/dma.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/nvic.h>
volatile int ms_time_delay;
struct color {
uint8_t g;
uint8_t r;
uint8_t b;
};
volatile uint8_t led_output_buf[NUMBER_LEDS*24+1]; //42 x 24
volatile struct color led_input_buf[NUMBER_LEDS];
void word_buffer_to_pwm_buffer(volatile uint8_t* target_buffer, const uint8_t* source_buffer, int length) {
for (int byte_index=0;byte_index<length;byte_index++) {
for (int bit_index=7;bit_index>=0;bit_index--) {
*target_buffer++ = source_buffer[byte_index] & (1 << bit_index) ? BIT_1 : BIT_0;
}
}
}
void dma1_transmit(uint32_t src, uint32_t dst, uint32_t length, uint32_t channel) {
dma_channel_reset(DMA1, channel);
dma_set_peripheral_address(DMA1, channel, dst);
dma_set_memory_address(DMA1, channel, src);
dma_set_number_of_data(DMA1, channel, length);
dma_set_read_from_memory(DMA1, channel);
dma_enable_memory_increment_mode(DMA1, channel);
dma_set_peripheral_size(DMA1, channel, DMA_CCR_PSIZE_8BIT);
dma_set_memory_size(DMA1, channel, DMA_CCR_MSIZE_8BIT);
dma_set_priority(DMA1, channel, DMA_CCR_PL_VERY_HIGH);
dma_enable_channel(DMA1, channel);
}
void dma1_transmit_8_32(uint32_t src, uint32_t dst, uint32_t length, uint32_t channel) {
dma_disable_channel(DMA1, channel);
dma_channel_reset(DMA1, channel);
dma_set_peripheral_address(DMA1, channel, dst);
dma_set_memory_address(DMA1, channel, src);
dma_set_number_of_data(DMA1, channel, length);
dma_set_read_from_memory(DMA1, channel);
dma_enable_memory_increment_mode(DMA1, channel);
dma_set_peripheral_size(DMA1, channel, DMA_CCR_PSIZE_32BIT);
dma_set_memory_size(DMA1, channel, DMA_CCR_MSIZE_8BIT);
dma_set_priority(DMA1, channel, DMA_CCR_PL_VERY_HIGH);
dma_enable_channel(DMA1, channel);
}
void dma1_recieve(uint32_t src, uint32_t dst, uint32_t length, uint32_t channel) {
dma_disable_channel(DMA1, channel);
dma_channel_reset(DMA1, channel);
dma_set_peripheral_address(DMA1, channel, src);
dma_set_memory_address(DMA1, channel, dst);
dma_set_number_of_data(DMA1, channel, length);
dma_set_read_from_peripheral(DMA1, channel);
dma_enable_memory_increment_mode(DMA1, channel);
dma_set_peripheral_size(DMA1, channel, DMA_CCR_PSIZE_8BIT);
dma_set_memory_size(DMA1, channel, DMA_CCR_MSIZE_8BIT);
dma_set_priority(DMA1, channel, DMA_CCR_PL_VERY_HIGH);
dma_enable_channel(DMA1, channel);
}
void sys_tick_handler(void) {
if (ms_time_delay) {
ms_time_delay--;
}
}
void sleep_ms(int t) {
ms_time_delay = t; while (ms_time_delay);
}
void colorHexagon(int hue, int *R, int *G, int *B) {
int frac = hue >> 12;
int ci = hue & 0xFFF;
int cd = 4095 - ci;
int cs = 4095;
switch (frac) {
case 0: *R = cs; *G = ci; *B = 0; break; //R1 G+ B0
case 1: *R = cd; *G = cs; *B = 0; break; //R- G1 B0
case 2: *R = 0; *G = cs; *B = ci; break; //R0 G1 B+
case 3: *R = 0; *G = cd; *B = cs; break; //R0 G- B1
case 4: *R = ci; *G = 0; *B = cs; break; //R+ G0 B1
case 5: *R = cs; *G = 0; *B = cd; break; //R1 G0 B-
}
}
unsigned long xorshf96(void) { /* A George Marsaglia generator, period 2^96-1 */
static unsigned long x=123456789, y=362436069, z=521288629;
unsigned long t;
x ^= x << 16;
x ^= x >> 5;
x ^= x << 1;
t = x;
x = y;
y = z;
z = t ^ x ^ y;
return z;
}
void init_rcc() {
rcc_clock_setup_in_hsi_out_24mhz();
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_AFIO);
rcc_periph_clock_enable(RCC_TIM2);
rcc_periph_clock_enable(RCC_DMA1);
rcc_periph_clock_enable(RCC_USART1);
}
void init_gpio() {
//LED data out
gpio_set(GPIOA, GPIO0);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO0);
//usart RX
gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX);
}
void init_systick() {
ms_time_delay=0;
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
systick_set_reload(24000-1); // 1 kHz
systick_interrupt_enable();
systick_counter_enable();
}
void init_timer() {
TIM2_CR1 = TIM_CR1_CKD_CK_INT | TIM_CR1_CMS_EDGE;
/* Period */
TIM2_ARR = (24000000 / FREQ)-1;
/* Prescaler */
TIM2_PSC = 0;
TIM2_EGR = TIM_EGR_UG;
/* Output compare 3 mode and preload */
TIM2_CCMR1 |= TIM_CCMR1_OC1M_PWM1 | TIM_CCMR1_OC1PE;
/* Polarity and state */
TIM2_CCER |= TIM_CCER_CC1E;
/* ARR reload enable */
TIM2_CR1 |= TIM_CR1_ARPE;
/* Counter enable */
TIM2_CR1 |= TIM_CR1_CEN;
TIM2_CCR1 = 0;
}
void init_usart() {
usart_set_baudrate(USART1, 1000000);
usart_set_databits(USART1, 8);
usart_set_stopbits(USART1, USART_STOPBITS_1);
usart_set_mode(USART1, USART_MODE_RX);
usart_set_parity(USART1, USART_PARITY_NONE);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
usart_enable(USART1);
}
void init_nvic() {
nvic_set_priority(NVIC_DMA1_CHANNEL5_IRQ, 0);
nvic_enable_irq(NVIC_DMA1_CHANNEL5_IRQ);
}
void init_stuff() {
init_rcc();
init_gpio();
init_systick();
init_timer();
init_usart();
// init_nvic();
}
void populate_test_buffer() {
// start populate buffer
for (int led=0;led<NUMBER_LEDS;led++) {
led_input_buf[led].r = led * 1;
led_input_buf[led].g = led * 2;
led_input_buf[led].b = 255 -led * 3;
}
}
void send_led_buffer() {
//Send led data
//dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL5);
// TIM2_DIER &= ~TIM_DIER_CC1DE; //Disable DMA transfer for CC1
// usart_disable_rx_dma(USART1);
dma1_transmit_8_32((uint32_t) led_output_buf, (uint32_t) &TIM2_CCR1, 24*NUMBER_LEDS+1, DMA_CHANNEL5 );
TIM2_DIER |= TIM_DIER_CC1DE; //Enable DMA transfer for CC1
}
void send_led_buffer_blocking() {
send_led_buffer();
while (!dma_get_interrupt_flag(DMA1, DMA_CHANNEL5, DMA_TCIF));
TIM2_DIER &= ~TIM_DIER_CC1DE; //Disable DMA transfer for CC1
}
void recieve_led_data_blocking() {
dma1_recieve((uint32_t)&USART1_DR, (uint32_t)led_input_buf, NUMBER_LEDS * sizeof(struct color), DMA_CHANNEL5);
//dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL5);
usart_enable_rx_dma(USART1);
while (!dma_get_interrupt_flag(DMA1, DMA_CHANNEL5, DMA_TCIF));
usart_disable_rx_dma(USART1);
}
void led_mapper_feature() {
const int white_wait = 100;
const int black_wait = 100;
const int channel_wait = 3000;
const int inter_channel_wait = 100;
const int inter_sequence_wait = 3000;
void fill_led_buffer(int r, int g, int b) {
for (int l=0; l<NUMBER_LEDS; l++) {
led_input_buf[l] = (struct color) {r, g, b};
}
}
void flash_white(int count) {
for (int c=0; c<count; c++) {
fill_led_buffer(255, 255, 255);
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(white_wait);
fill_led_buffer(0, 0, 0);
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(black_wait);
}
}
while (1) {
flash_white(3);
for (int led_index=0; led_index<NUMBER_LEDS; led_index++) {
//Send red
fill_led_buffer(0, 0, 0);
led_input_buf[led_index].r = 255;
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(channel_wait);
fill_led_buffer(0, 0, 0);
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(inter_channel_wait);
//Send green
fill_led_buffer(0, 0, 0);
led_input_buf[led_index].g = 255;
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(channel_wait);
fill_led_buffer(0, 0, 0);
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(inter_channel_wait);
//Send blue
fill_led_buffer(0, 0, 0);
led_input_buf[led_index].b = 255;
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(channel_wait);
fill_led_buffer(0, 0, 0);
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(inter_channel_wait);
//Send white
fill_led_buffer(0, 0, 0);
led_input_buf[led_index].r = 255;
led_input_buf[led_index].g = 255;
led_input_buf[led_index].b = 255;
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(channel_wait);
fill_led_buffer(0, 0, 0);
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(inter_channel_wait);
}
flash_white(5);
sleep_ms(inter_sequence_wait);
}
}
int main() {
init_stuff();
led_mapper_feature();
//populate_test_buffer();
int R, G, B, H=0;
while(1) {
for (int led=0; led<NUMBER_LEDS; led++) {
int local_hue = (H + led*HUE_SPREAD) % HUE_RANGE;
colorHexagon(local_hue, &R, &G, &B);
led_input_buf[led].r = R >> 4;
led_input_buf[led].g = G >> 4;
led_input_buf[led].b = B >> 4;
}
H = (H+HUE_SPEED) % HUE_RANGE;
word_buffer_to_pwm_buffer(led_output_buf, (uint8_t* ) led_input_buf, NUMBER_LEDS*3);
send_led_buffer_blocking();
sleep_ms(1);
}
// process_buffer();
// send_led_buffer_blocking();
// while(1) {
// recieve_led_data_blocking();
// process_buffer();
// send_led_buffer_blocking();
// }
return 0;
}
void dma1_channel5_isr(void) {
DMA1_IFCR |= DMA_IFCR_CTCIF5;
// switch (dma_mode) {
// case RECIEVE_LED_DATA:
// TIM2_DIER &= ~TIM_DIER_CC1DE; //Disable DMA transfer for CC1
// dma_mode = SEND_LED_DATA;
// dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL5);
// dma1_transmit_8_32((uint32_t) buf, (uint32_t) &TIM2_CCR1, 24*NUMBER_LEDS+1, DMA_CHANNEL5 );
// TIM2_DIER |= TIM_DIER_CC1DE; //Enable DMA transfer for CC1
// break;
// case SEND_LED_DATA:
// dma1_recieve((uint32_t)&USART1_DR, (uint32_t)led_data, 32, DMA_CHANNEL5);
// dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL5);
// usart_enable_rx_dma(USART1);
// break;
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment