Move include files out of uart folder
This commit is contained in:
135
stm-firmware/stm-periph/clock-enable-manager.c
Normal file
135
stm-firmware/stm-periph/clock-enable-manager.c
Normal file
@@ -0,0 +1,135 @@
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <helper-macros/helper-macros.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct rcc_enable_count {
|
||||
volatile uint32_t *rcc_reg_addr;
|
||||
uint32_t enable_bit_cnt;
|
||||
uint8_t rcc_enable_bit_pos;
|
||||
};
|
||||
|
||||
#if RCC_ENABLE_MANAGER_STATIC
|
||||
|
||||
static struct rcc_enable_count enable_count_list[RCC_ENABLE_MANAGER_COUNT] = {0};
|
||||
|
||||
#else
|
||||
#error "RCC manager with dynamic memory not implemented!"
|
||||
#endif
|
||||
|
||||
#if RCC_ENABLE_MANAGER_STATIC
|
||||
static struct rcc_enable_count *search_enable_entry_in_list(volatile uint32_t *reg_addr, uint8_t bit_pos)
|
||||
{
|
||||
int i;
|
||||
struct rcc_enable_count *ret_element = NULL;
|
||||
struct rcc_enable_count *current_element;
|
||||
|
||||
for (i = 0; i < COUNT_OF(enable_count_list); i++) {
|
||||
current_element = &enable_count_list[i];
|
||||
|
||||
/* Check if register address and bit position match */
|
||||
if (reg_addr != current_element->rcc_reg_addr)
|
||||
continue;
|
||||
if (bit_pos != current_element->rcc_enable_bit_pos)
|
||||
continue;
|
||||
|
||||
/* Found entry. Wohoo! */
|
||||
ret_element = current_element;
|
||||
}
|
||||
|
||||
return ret_element;
|
||||
}
|
||||
|
||||
static struct rcc_enable_count *enable_entry_list_get_free_entry()
|
||||
{
|
||||
struct rcc_enable_count *ret_ptr = NULL;
|
||||
const int list_len = COUNT_OF(enable_count_list);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < list_len; i++) {
|
||||
if (enable_count_list[i].rcc_reg_addr == NULL) {
|
||||
ret_ptr = &enable_count_list[i];
|
||||
|
||||
/* Clear the count value to be safe */
|
||||
ret_ptr->enable_bit_cnt = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_ptr;
|
||||
}
|
||||
|
||||
static void enable_entry_list_remove_entry(struct rcc_enable_count *entry)
|
||||
{
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
entry->rcc_reg_addr = NULL;
|
||||
entry->enable_bit_cnt = 0;
|
||||
entry->rcc_enable_bit_pos = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int rcc_manager_enable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no)
|
||||
{
|
||||
int ret_val = 0;
|
||||
struct rcc_enable_count *entry;
|
||||
|
||||
if (!rcc_enable_register || bit_no > 31) {
|
||||
return -1000;
|
||||
}
|
||||
|
||||
/* Enable the clock in any case, no matter what follows */
|
||||
*rcc_enable_register |= (1U<<bit_no);
|
||||
|
||||
/* Check if bit is already in list */
|
||||
entry = search_enable_entry_in_list(rcc_enable_register, bit_no);
|
||||
|
||||
if (!entry) {
|
||||
/* Create ne entry at first free place in list */
|
||||
entry = enable_entry_list_get_free_entry();
|
||||
|
||||
/* Check if entry is valid. If not return */
|
||||
if (!entry) {
|
||||
ret_val = -1;
|
||||
goto ret_error_code;
|
||||
}
|
||||
|
||||
/* Set entry */
|
||||
entry->rcc_reg_addr = rcc_enable_register;
|
||||
entry->rcc_enable_bit_pos = bit_no;
|
||||
}
|
||||
|
||||
/* Increment enable counter */
|
||||
entry->enable_bit_cnt++;
|
||||
|
||||
ret_error_code:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int rcc_manager_disable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no)
|
||||
{
|
||||
int ret_val = -1;
|
||||
struct rcc_enable_count *entry;
|
||||
|
||||
if (!rcc_enable_register || bit_no > 31) {
|
||||
return -1000;
|
||||
}
|
||||
|
||||
entry = search_enable_entry_in_list(rcc_enable_register, bit_no);
|
||||
|
||||
/* If entry is found and has a count of zero, disable clock */
|
||||
if (entry) {
|
||||
/* Found entry => Decrement count and delete if zero */
|
||||
entry->enable_bit_cnt--;
|
||||
if (entry->enable_bit_cnt <= 0) {
|
||||
enable_entry_list_remove_entry(entry);
|
||||
|
||||
/* Disable clock */
|
||||
*rcc_enable_register &= ~(1U<<bit_no);
|
||||
}
|
||||
|
||||
ret_val = 0;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
240
stm-firmware/stm-periph/dma-ring-buffer.c
Normal file
240
stm-firmware/stm-periph/dma-ring-buffer.c
Normal file
@@ -0,0 +1,240 @@
|
||||
#include <stm-periph/dma-ring-buffer.h>
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
static int dma_ring_buffer_switch_clock_enable(uint8_t base_dma, bool clk_en)
|
||||
{
|
||||
int ret_val;
|
||||
int (*clk_func)(volatile uint32_t *, uint8_t);
|
||||
|
||||
if (clk_en)
|
||||
clk_func = rcc_manager_enable_clock;
|
||||
else
|
||||
clk_func = rcc_manager_disable_clock;
|
||||
|
||||
switch (base_dma) {
|
||||
case 1:
|
||||
ret_val = clk_func(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA1EN));
|
||||
break;
|
||||
case 2:
|
||||
ret_val = clk_func(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
|
||||
break;
|
||||
default:
|
||||
ret_val = -1000;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_buffer, uint8_t base_dma_id,
|
||||
DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size,
|
||||
void *data_buffer, void* src_reg, uint8_t dma_trigger_channel)
|
||||
{
|
||||
int ret_val = 0;
|
||||
|
||||
if (!dma_buffer || !dma_stream || !data_buffer || !src_reg)
|
||||
return -1000;
|
||||
|
||||
if (dma_trigger_channel > 7)
|
||||
return -1007;
|
||||
|
||||
dma_buffer->base_dma_id = base_dma_id;
|
||||
|
||||
ret_val = dma_ring_buffer_switch_clock_enable(base_dma_id, true);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
dma_buffer->dma = dma_stream;
|
||||
dma_buffer->get_idx = 0;
|
||||
dma_buffer->buffer_count = buffer_element_count;
|
||||
|
||||
dma_buffer->data_ptr = data_buffer;
|
||||
dma_buffer->element_size = element_size;
|
||||
|
||||
dma_stream->PAR = (uint32_t)src_reg;
|
||||
dma_stream->M0AR = (uint32_t)data_buffer;
|
||||
dma_stream->NDTR = buffer_element_count;
|
||||
dma_stream->NDTR = buffer_element_count;
|
||||
|
||||
dma_stream->CR |= (dma_trigger_channel<<25) | DMA_SxCR_MINC | DMA_SxCR_CIRC | DMA_SxCR_EN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_ring_buffer_periph_to_mem_get_data(struct dma_ring_buffer_to_mem *buff, const void **data_buff, size_t *len)
|
||||
{
|
||||
int ret_code = 0;
|
||||
uint32_t ndtr;
|
||||
size_t put_idx;
|
||||
|
||||
if (!buff || !data_buff || !len)
|
||||
return -1;
|
||||
|
||||
|
||||
ndtr = buff->dma->NDTR;
|
||||
put_idx = buff->buffer_count - ndtr;
|
||||
|
||||
/* Check if wrap around */
|
||||
if (put_idx < buff->get_idx) {
|
||||
*data_buff = &(((char *)buff->data_ptr)[buff->get_idx * buff->element_size]);
|
||||
*len = buff->buffer_count - buff->get_idx;
|
||||
buff->get_idx = 0;
|
||||
ret_code = 1;
|
||||
} else if (put_idx > buff->get_idx) {
|
||||
*data_buff = &(((char *)buff->data_ptr)[buff->get_idx * buff->element_size]);
|
||||
*len = put_idx - buff->get_idx;
|
||||
buff->get_idx += *len;
|
||||
} else {
|
||||
/* No new data */
|
||||
*len = 0;
|
||||
}
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
void dma_ring_buffer_periph_to_mem_stop(struct dma_ring_buffer_to_mem *buff)
|
||||
{
|
||||
if (!buff || !buff->dma)
|
||||
return;
|
||||
|
||||
buff->dma->CR = 0;
|
||||
buff->dma->NDTR = 0;
|
||||
buff->dma->M1AR = 0;
|
||||
buff->dma->FCR = 0;
|
||||
|
||||
dma_ring_buffer_switch_clock_enable(buff->base_dma_id, false);
|
||||
}
|
||||
|
||||
int dma_ring_buffer_mem_to_periph_initialize(struct dma_ring_buffer_to_periph *dma_buffer, uint8_t base_dma_id, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, void *data_buffer, uint8_t dma_trigger_channel, void *dest_reg)
|
||||
{
|
||||
if (!dma_buffer || !dma_stream || !data_buffer || !dest_reg)
|
||||
return -1000;
|
||||
|
||||
dma_buffer->dma = dma_stream;
|
||||
dma_buffer->dma_base_id = base_dma_id;
|
||||
dma_buffer->src_buffer = data_buffer;
|
||||
dma_buffer->buffer_count = buffer_element_count;
|
||||
dma_buffer->element_size = element_size;
|
||||
dma_buffer->sw_put_idx = 0U;
|
||||
dma_buffer->dma_get_idx_current = 0U;
|
||||
dma_buffer->dma_get_idx_future = 0U;
|
||||
|
||||
dma_ring_buffer_switch_clock_enable(base_dma_id, true);
|
||||
|
||||
dma_stream->PAR = (uint32_t)dest_reg;
|
||||
dma_stream->CR = DMA_SxCR_MINC | DMA_SxCR_TCIE | (dma_trigger_channel<<25) | DMA_SxCR_DIR_0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t calculate_ring_buffer_fill_level(size_t buffer_size, size_t get_idx, size_t put_idx)
|
||||
{
|
||||
size_t fill_level;
|
||||
|
||||
if (put_idx >= get_idx) {
|
||||
fill_level = (put_idx - get_idx);
|
||||
} else {
|
||||
fill_level = buffer_size - get_idx + put_idx;
|
||||
}
|
||||
|
||||
return fill_level;
|
||||
}
|
||||
|
||||
static void queue_or_start_dma_transfer(struct dma_ring_buffer_to_periph *buff)
|
||||
{
|
||||
uint32_t dma_transfer_cnt;
|
||||
|
||||
if (!buff)
|
||||
return;
|
||||
|
||||
/* Check if DMA is running. Do nothing in this case. Will be stated from interrupt */
|
||||
if (buff->dma_get_idx_current != buff->dma_get_idx_future)
|
||||
return;
|
||||
|
||||
/* No new data to transfer */
|
||||
if (buff->sw_put_idx == buff->dma_get_idx_current)
|
||||
return;
|
||||
|
||||
/* Calculate future get idx. Stop at end of buffer to prevent impossible wrap around */
|
||||
if (buff->sw_put_idx < buff->dma_get_idx_current && buff->sw_put_idx != 0) {
|
||||
buff->dma_get_idx_future = 0U;
|
||||
dma_transfer_cnt = buff->buffer_count - buff->dma_get_idx_current;
|
||||
} else {
|
||||
buff->dma_get_idx_future = buff->sw_put_idx;
|
||||
if (buff->sw_put_idx == 0)
|
||||
dma_transfer_cnt = buff->buffer_count - buff->dma_get_idx_current;
|
||||
else
|
||||
dma_transfer_cnt = buff->sw_put_idx - buff->dma_get_idx_current;
|
||||
}
|
||||
|
||||
buff->dma->NDTR = dma_transfer_cnt;
|
||||
buff->dma->M0AR = (uint32_t)&((char *)buff->src_buffer)[buff->dma_get_idx_current * buff->element_size];
|
||||
buff->dma->CR |= DMA_SxCR_EN;
|
||||
}
|
||||
|
||||
int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *buff, const void *data_to_insert, size_t count)
|
||||
{
|
||||
int ret = 0;
|
||||
size_t free_item_count;
|
||||
char *insert_ptr;
|
||||
char *dest_ptr;
|
||||
void *ptr;
|
||||
size_t first_round_count;
|
||||
|
||||
if (!buff || !data_to_insert || !count)
|
||||
return -1000;
|
||||
|
||||
/* Check if data fits into buffer minus one element. If not: try full-1 buffer and rest
|
||||
* Buffer is not allowed to be completely full, because I cannot ddifferentiate a full buffer from a completely empty one
|
||||
*/
|
||||
if (count >= buff->buffer_count) {
|
||||
ret = dma_ring_buffer_mem_to_periph_insert_data(buff, data_to_insert, buff->buffer_count - 1);
|
||||
if (ret)
|
||||
goto return_retval;
|
||||
ptr = (void *)(((char *)data_to_insert) + ((buff->buffer_count-1) * buff->element_size));
|
||||
ret = dma_ring_buffer_mem_to_periph_insert_data(buff, ptr, count - buff->buffer_count + 1);
|
||||
goto return_retval;
|
||||
}
|
||||
|
||||
/* Wait for buffer to be able to handle input */
|
||||
do {
|
||||
free_item_count = buff->buffer_count - calculate_ring_buffer_fill_level(buff->buffer_count, buff->dma_get_idx_current, buff->sw_put_idx);
|
||||
} while (free_item_count < count+1);
|
||||
|
||||
/* Fillup buffer (max is buffer end, wrap around afterwards) */
|
||||
insert_ptr = (char *)data_to_insert;
|
||||
dest_ptr = &((char *)buff->src_buffer)[buff->sw_put_idx * buff->element_size];
|
||||
if (buff->buffer_count - buff->sw_put_idx >= count) {
|
||||
memcpy(dest_ptr, insert_ptr, buff->element_size * count);
|
||||
buff->sw_put_idx += count;
|
||||
if(buff->sw_put_idx >= buff->buffer_count)
|
||||
buff->sw_put_idx = 0;
|
||||
} else {
|
||||
first_round_count = buff->element_size * (buff->buffer_count - buff->sw_put_idx);
|
||||
memcpy(dest_ptr, insert_ptr, first_round_count);
|
||||
insert_ptr += first_round_count;
|
||||
memcpy(buff->src_buffer, insert_ptr, count - first_round_count);
|
||||
buff->sw_put_idx = count - first_round_count;
|
||||
}
|
||||
queue_or_start_dma_transfer(buff);
|
||||
|
||||
return_retval:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dma_ring_buffer_mem_to_periph_int_callback(struct dma_ring_buffer_to_periph *buff)
|
||||
{
|
||||
/* update current get index */
|
||||
buff->dma_get_idx_current = buff->dma_get_idx_future;
|
||||
queue_or_start_dma_transfer(buff);
|
||||
}
|
||||
|
||||
void dma_ring_buffer_mem_to_periph_stop(struct dma_ring_buffer_to_periph *buff)
|
||||
{
|
||||
buff->dma->CR = 0;
|
||||
dma_ring_buffer_switch_clock_enable(buff->dma_base_id, false);
|
||||
|
||||
memset(buff, 0, sizeof(struct dma_ring_buffer_to_periph));
|
||||
}
|
111
stm-firmware/stm-periph/uart.c
Normal file
111
stm-firmware/stm-periph/uart.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* uart.c
|
||||
*
|
||||
* Created on: Dec 15, 2014
|
||||
* Author: shino-chan
|
||||
*/
|
||||
//USART2
|
||||
//PA2 => TX
|
||||
//PA3 => RX
|
||||
//Alternate Function 7
|
||||
#include <stm-periph/uart.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <stm-periph/stm32-gpio-macros.h>
|
||||
#include <stm-periph/dma-ring-buffer.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct dma_ring_buffer_to_mem ring_buff_rx;
|
||||
static struct dma_ring_buffer_to_periph ring_buff_tx;
|
||||
static char uart_rx_buffer[64];
|
||||
static char uart_tx_buffer[256];
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
static inline void uart_gpio_config()
|
||||
{
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(UART_PORT_RCC_MASK));
|
||||
UART_PORT->MODER &= MODER_DELETE(UART_TX_PIN) & MODER_DELETE(UART_RX_PIN);
|
||||
UART_PORT->MODER |= ALTFUNC(UART_RX_PIN) | ALTFUNC(UART_TX_PIN);
|
||||
SETAF(UART_PORT, UART_RX_PIN, UART_RX_PIN_ALTFUNC);
|
||||
SETAF(UART_PORT, UART_TX_PIN, UART_TX_PIN_ALTFUNC);
|
||||
}
|
||||
#endif
|
||||
|
||||
void uart_init_with_dma()
|
||||
{
|
||||
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(UART_RCC_MASK));
|
||||
#ifdef DEBUGBUILD
|
||||
uart_gpio_config();
|
||||
#endif
|
||||
UART_PERIPH->BRR = UART_BRR_REG_VALUE;
|
||||
UART_PERIPH->CR3 = USART_CR3_DMAR | USART_CR3_DMAT;
|
||||
UART_PERIPH->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
|
||||
|
||||
dma_ring_buffer_periph_to_mem_initialize(&ring_buff_rx, 2, UART_RECEIVE_DMA_STREAM, sizeof(uart_rx_buffer), 1U,
|
||||
uart_rx_buffer, (char *)&UART_PERIPH->DR, 4);
|
||||
dma_ring_buffer_mem_to_periph_initialize(&ring_buff_tx, 2, UART_SEND_DMA_STREAM, sizeof(uart_tx_buffer), 1U,
|
||||
uart_tx_buffer, 4U, (void *)&UART_PERIPH->DR);
|
||||
|
||||
NVIC_EnableIRQ(DMA2_Stream7_IRQn);
|
||||
}
|
||||
|
||||
void uart_disable()
|
||||
{
|
||||
UART_PERIPH->CR1 = 0;
|
||||
UART_PERIPH->CR2 = 0;
|
||||
UART_PERIPH->CR3 = 0;
|
||||
dma_ring_buffer_periph_to_mem_stop(&ring_buff_rx);
|
||||
dma_ring_buffer_mem_to_periph_stop(&ring_buff_tx);
|
||||
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(UART_PORT_RCC_MASK));
|
||||
rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(UART_RCC_MASK));
|
||||
}
|
||||
|
||||
void uart_send_char(char c)
|
||||
{
|
||||
while(!(UART_PERIPH->SR & USART_SR_TXE));
|
||||
UART_PERIPH->DR = c;
|
||||
}
|
||||
|
||||
void uart_send_array(const char *data, uint32_t len)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
uart_send_char(data[i]);
|
||||
}
|
||||
|
||||
void uart_send_string(const char *string)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; string[i] != '\0'; i++)
|
||||
uart_send_char(string[i]);
|
||||
}
|
||||
|
||||
void uart_send_array_with_dma(const char *data, uint32_t len)
|
||||
{
|
||||
dma_ring_buffer_mem_to_periph_insert_data(&ring_buff_tx, data, len);
|
||||
}
|
||||
|
||||
void uart_send_string_with_dma(const char *string)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen(string);
|
||||
uart_send_array_with_dma(string, (uint32_t)len);
|
||||
}
|
||||
|
||||
int uart_receive_data_with_dma(const char **data, size_t *len)
|
||||
{
|
||||
return dma_ring_buffer_periph_to_mem_get_data(&ring_buff_rx, (const void **)data, len);
|
||||
}
|
||||
|
||||
void DMA2_Stream7_IRQHandler()
|
||||
{
|
||||
uint32_t hisr = DMA2->HISR;
|
||||
DMA2->HIFCR = hisr;
|
||||
|
||||
if (hisr & DMA_HISR_TCIF7) {
|
||||
dma_ring_buffer_mem_to_periph_int_callback(&ring_buff_tx);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user