--- /dev/null
+# RISC-V
+
+## Bumblebee的中断
+
+### 1. CSR `mtvec`的功能
+
+Bumblebe内核遵循的标准 RISC-V 特权架构文档版本为:“特权架构文档版本 1.10” (riscv-privileged-v1.10.pdf),在这个版本中关于`mtvec`的变更是这样表述的:
+>"Optional vectored interrupt support has been added to the mtvec and stvec CSRs."
+
+也就是说支持`pc=BASE+4*CAUSE`的向量跳转的中断方式是可选的,而Bumblebee就恰好没有实现这个功能。
+
+### 2. CSR `mtvec`的MODE部分
+
+在riscv-privileged-v1.10.pdf文档中,`mtvect`MODE的合法值为:
+
+|Value|Name|Description|
+|:-:|:-:|:--|
+|0|Direct|All exceptions set pc to BASE.|
+|1|Vectored|Asynchronous interrupts set pc to BASE+4×cause.|
+|≥2| -| Reserved |
+
+但是Bumblebe的文档里却说:
+
+1. `mtvec.MODE != 6'b000011`则采用“默认中断模式”
+2. `mtvec.MODE == 6'b000011`则采用“ECLIC 中断模式”
+
+这里有两个问题:
+
+1. RISC-V官方文档里MODE只有2个bit, Bumblebe却占6个bit
+2. RISC-V官方文档里MODE有效取值只有1、2,但是Bumblebe却能取到3
+
+所以这是直接的违反RISC-V的定义?
+
+### 3. `mtvt`、`mtvt2`、`mtvec`
+
+相对于标准文档,Bumblebe添加了`mtvt`、`mtvt2`两个CSR。
+
+`mtvt` 存放中断向量表起始地址
+
+`mtvt2` 存放非向量(矢量)中断**共享**入口地址,这里有两点
+
+ 1. `mtvt2`的最低位`mtvt2.MTVT2EN == 0`,则所有非向量中断共享的入口地址由CSR寄存器`mtvec`的值(忽略最低2位的值)指定
+ 2. `mtvt2`的最低位`mtvt2.MTVT2EN == 1`,则所有非向量中断共享的入口地址由CSR寄存器`mtvt2`的值(忽略最低2位的值)指定
+
+ECLIC的每个中断源均可以设置成向量或者非向量处理(通过寄存器`clicintattr[i].shv`),如果中断被配置为向量处理模式,则该中断被处理器内核响应后,处理器直接跳入该中断的向量入口(Vector Table Entry)存储的目标地址(ECLIC中断向量表的基地址保存在`mtvt`中,通过这个寄存器查得)。
+
+*疑问:如果`mtvt2.MTVT2EN==0` 且在clicintattr[i]中配置成向量中断,就与riscv-privileged-v1.10.pdf中的"vectored interrupt"基本等价?只是一个是从`mtvt`中取出基址,一个是从`mtvec`中取出基址?*
\ No newline at end of file
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider copy-of="extension" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"/>
- <provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1161171236337370767" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
+ <provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="-1698227678259987722" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider copy-of="extension" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"/>
- <provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1161171236337370767" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
+ <provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="-1698227678259987722" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
}
```
+## USART转发优化版本
+
+```
+#include "main.h"
+#include "usart.h"
+#include "gpio.h"
+#include "stm32f1xx_hal.h"
+#include "cmsis_os.h"
+
+#define BOARD_STANDARD
+//#define BOARD_NBIOT
+
+// 如果要测试BOARD_STANDARD上的M6312,则必需:
+// 1. 5V/2A电源要供电
+// 2. PC4_M6312_PWR_KEY 要设置为推挽输入,高电平
+// 3. J10接线端子用跳线帽接到M6312上
+
+#define USART_RX_BUFSZ 32
+#define USART_TX_BUFSZ 32
+typedef struct {
+ uint8_t rxbuf[USART_RX_BUFSZ];
+ uint8_t txbuf[USART_TX_BUFSZ];
+ uint16_t rxwp;
+ uint16_t rxrp;
+ UART_HandleTypeDef *huart;
+ uint8_t rxdata;
+} DebugUsart_t;
+
+#define INIT_DEBUG_USART(_name, _huart) \
+ static DebugUsart_t _name = { \
+ .rxwp = 0, \
+ .rxrp = 0, \
+ .huart = &_huart, \
+ .rxdata = 0 \
+ };
+
+
+
+INIT_DEBUG_USART(__usart1, huart1)
+
+#if defined(BOARD_STANDARD)
+ INIT_DEBUG_USART(__usart2, huart2)
+ #define LED_GPIO_Port STANDARD_LED_GPIO_Port
+ #define LED_Pin STANDARD_LED_Pin
+ #define UsartA __usart1
+ #define UsartB __usart2
+#elif defined(BOARD_NBIOT)
+ INIT_DEBUG_USART(__usart3, huart3)
+ #define LED_GPIO_Port NB_LED_GPIO_Port
+ #define LED_Pin NB_LED_Pin
+ #define UsartA __usart1
+ #define UsartB __usart3
+#else
+ #error "must define board"
+#endif
+
+
+
+void InitUsartTransfer(){
+ if(HAL_OK != HAL_UART_Receive_IT(UsartA.huart, &UsartA.rxdata, 1)) {
+ Error_Handler();
+ }
+
+ if(HAL_OK != HAL_UART_Receive_IT(UsartB.huart, &UsartB.rxdata, 1)) {
+ Error_Handler();
+ }
+}
+
+
+int ReadUsartData(DebugUsart_t *data, uint8_t *ch) {
+ uint16_t rxwp = data->rxwp;
+ if(data->rxrp == rxwp) {
+ // empty
+ return -1;
+ }
+ *ch = data->rxbuf[data->rxrp];
+ data->rxrp = (data->rxrp + 1) % USART_RX_BUFSZ;
+ return 0;
+}
+
+
+void ReceiveUsartData(DebugUsart_t *data) {
+ if((data->rxwp + 1) % USART_RX_BUFSZ == data->rxrp) {
+ // full
+ goto end;
+ }
+
+ data->rxbuf[data->rxwp] = data->rxdata;
+
+ data->rxwp =(data->rxwp + 1) % USART_RX_BUFSZ;
+
+end:
+ if(HAL_OK != HAL_UART_Receive_IT(data->huart, &data->rxdata, 1)) {
+ //Error_Handler();
+ }
+}
+
+void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
+ if(huart == UsartA.huart) {
+ return ReceiveUsartData(&UsartA);
+ }
+
+ if(huart == UsartB.huart) {
+ return ReceiveUsartData(&UsartB);
+ }
+}
+
+
+int TransferData(DebugUsart_t *from ,DebugUsart_t *to) {
+ int cnt = 0;
+ while(cnt < USART_TX_BUFSZ) {
+ uint8_t ch;
+ if(0 != ReadUsartData(from, &ch)) {
+ break;
+ }
+ from->txbuf[cnt++] = ch;
+ }
+
+ if(cnt > 0) {
+ HAL_UART_Transmit(to->huart, from->txbuf, cnt, 0xFFFF);
+ }
+
+ return cnt;
+}
+
+void TransferTask(void *arg) {
+ while(1) {
+ // 以下两次调用不得直接放到if表达式中
+ int cnt1 = TransferData(&UsartA, &UsartB);
+ int cnt2 = TransferData(&UsartB, &UsartA);
+
+ if(cnt1 == 0 && cnt2 == 0) {
+ osDelay(1);
+ }
+ }
+}
+
+void LedTask(void *pdata) {
+ while(1) {
+ HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
+ osDelay(100);
+ }
+}
+
+osThreadDef(transferTask, TransferTask, osPriorityNormal, 0, 128);
+osThreadDef(ledTask, LedTask, osPriorityLow, 0, 64);
+
+void InitDebug() {
+ InitUsartTransfer();
+
+#if defined(BOARD_STANDARD)
+ HAL_GPIO_WritePin(M6312_PWRKEY_GPIO_Port, M6312_PWRKEY_Pin, GPIO_PIN_SET);
+#endif
+
+ osThreadId taskHandle;
+ taskHandle = osThreadCreate(osThread(transferTask), NULL);
+ if(taskHandle == NULL) {
+ Error_Handler();
+ }
+
+ taskHandle = osThreadCreate(osThread(ledTask), NULL);
+ if(taskHandle == NULL) {
+ Error_Handler();
+ }
+}
+
+
+#if 1
+#include <stdio.h>
+#ifdef __GNUC__
+ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
+#else
+ #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
+#endif
+PUTCHAR_PROTOTYPE
+{
+#if defined(BOARD_CHINA_MOBILE_NBIOT)
+ HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
+#endif
+ return ch;
+}
+#endif
+
+
+```
+
# USART1、USART2 DMA转发
```
__HAL_UART_CLEAR_IDLEFLAG(huart);
+ //软件清空空闲中断标志位
+ volatile tmp;
+ tmp =huart->SR;
+ tmp =huart->DR;
+
HAL_UART_DMAStop(huart);
data->len = USART_RX_BUFSZ - data->dmarx->Instance->CNDTR;
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
-
+ ReceiveUsartData(&huart2);
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
- ReceiveUsartData(&huart2);
/* USER CODE END USART2_IRQn 1 */
}