当前位置: 首页 > news >正文

潍坊网站维护深圳网络推广培训

潍坊网站维护,深圳网络推广培训,加强网站建设的意见,党建网站建设解决方案串口DMA 环形缓冲,最直接的做法是DMA 一个buffer, ringbuffer再搞个buffer, 接收和发送时再把数据倒来倒去。但这样会有个问题,两个缓冲本质上是重复的,如果都很大,那就相当于浪费了一半内存!!&#xff01…

        串口DMA + 环形缓冲,最直接的做法是DMA 一个buffer, ringbuffer再搞个buffer, 接收和发送时再把数据倒来倒去。但这样会有个问题,两个缓冲本质上是重复的,如果都很大,那就相当于浪费了一半内存!!!DMA应该是可以和ringbuffer共用一个缓冲的...

  • 串口发送时,不管DMA有没有在工作,都先将数据写入环形缓冲(避免阻塞主程序,在中断程序里面也能打印!)
  • 如果DMA空闲就用DMA发送,DMA发送完成产生中断后,如果缓冲区还有数据则继续启动DMA发送,直到发完数据。
  • 只要缓冲区合理,就可以一次性写入大量数据,DMA再自己慢慢的发送出去。
  • 串口接收时,如果有串口空闲中断就更新接收计数,如果有DMA完成中断就重新开始接收
  • DMA会自己一直往缓冲区写入数据,只要在串口空闲中断和DMA完成中断中更新接收计数即可。
  • 发送和接收过程全部由DMA完成,不占用CPU时间
