Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Mozi
rt-thread
提交
07c0e130
R
rt-thread
项目概览
Mozi
/
rt-thread
与 Fork 源项目一致
Fork自
RT-Thread / rt-thread
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rt-thread
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
07c0e130
编写于
5月 20, 2016
作者:
B
Bernard Xiong
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #632 from armink/master
Improve serial DMA rx mode. #628
上级
4e95fdff
7d17f50a
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
427 addition
and
146 deletion
+427
-146
bsp/stm32f10x/drivers/usart.c
bsp/stm32f10x/drivers/usart.c
+226
-90
components/drivers/serial/serial.c
components/drivers/serial/serial.c
+201
-56
未找到文件。
bsp/stm32f10x/drivers/usart.c
浏览文件 @
07c0e130
...
...
@@ -13,6 +13,7 @@
* 2010-03-29 Bernard remove interrupt Tx and DMA Rx mode
* 2013-05-13 aozima update for kehong-lingtai.
* 2015-01-31 armink make sure the serial transmit complete in putc()
* 2016-05-13 armink add DMA Rx mode
*/
#include "stm32f10x.h"
...
...
@@ -44,10 +45,22 @@
/* STM32 uart driver */
struct
stm32_uart
{
USART_TypeDef
*
uart_device
;
USART_TypeDef
*
uart_device
;
IRQn_Type
irq
;
struct
stm32_uart_dma
{
/* dma channel */
DMA_Channel_TypeDef
*
rx_ch
;
/* dma global flag */
uint32_t
rx_gl_flag
;
/* dma irq channel */
uint8_t
rx_irq_ch
;
/* last receive index */
rt_size_t
last_recv_len
;
}
dma
;
};
static
void
DMA_Configuration
(
struct
rt_serial_device
*
serial
);
static
rt_err_t
stm32_configure
(
struct
rt_serial_device
*
serial
,
struct
serial_configure
*
cfg
)
{
struct
stm32_uart
*
uart
;
...
...
@@ -93,6 +106,7 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c
static
rt_err_t
stm32_control
(
struct
rt_serial_device
*
serial
,
int
cmd
,
void
*
arg
)
{
struct
stm32_uart
*
uart
;
rt_uint32_t
ctrl_arg
=
(
rt_uint32_t
)(
arg
);
RT_ASSERT
(
serial
!=
RT_NULL
);
uart
=
(
struct
stm32_uart
*
)
serial
->
parent
.
user_data
;
...
...
@@ -113,8 +127,13 @@ static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *ar
/* enable interrupt */
USART_ITConfig
(
uart
->
uart_device
,
USART_IT_RXNE
,
ENABLE
);
break
;
/* USART config */
case
RT_DEVICE_CTRL_CONFIG
:
if
(
ctrl_arg
==
RT_DEVICE_FLAG_DMA_RX
)
{
DMA_Configuration
(
serial
);
}
break
;
}
return
RT_EOK
;
}
...
...
@@ -148,6 +167,91 @@ static int stm32_getc(struct rt_serial_device *serial)
return
ch
;
}
/**
* Serial port receive idle process. This need add to uart idle ISR.
*
* @param serial serial device
*/
static
void
dma_uart_rx_idle_isr
(
struct
rt_serial_device
*
serial
)
{
struct
stm32_uart
*
uart
=
(
struct
stm32_uart
*
)
serial
->
parent
.
user_data
;
rt_size_t
recv_total_len
,
recv_len
;
/* disable dma, stop receive data */
DMA_Cmd
(
uart
->
dma
.
rx_ch
,
DISABLE
);
recv_total_len
=
serial
->
config
.
bufsz
-
DMA_GetCurrDataCounter
(
uart
->
dma
.
rx_ch
);
if
(
recv_total_len
>
uart
->
dma
.
last_recv_len
)
{
recv_len
=
recv_total_len
-
uart
->
dma
.
last_recv_len
;
}
else
{
recv_len
=
recv_total_len
;
}
uart
->
dma
.
last_recv_len
=
recv_total_len
;
rt_hw_serial_isr
(
serial
,
RT_SERIAL_EVENT_RX_DMADONE
|
(
recv_len
<<
8
));
/* read a data for clear receive idle interrupt flag */
USART_ReceiveData
(
uart
->
uart_device
);
DMA_ClearFlag
(
uart
->
dma
.
rx_gl_flag
);
DMA_Cmd
(
uart
->
dma
.
rx_ch
,
ENABLE
);
}
/**
* DMA receive done process. This need add to DMA receive done ISR.
*
* @param serial serial device
*/
static
void
dma_rx_done_isr
(
struct
rt_serial_device
*
serial
)
{
struct
stm32_uart
*
uart
=
(
struct
stm32_uart
*
)
serial
->
parent
.
user_data
;
rt_size_t
recv_total_len
,
recv_len
;
/* disable dma, stop receive data */
DMA_Cmd
(
uart
->
dma
.
rx_ch
,
DISABLE
);
recv_total_len
=
serial
->
config
.
bufsz
-
DMA_GetCurrDataCounter
(
uart
->
dma
.
rx_ch
);
if
(
recv_total_len
>
uart
->
dma
.
last_recv_len
)
{
recv_len
=
recv_total_len
-
uart
->
dma
.
last_recv_len
;
}
else
{
recv_len
=
recv_total_len
;
}
uart
->
dma
.
last_recv_len
=
recv_total_len
;
rt_hw_serial_isr
(
serial
,
RT_SERIAL_EVENT_RX_DMADONE
|
(
recv_len
<<
8
));
DMA_ClearFlag
(
uart
->
dma
.
rx_gl_flag
);
/* reload */
DMA_SetCurrDataCounter
(
uart
->
dma
.
rx_ch
,
serial
->
config
.
bufsz
);
DMA_Cmd
(
uart
->
dma
.
rx_ch
,
ENABLE
);
}
/**
* Uart common interrupt process. This need add to uart ISR.
*
* @param serial serial device
*/
static
void
uart_isr
(
struct
rt_serial_device
*
serial
)
{
struct
stm32_uart
*
uart
=
(
struct
stm32_uart
*
)
serial
->
parent
.
user_data
;
RT_ASSERT
(
uart
!=
RT_NULL
);
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_RXNE
)
!=
RESET
)
{
rt_hw_serial_isr
(
serial
,
RT_SERIAL_EVENT_RX_IND
);
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_RXNE
);
}
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_IDLE
)
!=
RESET
)
{
dma_uart_rx_idle_isr
(
serial
);
}
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_TC
)
!=
RESET
)
{
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_TC
);
}
if
(
USART_GetFlagStatus
(
uart
->
uart_device
,
USART_FLAG_ORE
)
==
SET
)
{
stm32_getc
(
serial
);
}
}
static
const
struct
rt_uart_ops
stm32_uart_ops
=
{
stm32_configure
,
...
...
@@ -162,70 +266,68 @@ struct stm32_uart uart1 =
{
USART1
,
USART1_IRQn
,
{
DMA1_Channel5
,
DMA1_FLAG_GL5
,
DMA1_Channel5_IRQn
,
0
,
},
};
struct
rt_serial_device
serial1
;
void
USART1_IRQHandler
(
void
)
{
struct
stm32_uart
*
uart
;
/* enter interrupt */
rt_interrupt_enter
();
uart
=
&
uart1
;
uart_isr
(
&
serial1
);
/* leave interrupt */
rt_interrupt_leave
();
}
void
DMA1_Channel5_IRQHandler
(
void
)
{
/* enter interrupt */
rt_interrupt_enter
();
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_RXNE
)
!=
RESET
)
{
rt_hw_serial_isr
(
&
serial1
,
RT_SERIAL_EVENT_RX_IND
);
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_RXNE
);
}
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_TC
)
!=
RESET
)
{
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_TC
);
}
if
(
USART_GetFlagStatus
(
uart
->
uart_device
,
USART_FLAG_ORE
)
==
SET
)
{
stm32_getc
(
&
serial1
);
}
dma_rx_done_isr
(
&
serial1
);
/* leave interrupt */
rt_interrupt_leave
();
}
#endif
/* RT_USING_UART1 */
#if defined(RT_USING_UART2)
/* UART
1
device driver structure */
/* UART
2
device driver structure */
struct
stm32_uart
uart2
=
{
USART2
,
USART2_IRQn
,
{
DMA1_Channel6
,
DMA1_FLAG_GL6
,
DMA1_Channel6_IRQn
,
0
,
},
};
struct
rt_serial_device
serial2
;
void
USART2_IRQHandler
(
void
)
{
struct
stm32_uart
*
uart
;
/* enter interrupt */
rt_interrupt_enter
();
uart
=
&
uart2
;
uart
_isr
(
&
serial2
)
;
/* leave interrupt */
rt_interrupt_leave
();
}
void
DMA1_Channel6_IRQHandler
(
void
)
{
/* enter interrupt */
rt_interrupt_enter
();
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_RXNE
)
!=
RESET
)
{
rt_hw_serial_isr
(
&
serial2
,
RT_SERIAL_EVENT_RX_IND
);
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_RXNE
);
}
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_TC
)
!=
RESET
)
{
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_TC
);
}
if
(
USART_GetFlagStatus
(
uart
->
uart_device
,
USART_FLAG_ORE
)
==
SET
)
{
stm32_getc
(
&
serial2
);
}
dma_rx_done_isr
(
&
serial2
);
/* leave interrupt */
rt_interrupt_leave
();
...
...
@@ -238,32 +340,31 @@ struct stm32_uart uart3 =
{
USART3
,
USART3_IRQn
,
{
DMA1_Channel3
,
DMA1_FLAG_GL3
,
DMA1_Channel3_IRQn
,
0
,
},
};
struct
rt_serial_device
serial3
;
void
USART3_IRQHandler
(
void
)
{
struct
stm32_uart
*
uart
;
/* enter interrupt */
rt_interrupt_enter
();
uart
=
&
uart3
;
uart
_isr
(
&
serial3
)
;
/* leave interrupt */
rt_interrupt_leave
();
}
void
DMA1_Channel3_IRQHandler
(
void
)
{
/* enter interrupt */
rt_interrupt_enter
();
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_RXNE
)
!=
RESET
)
{
rt_hw_serial_isr
(
&
serial3
,
RT_SERIAL_EVENT_RX_IND
);
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_RXNE
);
}
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_TC
)
!=
RESET
)
{
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_TC
);
}
if
(
USART_GetFlagStatus
(
uart
->
uart_device
,
USART_FLAG_ORE
)
==
SET
)
{
stm32_getc
(
&
serial3
);
}
dma_rx_done_isr
(
&
serial3
);
/* leave interrupt */
rt_interrupt_leave
();
...
...
@@ -276,69 +377,66 @@ struct stm32_uart uart4 =
{
UART4
,
UART4_IRQn
,
{
DMA2_Channel3
,
DMA2_FLAG_GL3
,
DMA2_Channel3_IRQn
,
0
,
},
};
struct
rt_serial_device
serial4
;
void
UART4_IRQHandler
(
void
)
{
struct
stm32_uart
*
uart
;
/* enter interrupt */
rt_interrupt_enter
();
uart
=
&
uart4
;
uart
_isr
(
&
serial4
)
;
/* leave interrupt */
rt_interrupt_leave
();
}
void
DMA2_Channel3_IRQHandler
(
void
)
{
/* enter interrupt */
rt_interrupt_enter
();
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_RXNE
)
!=
RESET
)
{
rt_hw_serial_isr
(
&
serial4
,
RT_SERIAL_EVENT_RX_IND
);
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_RXNE
);
}
if
(
USART_GetITStatus
(
uart
->
uart_device
,
USART_IT_TC
)
!=
RESET
)
{
/* clear interrupt */
USART_ClearITPendingBit
(
uart
->
uart_device
,
USART_IT_TC
);
}
if
(
USART_GetFlagStatus
(
uart
->
uart_device
,
USART_FLAG_ORE
)
==
SET
)
{
stm32_getc
(
&
serial4
);
}
dma_rx_done_isr
(
&
serial4
);
/* leave interrupt */
rt_interrupt_leave
();
}
#endif
/* RT_USING_UART3 */
#endif
/* RT_USING_UART4 */
static
void
RCC_Configuration
(
void
)
{
#if defined(RT_USING_UART1)
/* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_GPIOA
,
ENABLE
);
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_GPIOA
|
RCC_APB2Periph_AFIO
,
ENABLE
);
/* Enable UART clock */
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_USART1
,
ENABLE
);
#endif
/* RT_USING_UART1 */
#if defined(RT_USING_UART2)
/* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_GPIOA
,
ENABLE
);
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_GPIOA
|
RCC_APB2Periph_AFIO
,
ENABLE
);
/* Enable UART clock */
RCC_APB1PeriphClockCmd
(
RCC_APB1Periph_USART2
,
ENABLE
);
#endif
/* RT_USING_UART2 */
#if defined(RT_USING_UART3)
/* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_GPIOB
,
ENABLE
);
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_GPIOB
|
RCC_APB2Periph_AFIO
,
ENABLE
);
/* Enable UART clock */
RCC_APB1PeriphClockCmd
(
RCC_APB1Periph_USART3
,
ENABLE
);
#endif
/* RT_USING_UART3 */
#if defined(RT_USING_UART4)
/* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_GPIOC
,
ENABLE
);
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_GPIOC
|
RCC_APB2Periph_AFIO
,
ENABLE
);
/* Enable UART clock */
RCC_APB1PeriphClockCmd
(
RCC_APB1Periph_UART4
,
ENABLE
);
#endif
/* RT_USING_UART4 */
}
static
void
GPIO_Configuration
(
void
)
...
...
@@ -390,7 +488,6 @@ static void GPIO_Configuration(void)
GPIO_InitStructure
.
GPIO_Pin
=
UART4_GPIO_TX
;
GPIO_Init
(
UART4_GPIO
,
&
GPIO_InitStructure
);
#endif
/* RT_USING_UART4 */
}
static
void
NVIC_Configuration
(
struct
stm32_uart
*
uart
)
...
...
@@ -405,6 +502,46 @@ static void NVIC_Configuration(struct stm32_uart* uart)
NVIC_Init
(
&
NVIC_InitStructure
);
}
static
void
DMA_Configuration
(
struct
rt_serial_device
*
serial
)
{
struct
stm32_uart
*
uart
=
(
struct
stm32_uart
*
)
serial
->
parent
.
user_data
;
struct
rt_serial_rx_fifo
*
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
serial
->
serial_rx
;
DMA_InitTypeDef
DMA_InitStructure
;
NVIC_InitTypeDef
NVIC_InitStructure
;
/* enable transmit idle interrupt */
USART_ITConfig
(
uart
->
uart_device
,
USART_IT_IDLE
,
ENABLE
);
/* DMA clock enable */
RCC_AHBPeriphClockCmd
(
RCC_AHBPeriph_DMA1
,
ENABLE
);
RCC_AHBPeriphClockCmd
(
RCC_AHBPeriph_DMA2
,
ENABLE
);
/* rx dma config */
DMA_DeInit
(
uart
->
dma
.
rx_ch
);
DMA_InitStructure
.
DMA_PeripheralBaseAddr
=
(
uint32_t
)
&
(
uart
->
uart_device
->
DR
);
DMA_InitStructure
.
DMA_MemoryBaseAddr
=
(
uint32_t
)
rx_fifo
->
buffer
;
DMA_InitStructure
.
DMA_DIR
=
DMA_DIR_PeripheralSRC
;
DMA_InitStructure
.
DMA_BufferSize
=
serial
->
config
.
bufsz
;
DMA_InitStructure
.
DMA_PeripheralInc
=
DMA_PeripheralInc_Disable
;
DMA_InitStructure
.
DMA_MemoryInc
=
DMA_MemoryInc_Enable
;
DMA_InitStructure
.
DMA_PeripheralDataSize
=
DMA_PeripheralDataSize_Byte
;
DMA_InitStructure
.
DMA_MemoryDataSize
=
DMA_MemoryDataSize_Byte
;
DMA_InitStructure
.
DMA_Mode
=
DMA_Mode_Normal
;
DMA_InitStructure
.
DMA_Priority
=
DMA_Priority_High
;
DMA_InitStructure
.
DMA_M2M
=
DMA_M2M_Disable
;
DMA_Init
(
uart
->
dma
.
rx_ch
,
&
DMA_InitStructure
);
DMA_ClearFlag
(
uart
->
dma
.
rx_gl_flag
);
DMA_ITConfig
(
uart
->
dma
.
rx_ch
,
DMA_IT_TC
,
ENABLE
);
USART_DMACmd
(
uart
->
uart_device
,
USART_DMAReq_Rx
,
ENABLE
);
DMA_Cmd
(
uart
->
dma
.
rx_ch
,
ENABLE
);
/* rx dma interrupt config */
NVIC_InitStructure
.
NVIC_IRQChannel
=
uart
->
dma
.
rx_irq_ch
;
NVIC_InitStructure
.
NVIC_IRQChannelPreemptionPriority
=
0
;
NVIC_InitStructure
.
NVIC_IRQChannelSubPriority
=
1
;
NVIC_InitStructure
.
NVIC_IRQChannelCmd
=
ENABLE
;
NVIC_Init
(
&
NVIC_InitStructure
);
}
void
rt_hw_usart_init
(
void
)
{
struct
stm32_uart
*
uart
;
...
...
@@ -420,11 +557,11 @@ void rt_hw_usart_init(void)
serial1
.
ops
=
&
stm32_uart_ops
;
serial1
.
config
=
config
;
NVIC_Configuration
(
&
uart1
);
NVIC_Configuration
(
uart
);
/* register UART1 device */
rt_hw_serial_register
(
&
serial1
,
"uart1"
,
RT_DEVICE_FLAG_RDWR
|
RT_DEVICE_FLAG_INT_RX
,
RT_DEVICE_FLAG_RDWR
|
RT_DEVICE_FLAG_INT_RX
|
RT_DEVICE_FLAG_DMA_RX
,
uart
);
#endif
/* RT_USING_UART1 */
...
...
@@ -435,11 +572,11 @@ void rt_hw_usart_init(void)
serial2
.
ops
=
&
stm32_uart_ops
;
serial2
.
config
=
config
;
NVIC_Configuration
(
&
uart2
);
NVIC_Configuration
(
uart
);
/* register UART
1
device */
/* register UART
2
device */
rt_hw_serial_register
(
&
serial2
,
"uart2"
,
RT_DEVICE_FLAG_RDWR
|
RT_DEVICE_FLAG_INT_RX
,
RT_DEVICE_FLAG_RDWR
|
RT_DEVICE_FLAG_INT_RX
|
RT_DEVICE_FLAG_DMA_RX
,
uart
);
#endif
/* RT_USING_UART2 */
...
...
@@ -451,11 +588,11 @@ void rt_hw_usart_init(void)
serial3
.
ops
=
&
stm32_uart_ops
;
serial3
.
config
=
config
;
NVIC_Configuration
(
&
uart3
);
NVIC_Configuration
(
uart
);
/* register UART
1
device */
/* register UART
3
device */
rt_hw_serial_register
(
&
serial3
,
"uart3"
,
RT_DEVICE_FLAG_RDWR
|
RT_DEVICE_FLAG_INT_RX
,
RT_DEVICE_FLAG_RDWR
|
RT_DEVICE_FLAG_INT_RX
|
RT_DEVICE_FLAG_DMA_RX
,
uart
);
#endif
/* RT_USING_UART3 */
...
...
@@ -467,12 +604,11 @@ void rt_hw_usart_init(void)
serial4
.
ops
=
&
stm32_uart_ops
;
serial4
.
config
=
config
;
NVIC_Configuration
(
&
uart4
);
NVIC_Configuration
(
uart
);
/* register UART4 device */
rt_hw_serial_register
(
&
serial4
,
"uart4"
,
RT_DEVICE_FLAG_RDWR
|
RT_DEVICE_FLAG_INT_RX
,
RT_DEVICE_FLAG_RDWR
|
RT_DEVICE_FLAG_INT_RX
|
RT_DEVICE_FLAG_DMA_RX
,
uart
);
#endif
/* RT_USING_UART4 */
}
components/drivers/serial/serial.c
浏览文件 @
07c0e130
...
...
@@ -27,9 +27,10 @@
* the size of ring buffer.
* 2014-07-10 bernard rewrite serial framework
* 2014-12-31 bernard use open_flag for poll_tx stream mode.
* 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG
* 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG
* in open function.
* 2015-11-10 bernard fix the poll rx issue when there is no data.
* 2016-05-10 armink add fifo mode to DMA rx when serial->config.bufsz != 0.
*/
#include <rthw.h>
...
...
@@ -37,13 +38,13 @@
#include <rtdevice.h>
/*
* Serial poll routines
* Serial poll routines
*/
rt_inline
int
_serial_poll_rx
(
struct
rt_serial_device
*
serial
,
rt_uint8_t
*
data
,
int
length
)
{
int
ch
;
int
size
;
RT_ASSERT
(
serial
!=
RT_NULL
);
size
=
length
;
...
...
@@ -52,7 +53,7 @@ rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data,
ch
=
serial
->
ops
->
getc
(
serial
);
if
(
ch
==
-
1
)
break
;
*
data
=
ch
;
*
data
=
ch
;
data
++
;
length
--
;
if
(
ch
==
'\n'
)
break
;
...
...
@@ -77,9 +78,9 @@ rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t
{
serial
->
ops
->
putc
(
serial
,
'\r'
);
}
serial
->
ops
->
putc
(
serial
,
*
data
);
++
data
;
--
length
;
}
...
...
@@ -96,8 +97,8 @@ rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data,
struct
rt_serial_rx_fifo
*
rx_fifo
;
RT_ASSERT
(
serial
!=
RT_NULL
);
size
=
length
;
size
=
length
;
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
serial
->
serial_rx
;
RT_ASSERT
(
rx_fifo
!=
RT_NULL
);
...
...
@@ -136,7 +137,7 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
{
int
size
;
struct
rt_serial_tx_fifo
*
tx
;
RT_ASSERT
(
serial
!=
RT_NULL
);
size
=
length
;
...
...
@@ -157,32 +158,136 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
return
size
-
length
;
}
/**
* Calculate DMA received data length.
*
* @param serial serial device
*
* @return length
*/
static
rt_size_t
rt_dma_calc_recved_len
(
struct
rt_serial_device
*
serial
)
{
static
rt_size_t
rx_length
;
struct
rt_serial_rx_fifo
*
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
serial
->
serial_rx
;
RT_ASSERT
(
rx_fifo
!=
RT_NULL
);
rx_length
=
(
rx_fifo
->
put_index
>=
rx_fifo
->
get_index
)
?
(
rx_fifo
->
put_index
-
rx_fifo
->
get_index
)
:
(
serial
->
config
.
bufsz
-
(
rx_fifo
->
get_index
-
rx_fifo
->
put_index
));
return
rx_length
;
}
/**
* Read data finish by DMA mode then update the gut index for receive fifo.
*
* @param serial serial device
* @param len get data length for this operate
*/
static
void
rt_dma_recv_update_get_index
(
struct
rt_serial_device
*
serial
,
rt_size_t
len
)
{
struct
rt_serial_rx_fifo
*
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
serial
->
serial_rx
;
RT_ASSERT
(
rx_fifo
!=
RT_NULL
);
RT_ASSERT
(
len
<=
rt_dma_calc_recved_len
(
serial
));
rx_fifo
->
get_index
+=
len
;
if
(
rx_fifo
->
get_index
>
serial
->
config
.
bufsz
)
{
rx_fifo
->
get_index
-=
serial
->
config
.
bufsz
;
}
}
/**
* DMA received finish then update put index for receive fifo.
*
* @param serial serial device
* @param len received length for this transmit
*/
static
void
rt_dma_recv_update_put_index
(
struct
rt_serial_device
*
serial
,
rt_size_t
len
)
{
struct
rt_serial_rx_fifo
*
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
serial
->
serial_rx
;
rt_size_t
i
;
RT_ASSERT
(
rx_fifo
!=
RT_NULL
);
if
(
rx_fifo
->
get_index
<=
rx_fifo
->
put_index
)
{
rx_fifo
->
put_index
+=
len
;
/* beyond the fifo end */
if
(
rx_fifo
->
put_index
>=
serial
->
config
.
bufsz
)
{
for
(
i
=
0
;
i
<=
len
/
serial
->
config
.
bufsz
;
i
++
)
{
rx_fifo
->
put_index
-=
serial
->
config
.
bufsz
;
}
/* force overwrite get index */
if
(
rx_fifo
->
put_index
>=
rx_fifo
->
get_index
)
{
rx_fifo
->
get_index
=
rx_fifo
->
put_index
+
1
;
}
}
}
else
{
rx_fifo
->
put_index
+=
len
;
if
(
rx_fifo
->
put_index
>=
rx_fifo
->
get_index
)
{
/* beyond the fifo end */
if
(
rx_fifo
->
put_index
>=
serial
->
config
.
bufsz
)
{
for
(
i
=
0
;
i
<=
len
/
serial
->
config
.
bufsz
;
i
++
)
{
rx_fifo
->
put_index
-=
serial
->
config
.
bufsz
;
}
}
/* force overwrite get index */
rx_fifo
->
get_index
=
rx_fifo
->
put_index
+
1
;
}
}
}
/*
* Serial DMA routines
*/
rt_inline
int
_serial_dma_rx
(
struct
rt_serial_device
*
serial
,
rt_uint8_t
*
data
,
int
length
)
{
rt_base_t
level
;
int
result
=
RT_EOK
;
struct
rt_serial_rx_dma
*
rx_dma
;
RT_ASSERT
((
serial
!=
RT_NULL
)
&&
(
data
!=
RT_NULL
));
rx_dma
=
(
struct
rt_serial_rx_dma
*
)
serial
->
serial_rx
;
RT_ASSERT
(
rx_dma
!=
RT_NULL
);
level
=
rt_hw_interrupt_disable
();
if
(
rx_dma
->
activated
!=
RT_TRUE
)
{
rx_dma
->
activated
=
RT_TRUE
;
serial
->
ops
->
dma_transmit
(
serial
,
data
,
length
,
RT_SERIAL_DMA_RX
);
}
else
result
=
-
RT_EBUSY
;
rt_hw_interrupt_enable
(
level
);
if
(
result
==
RT_EOK
)
return
length
;
if
(
serial
->
config
.
bufsz
==
0
)
{
int
result
=
RT_EOK
;
struct
rt_serial_rx_dma
*
rx_dma
;
rx_dma
=
(
struct
rt_serial_rx_dma
*
)
serial
->
serial_rx
;
RT_ASSERT
(
rx_dma
!=
RT_NULL
);
if
(
rx_dma
->
activated
!=
RT_TRUE
)
{
rx_dma
->
activated
=
RT_TRUE
;
RT_ASSERT
(
serial
->
ops
->
dma_transmit
!=
RT_NULL
);
serial
->
ops
->
dma_transmit
(
serial
,
data
,
length
,
RT_SERIAL_DMA_RX
);
}
else
result
=
-
RT_EBUSY
;
rt_hw_interrupt_enable
(
level
);
if
(
result
==
RT_EOK
)
return
length
;
rt_set_errno
(
result
);
return
0
;
}
else
{
struct
rt_serial_rx_fifo
*
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
serial
->
serial_rx
;
rt_size_t
recv_len
=
0
,
fifo_recved_len
=
rt_dma_calc_recved_len
(
serial
);
RT_ASSERT
(
rx_fifo
!=
RT_NULL
);
rt_set_errno
(
result
);
return
0
;
if
(
length
<
fifo_recved_len
)
{
recv_len
=
length
;
}
else
{
recv_len
=
fifo_recved_len
;
}
if
(
rx_fifo
->
get_index
+
recv_len
<
serial
->
config
.
bufsz
)
{
rt_memcpy
(
data
,
rx_fifo
->
buffer
+
rx_fifo
->
get_index
,
recv_len
);
}
else
{
rt_memcpy
(
data
,
rx_fifo
->
buffer
+
rx_fifo
->
get_index
,
serial
->
config
.
bufsz
-
rx_fifo
->
get_index
);
rt_memcpy
(
data
+
serial
->
config
.
bufsz
-
rx_fifo
->
get_index
,
rx_fifo
->
buffer
,
recv_len
+
rx_fifo
->
get_index
-
serial
->
config
.
bufsz
);
}
rt_dma_recv_update_get_index
(
serial
,
recv_len
);
rt_hw_interrupt_enable
(
level
);
return
recv_len
;
}
}
rt_inline
int
_serial_dma_tx
(
struct
rt_serial_device
*
serial
,
const
rt_uint8_t
*
data
,
int
length
)
...
...
@@ -192,8 +297,8 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *
struct
rt_serial_tx_dma
*
tx_dma
;
tx_dma
=
(
struct
rt_serial_tx_dma
*
)(
serial
->
serial_tx
);
result
=
rt_data_queue_push
(
&
(
tx_dma
->
data_queue
),
data
,
length
,
RT_WAITING_FOREVER
);
result
=
rt_data_queue_push
(
&
(
tx_dma
->
data_queue
),
data
,
length
,
RT_WAITING_FOREVER
);
if
(
result
==
RT_EOK
)
{
level
=
rt_hw_interrupt_disable
();
...
...
@@ -203,7 +308,7 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *
rt_hw_interrupt_enable
(
level
);
/* make a DMA transfer */
serial
->
ops
->
dma_transmit
(
serial
,
data
,
length
,
RT_SERIAL_DMA_TX
);
serial
->
ops
->
dma_transmit
(
serial
,
(
rt_uint8_t
*
)
data
,
length
,
RT_SERIAL_DMA_TX
);
}
else
{
...
...
@@ -250,7 +355,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
serial
=
(
struct
rt_serial_device
*
)
dev
;
/* check device flag with the open flag */
if
((
oflag
&
RT_DEVICE_FLAG_DMA_RX
)
&&
!
(
dev
->
flag
&
RT_DEVICE_FLAG_DMA_RX
))
if
((
oflag
&
RT_DEVICE_FLAG_DMA_RX
)
&&
!
(
dev
->
flag
&
RT_DEVICE_FLAG_DMA_RX
))
return
-
RT_EIO
;
if
((
oflag
&
RT_DEVICE_FLAG_DMA_TX
)
&&
!
(
dev
->
flag
&
RT_DEVICE_FLAG_DMA_TX
))
return
-
RT_EIO
;
...
...
@@ -261,26 +366,41 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
/* get open flags */
dev
->
open_flag
=
oflag
&
0xff
;
/* initialize the Rx/Tx structure according to open flag */
if
(
serial
->
serial_rx
==
RT_NULL
)
{
if
(
oflag
&
RT_DEVICE_FLAG_DMA_RX
)
{
struct
rt_serial_rx_dma
*
rx_dma
;
rx_dma
=
(
struct
rt_serial_rx_dma
*
)
rt_malloc
(
sizeof
(
struct
rt_serial_rx_dma
));
RT_ASSERT
(
rx_dma
!=
RT_NULL
);
rx_dma
->
activated
=
RT_FALSE
;
serial
->
serial_rx
=
rx_dma
;
if
(
serial
->
config
.
bufsz
==
0
)
{
struct
rt_serial_rx_dma
*
rx_dma
;
rx_dma
=
(
struct
rt_serial_rx_dma
*
)
rt_malloc
(
sizeof
(
struct
rt_serial_rx_dma
));
RT_ASSERT
(
rx_dma
!=
RT_NULL
);
rx_dma
->
activated
=
RT_FALSE
;
serial
->
serial_rx
=
rx_dma
;
}
else
{
struct
rt_serial_rx_fifo
*
rx_fifo
;
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
rt_malloc
(
sizeof
(
struct
rt_serial_rx_fifo
)
+
serial
->
config
.
bufsz
);
RT_ASSERT
(
rx_fifo
!=
RT_NULL
);
rx_fifo
->
buffer
=
(
rt_uint8_t
*
)
(
rx_fifo
+
1
);
rt_memset
(
rx_fifo
->
buffer
,
0
,
serial
->
config
.
bufsz
);
rx_fifo
->
put_index
=
0
;
rx_fifo
->
get_index
=
0
;
serial
->
serial_rx
=
rx_fifo
;
/* configure fifo address and length to low level device */
serial
->
ops
->
control
(
serial
,
RT_DEVICE_CTRL_CONFIG
,
(
void
*
)
RT_DEVICE_FLAG_DMA_RX
);
}
dev
->
open_flag
|=
RT_DEVICE_FLAG_DMA_RX
;
}
else
if
(
oflag
&
RT_DEVICE_FLAG_INT_RX
)
{
struct
rt_serial_rx_fifo
*
rx_fifo
;
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
rt_malloc
(
sizeof
(
struct
rt_serial_rx_fifo
)
+
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
rt_malloc
(
sizeof
(
struct
rt_serial_rx_fifo
)
+
serial
->
config
.
bufsz
);
RT_ASSERT
(
rx_fifo
!=
RT_NULL
);
rx_fifo
->
buffer
=
(
rt_uint8_t
*
)
(
rx_fifo
+
1
);
...
...
@@ -308,7 +428,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
tx_dma
=
(
struct
rt_serial_tx_dma
*
)
rt_malloc
(
sizeof
(
struct
rt_serial_tx_dma
));
RT_ASSERT
(
tx_dma
!=
RT_NULL
);
tx_dma
->
activated
=
RT_FALSE
;
rt_data_queue_init
(
&
(
tx_dma
->
data_queue
),
8
,
4
,
RT_NULL
);
serial
->
serial_tx
=
tx_dma
;
...
...
@@ -346,7 +466,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
/* this device has more reference count */
if
(
dev
->
ref_count
>
1
)
return
RT_EOK
;
if
(
dev
->
open_flag
&
RT_DEVICE_FLAG_INT_RX
)
{
struct
rt_serial_rx_fifo
*
rx_fifo
;
...
...
@@ -362,12 +482,23 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
}
else
if
(
dev
->
open_flag
&
RT_DEVICE_FLAG_DMA_RX
)
{
struct
rt_serial_rx_dma
*
rx_dma
;
if
(
serial
->
config
.
bufsz
==
0
)
{
struct
rt_serial_rx_dma
*
rx_dma
;
rx_dma
=
(
struct
rt_serial_rx_dma
*
)
serial
->
serial_tx
;
RT_ASSERT
(
rx_dma
!=
RT_NULL
);
rx_dma
=
(
struct
rt_serial_rx_dma
*
)
serial
->
serial_rx
;
RT_ASSERT
(
rx_dma
!=
RT_NULL
);
rt_free
(
rx_dma
);
}
else
{
struct
rt_serial_rx_fifo
*
rx_fifo
;
rt_free
(
rx_dma
);
rx_fifo
=
(
struct
rt_serial_rx_fifo
*
)
serial
->
serial_rx
;
RT_ASSERT
(
rx_fifo
!=
RT_NULL
);
rt_free
(
rx_fifo
);
}
/* configure low level device */
serial
->
ops
->
control
(
serial
,
RT_DEVICE_CTRL_CLR_INT
,
(
void
*
)
RT_DEVICE_FLAG_DMA_RX
);
serial
->
serial_rx
=
RT_NULL
;
dev
->
open_flag
&=
~
RT_DEVICE_FLAG_DMA_RX
;
}
...
...
@@ -376,7 +507,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
{
struct
rt_serial_tx_fifo
*
tx_fifo
;
tx_fifo
=
(
struct
rt_serial_tx_fifo
*
)
serial
->
serial_
r
x
;
tx_fifo
=
(
struct
rt_serial_tx_fifo
*
)
serial
->
serial_
t
x
;
RT_ASSERT
(
tx_fifo
!=
RT_NULL
);
rt_free
(
tx_fifo
);
...
...
@@ -534,30 +665,30 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
ch
=
serial
->
ops
->
getc
(
serial
);
if
(
ch
==
-
1
)
break
;
/* disable interrupt */
level
=
rt_hw_interrupt_disable
();
rx_fifo
->
buffer
[
rx_fifo
->
put_index
]
=
ch
;
rx_fifo
->
put_index
+=
1
;
if
(
rx_fifo
->
put_index
>=
serial
->
config
.
bufsz
)
rx_fifo
->
put_index
=
0
;
/* if the next position is read index, discard this 'read char' */
if
(
rx_fifo
->
put_index
==
rx_fifo
->
get_index
)
{
rx_fifo
->
get_index
+=
1
;
if
(
rx_fifo
->
get_index
>=
serial
->
config
.
bufsz
)
rx_fifo
->
get_index
=
0
;
}
/* enable interrupt */
rt_hw_interrupt_enable
(
level
);
}
/* invoke callback */
if
(
serial
->
parent
.
rx_indicate
!=
RT_NULL
)
{
rt_size_t
rx_length
;
/* get rx length */
level
=
rt_hw_interrupt_disable
();
rx_length
=
(
rx_fifo
->
put_index
>=
rx_fifo
->
get_index
)
?
(
rx_fifo
->
put_index
-
rx_fifo
->
get_index
)
:
...
...
@@ -584,19 +715,19 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
struct
rt_serial_tx_dma
*
tx_dma
;
tx_dma
=
(
struct
rt_serial_tx_dma
*
)
serial
->
serial_tx
;
rt_data_queue_pop
(
&
(
tx_dma
->
data_queue
),
&
last_data_ptr
,
&
data_size
,
0
);
if
(
rt_data_queue_peak
(
&
(
tx_dma
->
data_queue
),
&
data_ptr
,
&
data_size
)
==
RT_EOK
)
{
/* transmit next data node */
tx_dma
->
activated
=
RT_TRUE
;
serial
->
ops
->
dma_transmit
(
serial
,
data_ptr
,
data_size
,
RT_SERIAL_DMA_TX
);
serial
->
ops
->
dma_transmit
(
serial
,
(
rt_uint8_t
*
)
data_ptr
,
data_size
,
RT_SERIAL_DMA_TX
);
}
else
{
tx_dma
->
activated
=
RT_FALSE
;
}
/* invoke callback */
if
(
serial
->
parent
.
tx_complete
!=
RT_NULL
)
{
...
...
@@ -607,13 +738,27 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
case
RT_SERIAL_EVENT_RX_DMADONE
:
{
int
length
;
struct
rt_serial_rx_dma
*
rx_dma
;
rx_dma
=
(
struct
rt_serial_rx_dma
*
)
serial
->
serial_rx
;
/* get DMA rx length */
length
=
(
event
&
(
~
0xff
))
>>
8
;
serial
->
parent
.
rx_indicate
(
&
(
serial
->
parent
),
length
);
rx_dma
->
activated
=
RT_FALSE
;
if
(
serial
->
config
.
bufsz
==
0
)
{
struct
rt_serial_rx_dma
*
rx_dma
;
rx_dma
=
(
struct
rt_serial_rx_dma
*
)
serial
->
serial_rx
;
RT_ASSERT
(
rx_dma
!=
RT_NULL
);
RT_ASSERT
(
serial
->
parent
.
rx_indicate
!=
RT_NULL
);
serial
->
parent
.
rx_indicate
(
&
(
serial
->
parent
),
length
);
rx_dma
->
activated
=
RT_FALSE
;
}
else
{
/* update fifo put index */
rt_dma_recv_update_put_index
(
serial
,
length
);
/* invoke callback */
if
(
serial
->
parent
.
rx_indicate
!=
RT_NULL
)
{
serial
->
parent
.
rx_indicate
(
&
(
serial
->
parent
),
rt_dma_calc_recved_len
(
serial
));
}
}
break
;
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录