Qinheng CH32V307VCT6 最小システムボード、全てのIOピンをピンアウト、Type-C×1をUSB2.0 Full-Speed OTGに接続、Flashチップ W25Q64(64 Mbit)をSPI2に接続、基板上にTL432電圧リファレンス1.25 V(実測1.246 V程度)をジャンパでPC3/AD13に接続可能、3.29 Vリファレンスは0 Ω抵抗でADC基準電圧VREFに接続可。
- MSP430F149最小システムボードを描き、オープンソース化:https://blog.zeruns.com/archives/713.html
- STM32F030C8T6最小システムボード+流水ランプ(回路図・PCB):https://blog.zeruns.com/archives/715.html
電子・マイコン技術交流グループ:2169025065
CH32V307VCT6概要
CH32Vシリーズは青稞32-bit RISC-Vを採用した産業用汎用マイコン。ハードウェアスタック領域、高速割り込みエントリを搭載し、標準と比べ割り込み応答を大幅高速化。CH32V303/305/307はV4Fコアを搭載し単精度浮動小数点命令セットをサポート、演算性能が向上。144 MHzゼロウェイト実行、8系統USART/UART、4系統モータタイマ、内蔵PHY付USB2.0 High-Speed(480 Mbps)、ギガビットEthernet MACなどを実装。
Qinheng公式製品紹介:https://url.zeruns.com/Hcd8p
サンプル無償申請(送料着払い):https://url.zeruns.com/x67TF
データシート:https://url.zeruns.com/hDzqw 抽出コード:cn7c
実物写真