/** @Author: LVGRAPE* @LastEditors: LVGRAPE*/
#include "drv_serial.h"
#include <string.h>
#include <stdbool.h>
#include "drv_pin.h"
#include "drv_led.h"#define USART1_TX_BUFFER_SIZE 1024
#define USART1_RX_BUFFER_SIZE 64uint16_t tx1_size;
volatile bool tx1_busy = 0;uint8_t usart1_tx_buffer[USART1_TX_BUFFER_SIZE];//DMA, ringbuffer 共用缓冲。 DMA 读出,ringbuffer 写入
uint8_t usart1_rx_buffer[USART1_RX_BUFFER_SIZE];//DMA, ringbuffer 共用缓冲。 DMA 写入,ringbuffer 读出
struct rt_ringbuffer rx1_ringbuffer = {.buffer_ptr = usart1_rx_buffer,.read_mirror = 0,.read_index = 0,.read_mirror = 0,.write_index = 0,.buffer_size = USART1_RX_BUFFER_SIZE
};
struct rt_ringbuffer tx1_ringbuffer = {.buffer_ptr = usart1_tx_buffer,.read_mirror = 0,.read_index = 0,.write_mirror = 0,.write_index = 0,.buffer_size = USART1_TX_BUFFER_SIZE
};/*** @brief 计算缓冲区中没有发送的数据,如果缓冲区中有数据,则启动DMA发送** @return int*/
int tx1_send_buffer(void)
{if (tx1_ringbuffer.read_index <= tx1_ringbuffer.write_index){/**缓冲未满,全部发送 *//** |---------Read----[data]-----Write-----------| */tx1_size = tx1_ringbuffer.write_index - tx1_ringbuffer.read_index;}else{/**缓冲已满,先发一部分,DMA中断接手剩余部分 *//**发送完成后,Read就回到Write左边了,也就是未满状态!环形缓冲转起来了!*//** |----[data]-----Write-----Read----[data]-----| */tx1_size = tx1_ringbuffer.buffer_size - tx1_ringbuffer.read_index;}if (tx1_size > 0){/**DMA发送 */tx1_busy = 1;DMA1_CHANNEL1->maddr = (uint32_t)tx1_ringbuffer.buffer_ptr + tx1_ringbuffer.read_index;//start address + read indexDMA1_CHANNEL1->dtcnt = tx1_size;dma_channel_enable(DMA1_CHANNEL1, TRUE);}return tx1_size;
}
/*** @brief  把数据写入到缓冲区,如果DMA没有在忙,则启动DMA发送,* DMA会连续在发送,直到缓冲区为空** @param buf* @param size* @return int*/
int uart1_write(uint8_t *buf, rt_size_t size)
{/**先把数据写入到缓冲区 */rt_ringbuffer_put(&tx1_ringbuffer, buf, size);/**如果DMA没有在忙,则启动DMA发送 */if (!tx1_busy){return tx1_send_buffer();}return 0;
}
/*** @brief  从缓冲区中读取数据** @param buf* @param size* @return int*/
int uart1_read(uint8_t *buf, rt_size_t size)
{return rt_ringbuffer_get(&rx1_ringbuffer, buf, size);
}
/*** @brief 缓冲区中有多少数据未读取** @return int16_t*/
int16_t usart1_get_rx_data_len(void)
{return rt_ringbuffer_data_len(&rx1_ringbuffer);
}/*** @brief  DMA发送完成中断。* @param  none* @retval none*/
void DMA1_Channel1_IRQHandler(void)
{rt_enter_critical();if (dma_interrupt_flag_get(DMA1_FDT1_FLAG)){tx1_busy = 0;dma_flag_clear(DMA1_FDT1_FLAG);dma_channel_enable(DMA1_CHANNEL1, FALSE);tx1_ringbuffer.read_index += tx1_size;if (tx1_ringbuffer.read_index >= tx1_ringbuffer.buffer_size){//下一圈tx1_ringbuffer.read_mirror = ~tx1_ringbuffer.read_mirror;tx1_ringbuffer.read_index -= tx1_ringbuffer.buffer_size;}/**NOTE 如果缓冲区中还有数据,继续发送 */tx1_send_buffer();}rt_exit_critical();
}/*** @brief  DMA接收完成中断* @param  none* @retval none*/
void DMA1_Channel2_IRQHandler(void)
{rt_enter_critical();if (dma_interrupt_flag_get(DMA1_FDT2_FLAG)){dma_flag_clear(DMA1_FDT2_FLAG);dma_channel_enable(DMA1_CHANNEL2, false);/**NOTE DMA不重置的话,计数就不会重置,接收内存地址也会继续增加 *//**NOTE DMA传输完成中断,说明缓冲已满,从头开始 */rx1_ringbuffer.write_index = 0;rx1_ringbuffer.write_mirror = ~rx1_ringbuffer.write_mirror;/**NOTE 重新接收 */DMA1_CHANNEL2->maddr = (uint32_t)usart1_rx_buffer;dma_data_number_set(DMA1_CHANNEL2, USART1_RX_BUFFER_SIZE);dma_channel_enable(DMA1_CHANNEL2, true);}rt_exit_critical();
}
/*** @brief  USART1 空闲中断,主要是为了避免DMA完全接收完的时间太久,* 所以使用空闲中断来及时更新接收到的数据长度**/
void USART1_IRQHandler(void)
{rt_enter_critical();if (usart_interrupt_flag_get(USART1, USART_IDLEF_FLAG)){usart_flag_clear(USART1, USART_IDLEF_FLAG);usart_data_receive(USART1);/**NOTE 使用IDLE中断来更新接收到的数据长度 *//**NOTE DMA向下计数,剩余多少即是接收了多少 *//**NOTE DMA完成中断会必须要优先于空闲中断,并先将DMA计数重置 *//**NOTE |MAX------[DATA]---DMA_CNT-------0| *//**NOTE |0--------[DATA]---Write-------MAX| */uint16_t rxCnt = USART1_RX_BUFFER_SIZE - dma_data_number_get(DMA1_CHANNEL2);rx1_ringbuffer.write_index = rxCnt;}rt_exit_critical();
}int rt_hw_console_init(void)
{rt_hw_uart1_init();return 0;
}void rt_hw_console_output(const char *str)
{uint16_t len = rt_strlen(str);uart1_write((uint8_t *)str, len);
}
int rt_hw_console_getchar(void)
{rt_uint8_t ch = -1;if (rt_ringbuffer_getchar(&rx1_ringbuffer, &ch) == 1)return ch;return -1;
}
/*** @brief  config usart* @param  none* @retval none*/
void usart_configuration(void)
{gpio_init_type gpio_init_struct;/* enable the usart1 and gpio clock */crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);gpio_default_para_init(&gpio_init_struct);/* configure the usart2 tx pin */gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_mode = GPIO_MODE_MUX;gpio_init_struct.gpio_pins = GPIO_PINS_9;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init(GPIOA, &gpio_init_struct);/* configure the usart2 rx pin */gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;gpio_init_struct.gpio_pins = GPIO_PINS_10;gpio_init_struct.gpio_pull = GPIO_PULL_UP;gpio_init(GPIOA, &gpio_init_struct);/* configure usart2 param */usart_init(USART1, 921600, USART_DATA_8BITS, USART_STOP_1_BIT);usart_transmitter_enable(USART1, TRUE);usart_receiver_enable(USART1, TRUE);usart_dma_transmitter_enable(USART1, TRUE);usart_dma_receiver_enable(USART1, TRUE);usart_interrupt_enable(USART1, USART_IDLE_INT, TRUE);nvic_irq_enable(USART1_IRQn, 1, 1);usart_enable(USART1, TRUE);
}/*** @brief  config dma for usart2 and usart3* @param  none* @retval none*/
void dma_configuration(void)
{dma_init_type dma_init_struct;/* enable dma1 clock */crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);/* dma1 channel1 for usart1 tx configuration */dma_reset(DMA1_CHANNEL1);dma_default_para_init(&dma_init_struct);dma_init_struct.buffer_size = USART1_TX_BUFFER_SIZE;dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;dma_init_struct.memory_base_addr = (uint32_t)usart1_tx_buffer;dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;dma_init_struct.memory_inc_enable = TRUE;dma_init_struct.peripheral_base_addr = (uint32_t)&USART1->dt;dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;dma_init_struct.peripheral_inc_enable = FALSE;dma_init_struct.priority = DMA_PRIORITY_MEDIUM;dma_init_struct.loop_mode_enable = FALSE;dma_init(DMA1_CHANNEL1, &dma_init_struct);/* enable transfer full data interrupt */dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);/* dma1 channel1 interrupt nvic init */nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);/* config flexible dma for usart2 tx */dma_flexible_config(DMA1, FLEX_CHANNEL1, DMA_FLEXIBLE_UART1_TX);/* dma1 channel2 for usart1 rx configuration */dma_reset(DMA1_CHANNEL2);dma_default_para_init(&dma_init_struct);dma_init_struct.buffer_size = USART1_RX_BUFFER_SIZE;dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;dma_init_struct.memory_base_addr = (uint32_t)usart1_rx_buffer;dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;dma_init_struct.memory_inc_enable = TRUE;dma_init_struct.peripheral_base_addr = (uint32_t)&USART1->dt;dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;dma_init_struct.peripheral_inc_enable = FALSE;dma_init_struct.priority = DMA_PRIORITY_MEDIUM;dma_init_struct.loop_mode_enable = FALSE;dma_init(DMA1_CHANNEL2, &dma_init_struct);/* enable transfer full data interrupt */dma_interrupt_enable(DMA1_CHANNEL2, DMA_FDT_INT, TRUE);/* dma1 channel2 interrupt nvic init */nvic_irq_enable(DMA1_Channel2_IRQn, 0, 0);/* config flexible dma for usart2 rx */dma_flexible_config(DMA1, FLEX_CHANNEL2, DMA_FLEXIBLE_UART1_RX);dma_channel_enable(DMA1_CHANNEL2, TRUE); /* usart1 rx begin dma receiving */
}
void rt_hw_uart1_init(void)
{usart_configuration();dma_configuration();led_pins_init();
}

