summaryrefslogtreecommitdiff
path: root/hw/bsp/ch32v10x/family.c
blob: aa709b0d83ca7bbdbe61020be4900ee5456707f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/* metadata:
   manufacturer: WCH
*/

#include <stdio.h>

// https://github.com/openwch/ch32v307/pull/90
// https://github.com/openwch/ch32v20x/pull/12
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif

#include "ch32v10x.h"
#include "ch32v10x_it.h"

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

#include "bsp/board_api.h"
#include "board.h"

__attribute__((interrupt)) __attribute__((used))
void USBHD_IRQHandler(void) {
  #if CFG_TUD_WCH_USBIP_USBFS
  tud_int_handler(0);
  #endif
}

__attribute__((interrupt)) __attribute__((used))
void USBWakeUp_IRQHandler(void) {
  #if CFG_TUD_WCH_USBIP_USBFS
  tud_int_handler(0);
  #endif
}

#if CFG_TUSB_OS == OPT_OS_NONE
volatile uint32_t system_ticks = 0;

__attribute__((interrupt)) __attribute__((used))
void SysTick_Handler(void) {
  SysTick->CNTL0 = SysTick->CNTL1 = SysTick->CNTL2 = SysTick->CNTL3 = 0;
  SysTick->CNTH0 = SysTick->CNTH1 = SysTick->CNTH2 = SysTick->CNTH3 = 0;
  system_ticks++;
}

static uint32_t SysTick_Config(uint32_t ticks) {
  NVIC_EnableIRQ(SysTicK_IRQn);
  SysTick->CTLR = 0;
  SysTick->CNTL0 = SysTick->CNTL1 = SysTick->CNTL2 = SysTick->CNTL3 = 0;
  SysTick->CNTH0 = SysTick->CNTH1 = SysTick->CNTH2 = SysTick->CNTH3 = 0;

  SysTick->CMPLR0 = (u8)(ticks & 0xFF);
  SysTick->CMPLR1 = (u8)(ticks >> 8);
  SysTick->CMPLR2 = (u8)(ticks >> 16);
  SysTick->CMPLR3 = (u8)(ticks >> 24);

  SysTick->CMPHR0 = SysTick->CMPHR1 = SysTick->CMPHR2 =   SysTick->CMPHR3 = 0;
  SysTick->CTLR = 1;
  return 0;
}

uint32_t tusb_time_millis_api(void) {
  return system_ticks;
}
#endif

void board_init(void) {
  /* Do NOT toggle the global interrupt enable here.
   * CH32V103 startup enters U-mode (mret with mstatus.MPP=0), so:
   *  - the SDK __disable_irq()/__enable_irq() write mstatus, which faults in U-mode;
   *  - writing CSR 0x800 (INTSYSCR) corrupts the QingKe V3 interrupt-mode config,
   *    which made the USB interrupt vector to a bad address (PC=0) and hang.
   * The startup already leaves interrupts correctly configured, and machine-mode
   * interrupts are globally enabled while running in U-mode regardless of mstatus.MIE. */

#if CFG_TUSB_OS == OPT_OS_NONE
  SysTick_Config(SystemCoreClock / 1000);
#endif

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

  EXTEN->EXTEN_CTR |= EXTEN_USBFS_IO_EN;
  uint8_t usb_div;
  switch (SystemCoreClock) {
    case 48000000: usb_div = RCC_USBCLKSource_PLLCLK_Div1; break;
    case 72000000: usb_div = RCC_USBCLKSource_PLLCLK_1Div5; break;
    default: TU_ASSERT(0,); break;
  }
  RCC_USBCLKConfig(usb_div);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBFS, ENABLE);

  #ifdef LED_PIN
  GPIO_InitTypeDef led_init = {
      .GPIO_Pin = LED_PIN,
      .GPIO_Mode = GPIO_Mode_Out_OD,
      .GPIO_Speed = GPIO_Speed_50MHz,
  };
  GPIO_Init(LED_PORT, &led_init);
  #endif

  #ifdef BUTTON_PIN
  GPIO_InitTypeDef button_init = {
      .GPIO_Pin = BUTTON_PIN,
      .GPIO_Mode = GPIO_Mode_IPU,
      .GPIO_Speed = GPIO_Speed_50MHz,
  };
  GPIO_Init(BUTTON_PORT, &button_init);
  #endif

  // UART TX is PA9
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  GPIO_InitTypeDef usart_init = {
    .GPIO_Pin = GPIO_Pin_9,
    .GPIO_Speed = GPIO_Speed_50MHz,
    .GPIO_Mode = GPIO_Mode_AF_PP,
  };
  GPIO_Init(GPIOA, &usart_init);

  USART_InitTypeDef usart = {
    .USART_BaudRate = 115200,
    .USART_WordLength = USART_WordLength_8b,
    .USART_StopBits = USART_StopBits_1,
    .USART_Parity = USART_Parity_No,
    .USART_Mode = USART_Mode_Tx,
    .USART_HardwareFlowControl = USART_HardwareFlowControl_None,
  };
  USART_Init(USART1, &usart);
  USART_Cmd(USART1, ENABLE);

  board_led_write(true);
}

void board_led_write(bool state) {
  GPIO_WriteBit(LED_PORT, LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON));
}

uint32_t board_button_read(void) {
  return BUTTON_STATE_ACTIVE == GPIO_ReadInputDataBit(BUTTON_PORT, BUTTON_PIN);
}

size_t board_get_unique_id(uint8_t id[], size_t max_len) {
  (void) max_len;
  volatile uint32_t* ch32_uuid = ((volatile uint32_t*) 0x1FFFF7E8UL);
  uint32_t* serial_32 = (uint32_t*) (uintptr_t) id;
  serial_32[0] = ch32_uuid[0];
  serial_32[1] = ch32_uuid[1];
  serial_32[2] = ch32_uuid[2];

  return 12;
}

int board_uart_read(uint8_t *buf, int len) {
  (void) buf;
  (void) len;
  return 0;
}

int board_uart_write(void const *buf, int len) {
  uint8_t const *p = (uint8_t const *) buf;
  int count = 0;
  while (count < len) {
    if (USART_GetFlagStatus(USART1, USART_FLAG_TC) != RESET) {
      USART_SendData(USART1, p[count]);
      count++;
    } else {
      break;
    }
  }
  return count;
}