first commit
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
.pio
|
||||
.vscode
|
||||
*.elf
|
||||
*.hex
|
||||
*.lst
|
||||
*.bin
|
||||
*.map
|
||||
.clangd
|
||||
.cache
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "ch32v003fun"]
|
||||
path = ch32v003fun
|
||||
url = https://github.com/cnlohr/ch32v003fun.git
|
||||
13
Makefile
Normal file
13
Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
all : flash
|
||||
|
||||
TARGET:=ch32ext
|
||||
CH32V003FUN=./ch32v003fun/ch32v003fun
|
||||
MINICHLINK=./ch32v003fun/minichlink
|
||||
PREFIX=riscv64-elf
|
||||
LINKER_SCRIPT=./ch32ext.ld
|
||||
# CFLAGS += -march=rv32ec_zicsr
|
||||
|
||||
include $(CH32V003FUN)/ch32v003fun.mk
|
||||
|
||||
flash : cv_flash
|
||||
clean : cv_clean
|
||||
157
ch32ext.c
Normal file
157
ch32ext.c
Normal file
@@ -0,0 +1,157 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ch32v003fun.h"
|
||||
#include "simple_eeprom.h"
|
||||
#include "state_manager.h"
|
||||
|
||||
#define RS485_DIR (1 << 0) // RS485 direction control
|
||||
#define SRCLR (1 << 1) // Shift register clear (active low)
|
||||
#define SRCLK (1 << 2) // Shift register clock
|
||||
#define RCLK (1 << 3) // Storage register clock
|
||||
#define SER (1 << 4) // Serial data input
|
||||
|
||||
// "protocol" defines
|
||||
#define BOARD_ADDRESS 0x01
|
||||
#define CMD_SET_OUTPUTS 0x01
|
||||
#define BROADCAST_ADDR 0xFF
|
||||
|
||||
// "protocol" states
|
||||
enum rx_states {
|
||||
STATE_ADDR,
|
||||
STATE_IGNORE,
|
||||
STATE_CMD,
|
||||
STATE_DATA_HIGH,
|
||||
STATE_DATA_LOW
|
||||
};
|
||||
|
||||
void setup_uart(int uartBRR) {
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC |
|
||||
RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO;
|
||||
|
||||
// RS485_DIR as output, set recv mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 0));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 0);
|
||||
GPIOC->BCR = RS485_DIR;
|
||||
|
||||
// UART pins (PD5=TX, PD6=RX)
|
||||
GPIOD->CFGLR &= ~(0xf << (4 * 5) | 0xf << (4 * 6));
|
||||
GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 5);
|
||||
GPIOD->CFGLR |= GPIO_CNF_IN_FLOATING << (4 * 6);
|
||||
|
||||
// 115200 8N1
|
||||
USART1->CTLR1 =
|
||||
USART_WordLength_8b | USART_Parity_No | USART_Mode_Tx | USART_Mode_Rx;
|
||||
USART1->CTLR2 = USART_StopBits_1;
|
||||
USART1->CTLR3 = USART_HardwareFlowControl_None;
|
||||
USART1->BRR = uartBRR;
|
||||
USART1->CTLR1 |= CTLR1_UE_Set;
|
||||
}
|
||||
|
||||
void setup_gpio(void) {
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC;
|
||||
|
||||
// PC1-PC4 as out
|
||||
for (int pin = 1; pin <= 4; pin++) {
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * pin));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * pin);
|
||||
}
|
||||
|
||||
GPIOC->BCR = SRCLR | SRCLK | RCLK | SER;
|
||||
}
|
||||
|
||||
void shift_out(uint16_t data) {
|
||||
GPIOC->BCR = RCLK;
|
||||
|
||||
// reorder
|
||||
uint16_t ordered_data = ((data & 0xFF00) >> 8) | // 1st reg (Q0-Q7)
|
||||
((data & 0x00FF) << 8); // 2nd reg (Q8-Q15)
|
||||
|
||||
// shift out 16 bits, MSB 1st
|
||||
for (int8_t i = 15; i >= 0; i--) {
|
||||
GPIOC->BCR = SRCLK;
|
||||
if (ordered_data & (1 << i)) {
|
||||
GPIOC->BSHR = SER;
|
||||
} else {
|
||||
GPIOC->BCR = SER;
|
||||
}
|
||||
GPIOC->BSHR = SRCLK;
|
||||
}
|
||||
|
||||
// latch
|
||||
GPIOC->BSHR = RCLK;
|
||||
GPIOC->BCR = RCLK;
|
||||
}
|
||||
|
||||
uint8_t uart_receive_byte(void) {
|
||||
while (!(USART1->STATR & USART_FLAG_RXNE));
|
||||
return USART1->DATAR & 0xFF;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
SystemInit();
|
||||
setup_gpio();
|
||||
setup_uart(UART_BRR);
|
||||
|
||||
// reset shift reg
|
||||
GPIOC->BSHR = SRCLR;
|
||||
GPIOC->BSHR = RCLK; // rising edge on RCLK
|
||||
GPIOC->BCR = RCLK;
|
||||
|
||||
// load last state
|
||||
uint16_t current_state = load_state();
|
||||
printf("Loaded state: %04x\n", current_state);
|
||||
shift_out(current_state);
|
||||
|
||||
uint8_t rx_state = STATE_ADDR;
|
||||
uint8_t addr, cmd;
|
||||
uint16_t data = 0;
|
||||
uint8_t bytes_to_ignore = 0;
|
||||
|
||||
printf("SystemClk:%d\r\n", FUNCONF_SYSTEM_CORE_CLOCK);
|
||||
printf("ChipID:%08lx\r\n", *(uint32_t *)0x1FFFF7C4);
|
||||
|
||||
while (1) {
|
||||
uint8_t byte = uart_receive_byte();
|
||||
|
||||
switch (rx_state) {
|
||||
case STATE_ADDR:
|
||||
addr = byte;
|
||||
if (addr == BOARD_ADDRESS || addr == BROADCAST_ADDR) {
|
||||
rx_state = STATE_CMD;
|
||||
} else {
|
||||
// crc??))
|
||||
bytes_to_ignore = 3; // skip cmd + data_high + data_low
|
||||
rx_state = STATE_IGNORE;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_IGNORE:
|
||||
bytes_to_ignore--;
|
||||
if (bytes_to_ignore == 0) {
|
||||
rx_state = STATE_ADDR;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_CMD:
|
||||
cmd = byte;
|
||||
rx_state = STATE_DATA_HIGH;
|
||||
break;
|
||||
|
||||
case STATE_DATA_HIGH:
|
||||
data = (uint16_t)byte << 8;
|
||||
rx_state = STATE_DATA_LOW;
|
||||
break;
|
||||
|
||||
case STATE_DATA_LOW:
|
||||
data |= byte;
|
||||
if (cmd == CMD_SET_OUTPUTS) {
|
||||
printf("Set outputs: 0x%04X\n", data);
|
||||
shift_out(data);
|
||||
save_state(data);
|
||||
dump_eeprom();
|
||||
}
|
||||
rx_state = STATE_ADDR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
151
ch32ext.ld
Normal file
151
ch32ext.ld
Normal file
@@ -0,0 +1,151 @@
|
||||
ENTRY(InterruptVector)
|
||||
|
||||
MEMORY {
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16K /* 16KB FLASH */
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2K /* 2KB RAM */
|
||||
}
|
||||
|
||||
SECTIONS {
|
||||
/* Initialization code section */
|
||||
.init : {
|
||||
_sinit = .;
|
||||
. = ALIGN(4);
|
||||
KEEP(*(SORT_NONE(.init)))
|
||||
. = ALIGN(4);
|
||||
_einit = .;
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
/* Main code section */
|
||||
.text : {
|
||||
. = ALIGN(4);
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
. = ALIGN(4);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.fini : {
|
||||
KEEP(*(SORT_NONE(.fini)))
|
||||
. = ALIGN(4);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
PROVIDE(_etext = .);
|
||||
PROVIDE(_eitcm = .);
|
||||
|
||||
.preinit_array : {
|
||||
PROVIDE_HIDDEN(__preinit_array_start = .);
|
||||
KEEP(*(.preinit_array))
|
||||
PROVIDE_HIDDEN(__preinit_array_end = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.init_array : {
|
||||
PROVIDE_HIDDEN(__init_array_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors))
|
||||
PROVIDE_HIDDEN(__init_array_end = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.fini_array : {
|
||||
PROVIDE_HIDDEN(__fini_array_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP(*(.fini_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .dtors))
|
||||
PROVIDE_HIDDEN(__fini_array_end = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.ctors : {
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP(*crtbegin.o(.ctors))
|
||||
KEEP(*crtbegin?.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP(*(EXCLUDE_FILE(*crtend.o *crtend?.o) .ctors))
|
||||
KEEP(*(SORT(.ctors.*)))
|
||||
KEEP(*(.ctors))
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.dtors : {
|
||||
KEEP(*crtbegin.o(.dtors))
|
||||
KEEP(*crtbegin?.o(.dtors))
|
||||
KEEP(*(EXCLUDE_FILE(*crtend.o *crtend?.o) .dtors))
|
||||
KEEP(*(SORT(.dtors.*)))
|
||||
KEEP(*(.dtors))
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.dalign : {
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data_vma = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
.dlalign : {
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data_lma = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.data : {
|
||||
. = ALIGN(4);
|
||||
*(.gnu.linkonce.r.*)
|
||||
*(.data .data.*)
|
||||
*(.gnu.linkonce.d.*)
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__global_pointer$ = . + 0x800);
|
||||
*(.sdata .sdata.*)
|
||||
*(.sdata2*)
|
||||
*(.gnu.linkonce.s.*)
|
||||
. = ALIGN(8);
|
||||
*(.srodata.cst16)
|
||||
*(.srodata.cst8)
|
||||
*(.srodata.cst4)
|
||||
*(.srodata.cst2)
|
||||
*(.srodata .srodata.*)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_edata = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
.bss : {
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_sbss = .);
|
||||
*(.sbss*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.bss*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON*)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_ebss = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
PROVIDE(_end = _ebss);
|
||||
PROVIDE(end = .);
|
||||
PROVIDE(_eusrstack = ORIGIN(RAM) + LENGTH(RAM));
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.note .note.*)
|
||||
*(.eh_frame .eh_frame.*)
|
||||
*(.comment .comment.*)
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
*(.ARM.exidx*)
|
||||
}
|
||||
|
||||
/* EEPROM section - reserves exactly one 64-byte page */
|
||||
.eeprom : {
|
||||
. = ALIGN(64);
|
||||
_reserved_nv_start = .;
|
||||
KEEP(*(.eeprom));
|
||||
. = _reserved_nv_start + 64;
|
||||
_reserved_nv_end = .;
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
PROVIDE(_reserved_nv_start = _reserved_nv_start);
|
||||
PROVIDE(_reserved_nv_end = _reserved_nv_end);
|
||||
}
|
||||
1
ch32v003fun
Submodule
1
ch32v003fun
Submodule
Submodule ch32v003fun added at e4b70191d4
24
funconfig.h
Normal file
24
funconfig.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef _FUNCONFIG_H
|
||||
#define _FUNCONFIG_H
|
||||
|
||||
// #define FUNCONF_USE_PLL 1 // Use built-in 2x PLL
|
||||
// #define FUNCONF_USE_HSI 1 // Use HSI Internal Oscillator
|
||||
// #define FUNCONF_USE_HSE 0 // Use External Oscillator
|
||||
// #define FUNCONF_HSITRIM 0x10 // Use factory calibration on HSI Trim.
|
||||
// #define FUNCONF_SYSTEM_CORE_CLOCK 48000000 // Computed Clock in Hz (Default only for 003, other chips have other defaults)
|
||||
// #define FUNCONF_HSE_BYPASS 0 // Use HSE Bypass feature (for oscillator input)
|
||||
// #define FUNCONF_USE_CLK_SEC 1 // Use clock security system, enabled by default
|
||||
#define FUNCONF_USE_DEBUGPRINTF 1
|
||||
// #define FUNCONF_USE_UARTPRINTF 0
|
||||
// #define FUNCONF_NULL_PRINTF 0 // Have printf but direct it "nowhere"
|
||||
#define FUNCONF_SYSTICK_USE_HCLK 1 // Should systick be at 48 MHz or 6MHz?
|
||||
// #define FUNCONF_TINYVECTOR 0 // If enabled, Does not allow normal interrupts.
|
||||
// #define FUNCONF_UART_PRINTF_BAUD 115200 // Only used if FUNCONF_USE_UARTPRINTF is set.
|
||||
// #define FUNCONF_DEBUGPRINTF_TIMEOUT 160000 // Arbitrary time units
|
||||
// #define FUNCONF_ENABLE_HPE 1 // Enable hardware interrupt stack. Very good on QingKeV4, i.e. x035, v10x, v20x, v30x, but questionable on 003.
|
||||
// #define FUNCONF_USE_5V_VDD 0 // Enable this if you plan to use your part at 5V - affects USB and PD configration on the x035.
|
||||
// #define FUNCONF_DEBUG 0 // Log fatal errors with "printf"
|
||||
|
||||
#define CH32V003 1
|
||||
|
||||
#endif
|
||||
150
simple_eeprom.h
Normal file
150
simple_eeprom.h
Normal file
@@ -0,0 +1,150 @@
|
||||
#ifndef __SIMPLE_EEPROM_H
|
||||
#define __SIMPLE_EEPROM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ch32v003fun.h"
|
||||
|
||||
// config
|
||||
#define EEPROM_PAGE_SIZE 64 // size in bytes
|
||||
#define EEPROM_HALFWORD_SIZE 2 // size of halfword in bytes
|
||||
#define EEPROM_MAX_ENTRIES (EEPROM_PAGE_SIZE / EEPROM_HALFWORD_SIZE)
|
||||
|
||||
typedef enum {
|
||||
EEPROM_OK = 0,
|
||||
EEPROM_ERROR_WRITE,
|
||||
EEPROM_ERROR_ERASE,
|
||||
EEPROM_ERROR_VERIFY
|
||||
} eeprom_status_t;
|
||||
|
||||
// ######## internal variables
|
||||
// import from .ld, halal by
|
||||
// https://sourceware.org/binutils/docs/ld/Source-Code-Reference.html
|
||||
extern char _reserved_nv_start[];
|
||||
extern char _reserved_nv_end[];
|
||||
|
||||
#define EEPROM_BASE (FLASH_BASE + (uint32_t)(uintptr_t)_reserved_nv_start)
|
||||
|
||||
static void flash_unlock(void) {
|
||||
if (FLASH->CTLR & 0x80) {
|
||||
FLASH->KEYR = FLASH_KEY1;
|
||||
FLASH->KEYR = FLASH_KEY2;
|
||||
}
|
||||
}
|
||||
|
||||
static void flash_lock(void) { FLASH->CTLR = 0x80; }
|
||||
|
||||
static void flash_unlock_fast_mode(void) {
|
||||
if (FLASH->CTLR & 0x8000) {
|
||||
FLASH->MODEKEYR = FLASH_KEY1;
|
||||
FLASH->MODEKEYR = FLASH_KEY2;
|
||||
}
|
||||
}
|
||||
|
||||
static void flash_wait_busy(void) { while (FLASH->STATR & FLASH_STATR_BSY); }
|
||||
|
||||
static eeprom_status_t flash_erase_page(void) {
|
||||
uint16_t *page_addr = (uint16_t *)EEPROM_BASE;
|
||||
|
||||
flash_unlock_fast_mode();
|
||||
flash_wait_busy();
|
||||
|
||||
// erase page
|
||||
FLASH->CTLR = CR_PAGE_ER;
|
||||
FLASH->ADDR = (uint32_t)page_addr;
|
||||
FLASH->CTLR = CR_STRT_Set | CR_PAGE_ER;
|
||||
flash_wait_busy();
|
||||
|
||||
// verify erase
|
||||
for (int i = 0; i < EEPROM_MAX_ENTRIES; i++) {
|
||||
if (page_addr[i] != 0xFFFF) {
|
||||
return EEPROM_ERROR_ERASE;
|
||||
}
|
||||
}
|
||||
|
||||
// disable fast mode
|
||||
FLASH->CTLR = 0x8000;
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
static int find_next_free_slot(void) {
|
||||
uint16_t *word = (uint16_t *)EEPROM_BASE;
|
||||
for (int i = 0; i < EEPROM_MAX_ENTRIES; i++) {
|
||||
if (word[i] == 0xFFFF) { // look for erased entries
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return EEPROM_MAX_ENTRIES;
|
||||
}
|
||||
|
||||
eeprom_status_t eeprom_write(uint16_t data) {
|
||||
flash_unlock();
|
||||
|
||||
// find next available slot
|
||||
int slot = find_next_free_slot();
|
||||
uint16_t *word = (uint16_t *)EEPROM_BASE + slot;
|
||||
|
||||
// page is full, erase it
|
||||
if (slot >= EEPROM_MAX_ENTRIES) {
|
||||
eeprom_status_t status = flash_erase_page();
|
||||
if (status != EEPROM_OK) {
|
||||
flash_lock();
|
||||
return status;
|
||||
}
|
||||
word = (uint16_t *)EEPROM_BASE; // reset to start of page
|
||||
}
|
||||
|
||||
// write data
|
||||
FLASH->CTLR = CR_PG_Set;
|
||||
*word = data; // write full 16-bit value
|
||||
flash_wait_busy();
|
||||
|
||||
// verify write
|
||||
if (*word != data) {
|
||||
flash_lock();
|
||||
return EEPROM_ERROR_VERIFY;
|
||||
}
|
||||
|
||||
flash_lock();
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
uint16_t eeprom_read(void) {
|
||||
uint16_t *word =
|
||||
(uint16_t *)(EEPROM_BASE + EEPROM_PAGE_SIZE - EEPROM_HALFWORD_SIZE);
|
||||
|
||||
// scan back from the end until we find a non-erased value
|
||||
for (int i = 0; i < EEPROM_MAX_ENTRIES; i++) {
|
||||
uint16_t val = *word;
|
||||
if (val != 0xFFFF) {
|
||||
return val;
|
||||
}
|
||||
word--;
|
||||
}
|
||||
|
||||
return 0xFFFF; // nothing found
|
||||
}
|
||||
|
||||
eeprom_status_t eeprom_init(void) {
|
||||
uint16_t *page = (uint16_t *)EEPROM_BASE;
|
||||
|
||||
// check empty/partial page
|
||||
bool needs_erase = true;
|
||||
for (int i = 0; i < EEPROM_MAX_ENTRIES; i++) {
|
||||
if (page[i] != 0xFFFF) {
|
||||
needs_erase = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_erase) {
|
||||
return flash_erase_page();
|
||||
}
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
eeprom_status_t eeprom_wipe(void) { return flash_erase_page(); }
|
||||
|
||||
#endif
|
||||
24
state_manager.h
Normal file
24
state_manager.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef __STATE_MANAGER_H
|
||||
#define __STATE_MANAGER_H
|
||||
|
||||
#include "simple_eeprom.h"
|
||||
|
||||
#define DEFAULT_STATE 0x0000
|
||||
|
||||
void save_state(uint16_t state) { eeprom_write(state); }
|
||||
|
||||
uint16_t load_state(void) { return eeprom_read(); }
|
||||
|
||||
void dump_eeprom(void) {
|
||||
uint16_t *word = (uint16_t *)(EEPROM_BASE);
|
||||
printf("EEPROM contents:");
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint16_t val = word[i];
|
||||
// if (!(val & 0x8000)) {
|
||||
printf(" %04X", val);
|
||||
// }
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user