http://www.cadmedia.cn/news/13673.html

相关文章:

  • 如何挑选网站建设平台b2b和b2c是什么意思
  • 吉林省建设厅证件查询网站seo超级外链
  • 电商平台系统上海优化seo公司
  • 快乐无极网站精准拓客软件哪个好
  • 给网站做维护是什么工作卖网站链接
  • 网站制作公司 哪家好seo网站平台
  • 代理网店一件代发福州短视频seo方法
  • 免费b站不收费网站2023免费制作自己的网页
  • 网站建设微信公众号小程序app网络营销买什么好
  • 景区网站如何建设小红书推广平台
  • 网站找回备案密码怎么不对网站运营管理
  • 个人网站搭建详细步骤经典网络营销案例
  • 温州鹿城区企业网站搭建谷歌seo培训
  • 建设人才库网站网推渠道
  • 网站建设费属于无形资产吗2023网站推广入口
  • 重庆沙坪坝新闻最新消息seo最好的工具
  • 抖音代运营都做什么seo云优化方法
  • 新疆网架公司seo是干啥的
  • 怎么创建网站自己创建系列推广软文范例
  • 建筑导航网站重庆疫情最新数据
  • 如何做能上传视频网站网络上哪里可以做推广
  • 北滘网站建设网站优化平台
  • app商城需要手机网站吗专业推广公司
  • 企业网站直销例子网络营销首先要
  • 网站建设首页布局优化资讯
  • 个人网站制作申请优化外包服务公司
  • 汉阳网页设计苏州关键词优化怎样
  • 网站建设营销解决方案广州网站推广排名
  • 建一个电商网站要多少钱上海百度推广方案
  • 建设刷单网站销售找客户的方法