Merge pull request 'Implement DMX reciever and add more advanced failure mode' (#1) from dmx_receiver into master
Reviewed-on: #1
This commit is contained in:
		@@ -13,6 +13,7 @@ endif
 | 
			
		||||
#Add Files and Folders below#########################################################
 | 
			
		||||
CFILES 	= main.c syscalls/syscalls.c setup/system_init.c startup/startup_stm32f0xx.c
 | 
			
		||||
CFILES += temp-adc.c
 | 
			
		||||
CFILES += dmx.c
 | 
			
		||||
ASFILES = sk6812.S
 | 
			
		||||
INCLUDEPATH = -Iinclude -Iinclude/cmsis
 | 
			
		||||
 | 
			
		||||
@@ -37,7 +38,7 @@ SIZE=arm-none-eabi-size
 | 
			
		||||
 | 
			
		||||
LFLAGS = -mlittle-endian -mthumb -mcpu=cortex-m0 -mthumb-interwork 
 | 
			
		||||
LFLAGS += -mfloat-abi=soft --disable-newlib-supplied-syscalls -nostartfiles
 | 
			
		||||
LFLAGS += -Tstartup/stm32f030.ld -Wl,-Map=$(mapfile).map -Wl,--gc-sections -g
 | 
			
		||||
LFLAGS += -Tstartup/stm32f030.ld -Wl,-Map=$(mapfile).map -Wl,--gc-sections -Wl,--print-memory-usage -g
 | 
			
		||||
 | 
			
		||||
CFLAGS = -c -fmessage-length=0 -mlittle-endian -mthumb -mcpu=cortex-m0 -mthumb-interwork
 | 
			
		||||
CFLAGS += -mfloat-abi=soft -nostartfiles -Wall -g3 -O0
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										136
									
								
								firmware/dmx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								firmware/dmx.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
#include <ring-light/dmx.h>
 | 
			
		||||
#include <stm32f0xx.h>
 | 
			
		||||
 | 
			
		||||
static uint32_t dmx_base_channel;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum dmx_rx_state_enum {
 | 
			
		||||
	DMX_RX_WAIT_FOR_BREAK = 0,
 | 
			
		||||
	DMX_RX_DATA,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static volatile enum dmx_rx_state_enum dmx_state;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static volatile bool break_received;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief DMX data received. Contains the whole DMX universe including the first 0 byte.
 | 
			
		||||
 * The controller does check the first byte to be zero.
 | 
			
		||||
 */
 | 
			
		||||
static volatile uint8_t dmx_channel_data[DMX_UNIVERSE_SIZE + 1];
 | 
			
		||||
 | 
			
		||||
void dmx_init(uint32_t base_channel)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	volatile uint8_t *ptr;
 | 
			
		||||
 | 
			
		||||
	for (i = 0, ptr = dmx_channel_data; i < DMX_USED_CHANNEL_COUNT; i++, ptr++) {
 | 
			
		||||
		*ptr = 0u;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dmx_base_channel = base_channel;
 | 
			
		||||
	break_received = false;
 | 
			
		||||
 | 
			
		||||
	/* Enable GPIOA and USART1 clock */
 | 
			
		||||
	RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMAEN;
 | 
			
		||||
	RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
 | 
			
		||||
 | 
			
		||||
	/* Switch RXTX pin low, activating permanent READ mode */
 | 
			
		||||
	GPIOA->MODER |= (0x1<<(2*5));
 | 
			
		||||
	GPIOA->BRR |= (1<<5);
 | 
			
		||||
 | 
			
		||||
	/* Switch PA10 to RX alternate function of USART1 (AF1) */
 | 
			
		||||
	GPIOA->MODER |= (0x2<<(2*10));
 | 
			
		||||
	GPIOA->AFR[1] |=(0x1<<(4*2));
 | 
			
		||||
 | 
			
		||||
	/* Set baudrate: 48MHz / 250k = 129 */
 | 
			
		||||
	USART1->BRR = 192u;
 | 
			
		||||
	USART1->CR3 = USART_CR3_EIE;
 | 
			
		||||
	USART1->CR2 = USART_CR2_STOP_1;
 | 
			
		||||
	USART1->CR1 = USART_CR1_RXNEIE | USART_CR1_RE | USART_CR1_UE;
 | 
			
		||||
 | 
			
		||||
	/* Map USART1 RX to DMA Channel 3 */
 | 
			
		||||
	SYSCFG->CFGR1 &= ~SYSCFG_CFGR1_USART1RX_DMA_RMP;
 | 
			
		||||
 | 
			
		||||
	DMA1_Channel3->CCR = DMA_CCR_PL_1 | DMA_CCR_MINC | DMA_CCR_TCIE;
 | 
			
		||||
 | 
			
		||||
	NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
 | 
			
		||||
	NVIC_EnableIRQ(USART1_IRQn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const uint8_t *dmx_get_data()
 | 
			
		||||
{
 | 
			
		||||
	return (const uint8_t *)dmx_channel_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void USART1_IRQHandler(void)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t isr;
 | 
			
		||||
 | 
			
		||||
	isr = USART1->ISR;
 | 
			
		||||
	USART1->ICR = USART_ICR_ORECF | USART_ICR_NCF | USART_ICR_FECF;
 | 
			
		||||
 | 
			
		||||
	if (isr & USART_ISR_FE) {
 | 
			
		||||
		/* Frame error received. Start of DMX frame */
 | 
			
		||||
		/* Flush RX data */
 | 
			
		||||
		USART1->CR3 &= ~USART_CR3_DMAR;
 | 
			
		||||
		USART1->RQR = USART_RQR_RXFRQ;
 | 
			
		||||
		DMA1_Channel3->CCR &= ~DMA_CCR_EN;
 | 
			
		||||
		while (DMA1_Channel3->CCR & DMA_CCR_EN);
 | 
			
		||||
		DMA1_Channel3->CMAR = (uint32_t)dmx_channel_data;
 | 
			
		||||
		DMA1_Channel3->CPAR = (uint32_t)&USART1->RDR;
 | 
			
		||||
		DMA1_Channel3->CNDTR = DMX_UNIVERSE_SIZE + 1;
 | 
			
		||||
		DMA1_Channel3->CCR |= DMA_CCR_EN;
 | 
			
		||||
		USART1->RQR = USART_RQR_RXFRQ;
 | 
			
		||||
		USART1->CR3 |= USART_CR3_DMAR;
 | 
			
		||||
		break_received = true;
 | 
			
		||||
		dmx_state = DMX_RX_DATA;
 | 
			
		||||
	} else if (isr & USART_ISR_RXNE) {
 | 
			
		||||
		if (dmx_state != DMX_RX_DATA) {
 | 
			
		||||
			USART1->RQR = USART_RQR_RXFRQ;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	__DSB();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DMA_CH2_3_DMA2_CH1_2_IRQHandler(void)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t isr;
 | 
			
		||||
 | 
			
		||||
	isr = DMA1->ISR;
 | 
			
		||||
	/* Only clear the interupts of channel 2 (bits 11:9) */
 | 
			
		||||
	DMA1->IFCR = isr & 0xF00;
 | 
			
		||||
 | 
			
		||||
	if (isr & DMA_ISR_TCIF3) {
 | 
			
		||||
		DMA1->ISR;
 | 
			
		||||
		dmx_state = DMX_RX_WAIT_FOR_BREAK;
 | 
			
		||||
	}
 | 
			
		||||
	__DSB();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dmx_poll_break_received(void)
 | 
			
		||||
{
 | 
			
		||||
	bool ret;
 | 
			
		||||
 | 
			
		||||
	/* Atomically reset the flag */
 | 
			
		||||
	__disable_irq();
 | 
			
		||||
	ret = break_received;
 | 
			
		||||
	break_received = false;
 | 
			
		||||
	__enable_irq();
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dmx_enough_data_received()
 | 
			
		||||
{
 | 
			
		||||
	uint32_t received_count = (DMX_UNIVERSE_SIZE + 1) - DMA1_Channel3->CNDTR;
 | 
			
		||||
 | 
			
		||||
	if (received_count > (dmx_base_channel + DMX_USED_CHANNEL_COUNT)) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								firmware/include/ring-light/dmx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								firmware/include/ring-light/dmx.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
#ifndef _DMX_H_
 | 
			
		||||
#define _DMX_H_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#define DMX_UNIVERSE_SIZE (512u)
 | 
			
		||||
#define DMX_USED_CHANNEL_COUNT (129u)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Init DMX reception
 | 
			
		||||
 *
 | 
			
		||||
 * DMX data is received from the base channel onwards:
 | 
			
		||||
 * - R LED1
 | 
			
		||||
 * - G LED1
 | 
			
		||||
 * - B LED1
 | 
			
		||||
 * - W LED1
 | 
			
		||||
 * - R LED2
 | 
			
		||||
 * ...
 | 
			
		||||
 * - W LED32
 | 
			
		||||
 * - W DISCRETE
 | 
			
		||||
 *
 | 
			
		||||
 * In Sum: 129 8 bit channels
 | 
			
		||||
 *
 | 
			
		||||
 * @param base_channel Base channel the ring light will listen on
 | 
			
		||||
 */
 | 
			
		||||
void dmx_init(uint32_t base_channel);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Returns the array of the 129 DMX channels
 | 
			
		||||
 * @return
 | 
			
		||||
 */
 | 
			
		||||
const uint8_t *dmx_get_data(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Check if a break was received. This resets the flag
 | 
			
		||||
 * @return true if a break was received since the last time calling this function
 | 
			
		||||
 */
 | 
			
		||||
bool dmx_poll_break_received(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief The DMX receiver has received all data for the ring light. It can be read
 | 
			
		||||
 * @return
 | 
			
		||||
 */
 | 
			
		||||
bool dmx_enough_data_received(void);
 | 
			
		||||
 | 
			
		||||
#endif /* _DMX_H_ */
 | 
			
		||||
							
								
								
									
										129
									
								
								firmware/main.c
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								firmware/main.c
									
									
									
									
									
								
							@@ -2,6 +2,7 @@
 | 
			
		||||
#include <cmsis/core_cm0.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <ring-light/temp-adc.h>
 | 
			
		||||
#include <ring-light/dmx.h>
 | 
			
		||||
 | 
			
		||||
#define RING_MAX_LED	32u
 | 
			
		||||
#define MAX_TEMP_CELSIUS 70
 | 
			
		||||
@@ -15,7 +16,9 @@ enum ring_modes {
 | 
			
		||||
	RING_MODE_ARC,                  /*!< SK6812 closing ring */
 | 
			
		||||
	RING_MODE_QUARTER,              /*!< SK6812 walking quarter */
 | 
			
		||||
	RING_MODE_IN_FARBE_UND_BUNT,    /*!< SK6812 color mix */
 | 
			
		||||
	RING_MODE_MAX                   /*!< end of list */
 | 
			
		||||
	RING_MODE_MAX,                   /*!< end of list */
 | 
			
		||||
	RING_MODE_WAIT_DMX,
 | 
			
		||||
	RING_MODE_WAIT_DMX_BREAK
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
volatile int32_t temperature;
 | 
			
		||||
@@ -23,6 +26,7 @@ volatile int32_t temperature;
 | 
			
		||||
extern void sk6812_send_led(uint32_t rgbw);
 | 
			
		||||
 | 
			
		||||
volatile uint32_t wait_tick = 0;
 | 
			
		||||
volatile bool blink_tick = false;
 | 
			
		||||
 | 
			
		||||
static void wait_for_ticks(uint32_t ticks)
 | 
			
		||||
{
 | 
			
		||||
@@ -33,11 +37,19 @@ static void wait_for_ticks(uint32_t ticks)
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t led_val = 0x00UL;
 | 
			
		||||
	uint32_t last_led_val = 0x00UL;
 | 
			
		||||
	uint32_t led_calc_val[RING_MAX_LED] = {0x00UL};
 | 
			
		||||
	uint8_t led_pwm_val = 0u;
 | 
			
		||||
	const uint8_t *dmx_data;
 | 
			
		||||
 | 
			
		||||
	bool button_pressed = false;
 | 
			
		||||
	enum ring_modes mode = RING_MODE_ALL;
 | 
			
		||||
	bool force_led_update;
 | 
			
		||||
	bool overtemp_flag = false;
 | 
			
		||||
	enum ring_modes mode;
 | 
			
		||||
 | 
			
		||||
	/* Led value / mode before going to DMX */
 | 
			
		||||
	uint32_t led_val_before_dmx = 0u;
 | 
			
		||||
	enum ring_modes mode_before_dmx = RING_MODE_RED; /* Init to save value */
 | 
			
		||||
 | 
			
		||||
	RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN;
 | 
			
		||||
	RCC->APB1ENR |= RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM14EN;
 | 
			
		||||
@@ -83,17 +95,41 @@ int main(void)
 | 
			
		||||
	mode    = RING_MODE_WHITE_DISCRETE;
 | 
			
		||||
 | 
			
		||||
	temperature_adc_init();
 | 
			
		||||
	dmx_init(0u);
 | 
			
		||||
 | 
			
		||||
	SysTick_Config(800000);
 | 
			
		||||
	while(1) {
 | 
			
		||||
		force_led_update = false;
 | 
			
		||||
		temperature = temperature_adc_get_temp();
 | 
			
		||||
 | 
			
		||||
		if (led_val != last_led_val || button_pressed) {
 | 
			
		||||
			force_led_update = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*! -# Gradually dim down the LED brightness in case the temperature is too high */
 | 
			
		||||
		if (temperature > ((MAX_TEMP_CELSIUS) * 10)) {
 | 
			
		||||
			if (led_val > 20)
 | 
			
		||||
		if (overtemp_flag) {
 | 
			
		||||
			if (temperature < (MAX_TEMP_CELSIUS-15) * 10) {
 | 
			
		||||
				overtemp_flag = false;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			overtemp_flag = temperature > ((MAX_TEMP_CELSIUS) * 10) ? true : false;
 | 
			
		||||
		}
 | 
			
		||||
		if (overtemp_flag) {
 | 
			
		||||
			if (led_val > 2 && mode < RING_MODE_MAX)
 | 
			
		||||
				led_val--;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (dmx_poll_break_received()) {
 | 
			
		||||
			/* DMX received. Go to DMX mode.
 | 
			
		||||
			 * Save old state
 | 
			
		||||
			 */
 | 
			
		||||
			if (mode < RING_MODE_MAX) {
 | 
			
		||||
				led_val_before_dmx = led_val;
 | 
			
		||||
				mode_before_dmx = mode;
 | 
			
		||||
			}
 | 
			
		||||
			mode = RING_MODE_WAIT_DMX;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		led_pwm_val = 0u;
 | 
			
		||||
		switch (mode)
 | 
			
		||||
		{
 | 
			
		||||
@@ -163,6 +199,32 @@ int main(void)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case RING_MODE_WAIT_DMX:
 | 
			
		||||
			force_led_update = false;
 | 
			
		||||
			if (dmx_enough_data_received() && !overtemp_flag) {
 | 
			
		||||
				dmx_data = dmx_get_data();
 | 
			
		||||
				mode = RING_MODE_WAIT_DMX_BREAK;
 | 
			
		||||
				if (dmx_data[0] != 0)
 | 
			
		||||
					break;
 | 
			
		||||
				for (int i = 0; i < RING_MAX_LED; i++) {
 | 
			
		||||
					led_calc_val[i] = (dmx_data[1 + i*4 + 3]) |
 | 
			
		||||
							(dmx_data[1 + i*4 + 2] << 8) |
 | 
			
		||||
							(dmx_data[1 + i*4 + 0] << 16) |
 | 
			
		||||
							(dmx_data[1 + i*4 + 1] << 24);
 | 
			
		||||
				}
 | 
			
		||||
				led_pwm_val = dmx_data[129];
 | 
			
		||||
				force_led_update = true;
 | 
			
		||||
			} else if (overtemp_flag) {
 | 
			
		||||
				force_led_update = true;
 | 
			
		||||
				for (int i = 0; i < RING_MAX_LED; i++) {
 | 
			
		||||
					led_calc_val[i] = 0ul;
 | 
			
		||||
				}
 | 
			
		||||
				led_pwm_val = 0;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case RING_MODE_WAIT_DMX_BREAK:
 | 
			
		||||
			force_led_update = false;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			for(int i = 0; i < RING_MAX_LED; i ++) {
 | 
			
		||||
				led_calc_val[i] = 0x00000000UL;
 | 
			
		||||
@@ -170,37 +232,68 @@ int main(void)
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		TIM14->CCR1 = led_pwm_val;
 | 
			
		||||
		__disable_irq();
 | 
			
		||||
		for(int i = 0; i < RING_MAX_LED; i ++) {
 | 
			
		||||
			sk6812_send_led(led_calc_val[i]);
 | 
			
		||||
		if (overtemp_flag) {
 | 
			
		||||
			force_led_update = true;
 | 
			
		||||
			led_calc_val[0] = blink_tick ? 0x00FF0000UL : 0UL;
 | 
			
		||||
		}
 | 
			
		||||
		__enable_irq();
 | 
			
		||||
		wait_for_ticks(5);
 | 
			
		||||
 | 
			
		||||
		if (force_led_update) {
 | 
			
		||||
			TIM14->CCR1 = led_pwm_val;
 | 
			
		||||
 | 
			
		||||
			for(int i = 0; i < RING_MAX_LED; i ++) {
 | 
			
		||||
				/* Allow interrupts in between LEDs.
 | 
			
		||||
				 * They must not exceed the reset length of 80us of SK6812.
 | 
			
		||||
				 */
 | 
			
		||||
				__disable_irq();
 | 
			
		||||
				sk6812_send_led(led_calc_val[i]);
 | 
			
		||||
				__enable_irq();
 | 
			
		||||
			}
 | 
			
		||||
			last_led_val = led_val;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Only wait in case of non-DMX mode */
 | 
			
		||||
		if (!(mode == RING_MODE_WAIT_DMX_BREAK || mode == RING_MODE_WAIT_DMX) || overtemp_flag)
 | 
			
		||||
			wait_for_ticks(5);
 | 
			
		||||
 | 
			
		||||
		if((int16_t)TIM3->CNT > (int16_t)led_val) {
 | 
			
		||||
			led_val = 0u;
 | 
			
		||||
		}
 | 
			
		||||
		else if(((int16_t)led_val - (int16_t)TIM3->CNT) > UINT8_MAX) {
 | 
			
		||||
		} else if(((int16_t)led_val - (int16_t)TIM3->CNT) > UINT8_MAX) {
 | 
			
		||||
			led_val = 255u;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
		} else {
 | 
			
		||||
			led_val = (int16_t)led_val - (int16_t)TIM3->CNT;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		TIM3->CNT = 0u;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		if(button_pressed) {
 | 
			
		||||
			if(GPIOA->IDR & GPIO_IDR_0) {
 | 
			
		||||
				button_pressed = false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if(!(GPIOA->IDR & GPIO_IDR_0)) {
 | 
			
		||||
			mode = (mode + 1) % RING_MODE_MAX;
 | 
			
		||||
		} else if(!(GPIOA->IDR & GPIO_IDR_0)) {
 | 
			
		||||
			button_pressed = true;
 | 
			
		||||
			/* Button pressed */
 | 
			
		||||
			if (mode > RING_MODE_MAX) {
 | 
			
		||||
				/* In DMX mode. Abort DMX mode */
 | 
			
		||||
				mode = mode_before_dmx;
 | 
			
		||||
				led_val = led_val_before_dmx;
 | 
			
		||||
			} else {
 | 
			
		||||
				/* Normal mode switching */
 | 
			
		||||
				mode = (mode + 1) % RING_MODE_MAX;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SysTick_Handler(void) {
 | 
			
		||||
void SysTick_Handler(void)
 | 
			
		||||
{
 | 
			
		||||
	static uint32_t tick = 10;
 | 
			
		||||
 | 
			
		||||
	if (!--tick) {
 | 
			
		||||
		tick = 10;
 | 
			
		||||
		blink_tick = !blink_tick;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	wait_tick++;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -96,7 +96,7 @@ void DMA_CH1_IRQHandler(void)
 | 
			
		||||
	uint32_t isr;
 | 
			
		||||
	
 | 
			
		||||
	isr = DMA1->ISR;
 | 
			
		||||
	DMA1->IFCR = isr;
 | 
			
		||||
	DMA1->IFCR = isr & 0xF;
 | 
			
		||||
 | 
			
		||||
	if (isr & DMA_ISR_TCIF1) {
 | 
			
		||||
		process_adc_samples();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user