Created
November 26, 2019 19:08
-
-
Save devilholk/c22d1622e3cd2719bf9518b5adb9118a to your computer and use it in GitHub Desktop.
Simple test application for LED driving
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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