回路図
Type-CコネクタのCC1/CC2は5.1 kΩでそれぞれプルダウン必要、並列プルダウンするとEmarkケーブル時に給電できません。LCSC公開プロジェクトは修正済み。
PCB
Top Layer:
TL432の1.25 V(実測1.246 V程度)はH8ジャンパでGPIO PC3/ADC13に接続可。
SW3はBOOT0/1ピン制御用、ブートモード設定(データシート2.5.2「オンチップメモリ及びブートモード」参照)、両方LOW(OFF)でOK。
H9ピンヘッダはWCH-Link書き込み用。
H5ピンヘッダはVBAT電源選択、バッテリ未装着時はジャンパで3.3 Vに、装着時はBATへ。
Bottom Layer:
外部VDDA/VREF不要の場合は裏面R11・R7に0 Ω実装、VREF+はR8/R9でLDO 3.3 VまたはTL432 3.29 Vリファレンスを選択、通常はR9実装で残りは空けておく。
部品購入先
- 0805抵抗サンプル帳:https://u.jd.com/DzK9k0O
- 0805コンデンササンプル帳:https://s.click.taobao.com/cTZzzDu
- CH32V307VCT6:https://s.click.taobao.com/5SjzzDu
- W25Q64JV:https://s.click.taobao.com/YAv6NEu
- TL432:https://s.click.taobao.com/t3AzzDu
- WCH-Link:https://s.click.taobao.com/m6KyzDu
- ピンヘッダ:https://u.jd.com/DbKUBDu
部品購入はLCSC推奨、優惠登録リンク:https://activity.szlcsc.com/invite/D03E5B9CEAAE70A4.html
基板搭載部品は全てLCSCで購入可能、オープンソースリンクのBOM表「すぐにLCSCで注文」ボタンでカートに一括インポート。
サンプルコード
完全プロジェクトダウンロード:https://url.zeruns.com/2q4tX 抽出コード:9527
LCSCオープンソースプロジェクト:https://url.zeruns.com/Avda8
サンプルはHarmony LiteOS-M採用、3タスク作成:LED2を500 ms周期、LED3を1 s周期、LED4を2 s周期で点滅(上記GIFは1.5倍速)。
プロジェクトはMounRiver Studioで開く。
main.c:
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "debug.h"
#include "los_tick.h"
#include "los_task.h"
#include "los_config.h"
#include "los_interrupt.h"
#include "los_debug.h"
#include "los_compiler.h"
/* Global define */
``````c
/* グローバル変数 */
__attribute__((aligned (8))) UINT8 g_memStart[LOSCFG_SYS_HEAP_SIZE];
UINT32 g_VlaueSp=0;
u8 i = 0,j=0,k=0;
/*********************************************************************
* @fn taskSampleEntry3
*
* @brief taskSampleEntry3 プログラム.
*
* @return none
*/
VOID taskSampleEntry3(VOID)
{
while(1) {
LOS_TaskDelay(2000);
printf("taskSampleEntry3 running,task3 SP:%08x\n",__get_SP());
GPIO_WriteBit(GPIOD, GPIO_Pin_13, (k == 0) ? (k = Bit_SET) : (k = Bit_RESET));
}
}
/*********************************************************************
* @fn taskSampleEntry2
*
* @brief taskSampleEntry2 プログラム.
*
* @return none
*/
VOID taskSampleEntry2(VOID)
{
while(1) {
LOS_TaskDelay(1000);
printf("taskSampleEntry2 running,task2 SP:%08x\n",__get_SP());
GPIO_WriteBit(GPIOD, GPIO_Pin_12, (j == 0) ? (j = Bit_SET) : (j = Bit_RESET));
}
}
/*********************************************************************
* @fn taskSampleEntry1
*
* @brief taskSampleEntry1 プログラム.
*
* @return none
*/
VOID taskSampleEntry1(VOID)
{
while(1) {
LOS_TaskDelay(500);
printf("taskSampleEntry1 running,task1 SP:%08x\n",__get_SP());
GPIO_WriteBit(GPIOD, GPIO_Pin_11, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET));
}
}
// https://blog.zeruns.com
/*********************************************************************
* @fn EXTI0_INT_INIT
*
* @brief EXTI0 コレクションを初期化.
*
* @return none
*/
void EXTI0_INT_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure={0};
EXTI_InitTypeDef EXTI_InitStructure={0};
NVIC_InitTypeDef NVIC_InitStructure={0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOA ----> EXTI_Line0 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void GPIO_INIT(void) {
GPIO_InitTypeDef GPIO_InitStructure = { 0 };
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11|GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
/*********************************************************************
* @fn taskSample
*
* @brief taskSample プログラム.
*
* @return none
*/
UINT32 taskSample(VOID) {
UINT32 uwRet;
UINT32 taskID1, taskID2, taskID3;
TSK_INIT_PARAM_S stTask = { 0 };
stTask.pfnTaskEntry = (TSK_ENTRY_FUNC) taskSampleEntry1;
stTask.uwStackSize = 0X500;
stTask.pcName = "taskSampleEntry1";
stTask.usTaskPrio = 6;/* 高優先度 */
uwRet = LOS_TaskCreate(&taskID1, &stTask);
if (uwRet != LOS_OK) {
printf("create task1 failed\n");
}
stTask.pfnTaskEntry = (TSK_ENTRY_FUNC) taskSampleEntry2;
stTask.uwStackSize = 0X500;
stTask.pcName = "taskSampleEntry2";
stTask.usTaskPrio = 7;/* 低優先度 */
uwRet = LOS_TaskCreate(&taskID2, &stTask);
if (uwRet != LOS_OK) {
printf("create task2 failed\n");
}
stTask.pfnTaskEntry = (TSK_ENTRY_FUNC) taskSampleEntry3;
stTask.uwStackSize = 0X500;
stTask.pcName = "taskSampleEntry3";
stTask.usTaskPrio = 7;/* 低優先度 */
uwRet = LOS_TaskCreate(&taskID3, &stTask);
if (uwRet != LOS_OK) {
printf("create task3 failed\n");
}
// https://blog.vpszj.cn
EXTI0_INT_INIT();
return LOS_OK;
}
/*********************************************************************
* @fn main
*
* @brief メインプログラム.
*
* @return none
*/
LITE_OS_SEC_TEXT_INIT int main(void)
{
unsigned int ret;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
SystemCoreClockUpdate();
Delay_Init();
GPIO_INIT();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n",SystemCoreClock);
printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
ret = LOS_KernelInit();
taskSample();
if (ret == LOS_OK)
{
LOS_Start();
}
GPIO_WriteBit(GPIOC, GPIO_Pin_1,RESET);
while (1) {
__asm volatile("nop");
}
}
/*********************************************************************
* @fn EXTI0_IRQHandler
*
* @brief この関数は EXTI0 ハンドラを処理.
*
* @return none
*/
void EXTI0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void EXTI0_IRQHandler(void)
{
/* 割込みスタックは元の main 設定値を使用し、割込みスタックとスレッドスタックを分離することで、
* スレッドが割込みに遷移しても、割込み関数がネスト深度が大きくてもスレッドスタックが溢れない。
* ただし現状の方式では、スレッドが割込みに入る際、コンパイラが保存する16個の caller レジスタは
* 依然としてスレッドスタックに積まれる。caller レジスタを割込みスタックに積みたい場合は、
* 割込み関数の入口・出口でアセンブリを使用し、途中でユーザ割込み処理関数を呼び出せばよい。
* los_exc.S の ipq_entry 例を参照。
* */
GET_INT_SP();
HalIntEnter();
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
{
g_VlaueSp= __get_SP();
printf("Run at EXTI:");
printf("interruption sp:%08x\r\n",g_VlaueSp);
HalDisplayTaskInfo();
EXTI_ClearITPendingBit(EXTI_Line0); /* フラグクリア */
}
HalIntExit();
FREE_INT_SP();
}
その他のオープンソースプロジェクトおすすめ
- SY8205同期降圧可調DCDC電源モジュール(回路図とPCB):https://blog.zeruns.com/archives/717.html
- 2011年全国電子競技課題-スイッチング電源モジュール並列給電システム:https://blog.zeruns.com/archives/718.html
- 2007年電源課題:30~36V可調昇圧DCDCモジュール(UC3843):https://oshwhub.com/zeruns/36v-sheng-ya-dcdc-mo-kuai-uc3842
- STC12C5A60S2最小システムボード/51マイコン温度表示と温度制御ファン:https://blog.zeruns.com/archives/721.html
- U8g2グラフィックライブラリを移植済みのSTM32F407標準ライブラリプロジェクトテンプレート:https://blog.zeruns.com/archives/722.html
おすすめ記事
- コストパフォーマンスに優れた安価なVPS/クラウドサーバーおすすめ: https://blog.vpszj.cn/archives/41.html
- 個人ブログの構築方法:https://blog.zeruns.com/archives/218.html
- マインクラフトサーバー構築チュートリアル:https://blog.zeruns.com/tag/mc/
- STM32でSHT3xシリーズ温湿度センサーを読み取る:https://blog.zeruns.com/archives/700.html
- Keilの代わりにVSCodeでSTM32と51マイコン開発を行う:https://blog.zeruns.com/archives/690.html
- 雨雲 アメリカ高防護専用サーバー 性能レビュー、8コア16G 50Mbps 200G防御:https://blog.vpszj.cn/archives/1603.html
- 特語雲 湖北十堰 高防護VPS 性能評価、4コア8G 10Mbps 100G防御:https://blog.vpszj.cn/archives/1523.html






