Compiled and linked SAMD21x18 version successfully.

This commit is contained in:
Scott Shawcroft 2016-08-19 20:24:04 -07:00
parent f2a21a2489
commit a5f6cb3c57
12 changed files with 613 additions and 0 deletions

93
atmel-samd/Makefile Normal file
View File

@ -0,0 +1,93 @@
include ../py/mkenv.mk
CROSS = 0
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h
# include py core make definitions
include ../py/py.mk
ifeq ($(CROSS), 1)
CROSS_COMPILE = arm-none-eabi-
endif
BOSSAC := /Users/tannewt/ArduinoCore-samd/tools/bossac_osx
INC += -I.
INC += -I..
INC += -I../lib/mp-readline
INC += -I$(BUILD)
ifeq ($(CROSS), 1)
CFLAGS_CORTEX_M0 = -mthumb -mabi=aapcs-linux -mcpu=cortex-m0plus -fsingle-precision-constant -Wdouble-promotion -D__SAMD21G18A__
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M0) $(COPT)
else
CFLAGS = -m32 $(INC) -Wall -Werror -ansi -std=gnu99 $(COPT)
endif
#Debugging/Optimization
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -ggdb
else
CFLAGS += -Os -DNDEBUG
endif
LIBS =
ifeq ($(CROSS), 1)
LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
LDFLAGS = -Lasf/thirdparty/CMSIS/Lib/GCC/ -L $(dir $(LIBGCC_FILE_NAME)) -nostdlib -T samd21.ld -Map=$@.map --cref
LIBS += -larm_cortexM0l_math -lgcc
else
LD = gcc
LDFLAGS = -m32 -Wl,-Map=$@.map,--cref
endif
SRC_C = \
main.c \
uart_core.c \
lib/utils/stdout_helpers.c \
lib/utils/printf.c \
lib/utils/pyexec.c \
lib/libc/string0.c \
lib/mp-readline/readline.c \
$(BUILD)/_frozen_mpy.c \
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
ifeq ($(CROSS), 1)
all: $(BUILD)/firmware.bin
else
all: $(BUILD)/firmware.elf
endif
$(BUILD)/_frozen_mpy.c: frozentest.mpy $(BUILD)/genhdr/qstrdefs.generated.h
$(ECHO) "MISC freezing bytecode"
$(Q)../tools/mpy-tool.py -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h -mlongint-impl=none $< > $@
$(BUILD)/firmware.elf: $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(Q)$(SIZE) $@
$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
$(ECHO) "Create $@"
$(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $@
deploy: $(BUILD)/firmware.bin
$(ECHO) "Writing $< to the board"
$(BOSSAC) -u $<
# Run emulation build on a POSIX system with suitable terminal settings
run:
stty raw opost -echo
build/firmware.elf
@echo Resetting terminal...
# This sleep is useful to spot segfaults
sleep 1
reset
test: $(BUILD)/firmware.elf
$(Q)/bin/echo -e "print('hello world!', list(x+1 for x in range(10)), end='eol\\\\n')\\r\\n\\x04" | $(BUILD)/firmware.elf | tail -n2 | grep "^hello world! \\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\\]eol"
include ../py/mkrules.mk

17
atmel-samd/README.md Normal file
View File

@ -0,0 +1,17 @@
# SAMD21x18
This port is intended to be a full featured MicroPython port for SAMD21x18 based
development boards including the Arduino Zero, Adafruit Feather M0 and Adafruit
M0 BLE.
## Building for a SAMD21x18 MCU
The Makefile has the ability to build for a SAMD21x18, and by default
includes some start-up code and also enables a UART for communication. To build:
$ make CROSS=1
If you previously built the Linux version, you will need to first run
`make clean` to get rid of incompatible object files.
Deploying coming soon!

Binary file not shown.

125
atmel-samd/asf/readme.txt Normal file
View File

@ -0,0 +1,125 @@
1 - Introduction
----------------
The Atmel® Software Framework (ASF) is a collection of embedded software for Atmel flash MCU (www.atmel.com/asf).
» It simplifies the usage of microcontrollers, providing an abstraction to the hardware and high-value middlewares
» ASF is designed to be used for evaluation, prototyping, design and production phases
» ASF is integrated in the Atmel Studio IDE with a graphical user interface or available as standalone for GCC, IAR compilers
» ASF can be downloaded for free
ASF online documentation can be found here: http://asf.atmel.com
Supported devices:
» AVR UC3(Trade Mark) (http://www.atmel.com/products/microcontrollers/avr/32-bitavruc3.aspx)
» AVR XMEGA(Trade Mark) (http://www.atmel.com/products/microcontrollers/avr/avr_xmega.aspx)
» megaAVR(Trade Mark) (http://www.atmel.com/products/microcontrollers/avr/megaavr.aspx)
» SAM (http://www.atmel.com/products/microcontrollers/arm/default.aspx)
Each software module is provided with full source code, example of usage and
ready-to-use projects for the IAR EW and GNU GCC compilers.
This package is dedicated for IAR and GCC makefile users. AVR Studio 5 or Atmel Studio 6 users do not
need this package as the ASF is integrated in Atmel Studio.
The top folder organization is as follow:
- the avr32/ folder contains software modules(source code and projects) dedicated to AVR UC3 devices,
- the mega/ folder contains software modules(source code and projects) dedicated to megaAVR devices,
- the xmega/ folder contains software modules(source code and projects) dedicated to AVR XMEGA devices,
- the sam/ folder contains software modules(source code and projects) dedicated to SAM devices,
- the common/ folder contains software modules(source code and projects) shared by all AVR and SAM devices,
- the thirdparty/ folder contains software modules(source code and projects) from thirdparty providers for all Atmel devices.
The thirdparty/ folder is organized by thirdparty software module (i.e. one folder per thirdparty software module).
The avr32/, xmega/, mega/, sam/ and common/ folders are organized as follow:
- the drivers/ folder contains low-level software drivers for MCU on-chip resources (eg cpu, usart, adc drivers).
- the boards/ folder contains board-specific source code files.
- the utils/ folder contains files that are used by all other modules: it holds
several linker script files, IAR & GCC pre-compiled libraries of some ASF modules,
and C/C++ utility files with general usage defines, macros and functions.
- the services/ folder contains application-oriented pieces of software that are
not specific to boards nor chips (eg. FAT, TCP/IP stack, os, JPEG decoder).
For the common/ top folder, the services/ folder also contains chip-specific code.
- the components/ folder offers, for each supported hardware component, a software
interface to interact with the component (eg memories like SDRAM, SD card, or display)
- the applications/ contains hefty examples of applications using services and drivers.
2 - Documentation
--------------------------
ASF release notes, reference manual and getting started documents can be found on http://www.atmel.com/asf.
The ASF documentation can be found online on http://asf.atmel.com.
3 - Toolchain Header Files Update
---------------------------------
For 8-bit AVR users it is recommended to update the toolchain header files, a
description about how to do that is located in the readme.txt file under the
xmega/utils/header_files/ directory.
For AVR UC3 users using IAR, it is recommended to update the IAR header files.
To do that, unzip the avr32-headers.zip file (located under
the avr32/utils/header_files/ directory) to the IAR EWAVR32 installation folder
under "IAR installation folder"/Embedded Workbench x.y/avr32/inc/.
4 - IAR EW Users
----------------
Using an example of usage of the AVR UC3 GPIO driver module as an example, the
IAR projects are located under:
- avr32/drivers/gpio/peripheral_bus_example/at32uc3a0512_evk1000/iar/ for an EVK1100 board,
- avr32/drivers/gpio/peripheral_bus_example/at32uc3a0512_evk1105/iar/ for an EVK1105 board,
- avr32/drivers/gpio/peripheral_bus_example/at32uc3b0256_evk1101/iar/ for an EVK1101 board,
- avr32/drivers/gpio/peripheral_bus_example/at32uc3a3256_evk1104/iar/ for an EVK1104 board,
- avr32/drivers/gpio/peripheral_bus_example/at32uc3l064_stk600-rcuc3l0/iar/ for an STK600-RCUC3L0 setup,
- avr32/drivers/gpio/peripheral_bus_example/at32uc3c0512c_uc3c_ek/iar/ for an AT32UC3C-EK board,
- avr32/drivers/gpio/peripheral_bus_example/at32uc3l064_uc3l_ek/iar/ for an AT32UC3L-EK board.
Each iar folder contains a full IAR project with:
- an IAR EWAVR32 workspace file(avr32_drivers_gpio_peripheral_bus_example_uc3l_ek.eww: double-click on this file to open the whole project),
- an IAR EWAVR32 project file(avr32_drivers_gpio_peripheral_bus_example_uc3l_ek.ewp),
- an IAR EWAVR32 debug configuration file(avr32_drivers_gpio_peripheral_bus_example_uc3l_ek.ewd).
5 - AVR32 Studio Users
----------------------
It is possible to work with an unzipped ASF package from within AVR32 Studio: this
is described in the application note "AVR32769: How to Compile the standalone AVR
UC3 Software Framework in AVR32 Studio V2": http://www.atmel.com/dyn/resources/prod_documents/doc32115.pdf
6 - Offline documentation - Generating The HTML Documentation
-------------------------------------
All modules are fully documented using doxygen tags. Each project within the ASF
contains a doxyfile.doxygen (used to configure doxygen for a proper documentation
generation): to generate the html documentation, doxygen must be installed (see
http://www.doxygen.org/download.html) and the doxyfile.doxygen must be used as
the input configuration file for doxygen.
Using an example of usage of the AVR UC3 GPIO driver module as an example, for
an AT32UC3C-EK board, the associated doxyfile.doxygen file is under the
avr32/drivers/gpio/peripheral_bus_example/at32uc3c0512c_uc3c_ek/doxygen/ folder.
Run doxygen and use this doxyfile.doxygen as configuration file for doxygen.
Using the command line, this is done with the following command: doxygen doxyfile.doxygen
7 - Contact Information
-----------------------
For more info about Atmel MCU visit http://www.atmel.com/products/microcontrollers/default.aspx or contact support through the http://support.atmel.no/ site.
The support site also have a Frequently Asked Questions page with the most common questions.
ASF bugs or enhancement requests can be reported in the ASF Bug Tracker (http://asf.atmel.com/bugzilla/).
8 - Community Information
-------------------------
Users can find an ASF forum (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewforum&f=21) on AVRfreaks for AVR users or on http://www.at91.com/ for SAM users.
This forum can be used to have an open discussion about usage, development, bugs, fixes, improvements, etc.

BIN
atmel-samd/frozentest.mpy Normal file

Binary file not shown.

7
atmel-samd/frozentest.py Normal file
View File

@ -0,0 +1,7 @@
print('uPy')
print('a long string that is not interned')
print('a string that has unicode αβγ chars')
print(b'bytes 1234\x01')
print(123456789)
for i in range(4):
print(i)

167
atmel-samd/main.c Normal file
View File

@ -0,0 +1,167 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "py/nlr.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/gc.h"
#include "lib/utils/pyexec.h"
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
if (lex == NULL) {
printf("MemoryError: lexer could not allocate memory\n");
return;
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
qstr source_name = lex->source_name;
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
mp_call_function_0(module_fun);
nlr_pop();
} else {
// uncaught exception
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
}
}
static char *stack_top;
static char heap[2048];
int main(int argc, char **argv) {
int stack_dummy;
stack_top = (char*)&stack_dummy;
#if MICROPY_ENABLE_GC
gc_init(heap, heap + sizeof(heap));
#endif
mp_init();
#if MICROPY_REPL_EVENT_DRIVEN
pyexec_event_repl_init();
for (;;) {
int c = mp_hal_stdin_rx_chr();
if (pyexec_event_repl_process_char(c)) {
break;
}
}
#else
pyexec_friendly_repl();
#endif
//do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT);
//do_str("for i in range(10):\r\n print(i)", MP_PARSE_FILE_INPUT);
mp_deinit();
return 0;
}
void gc_collect(void) {
// WARNING: This gc_collect implementation doesn't try to get root
// pointers from CPU registers, and thus may function incorrectly.
void *dummy;
gc_collect_start();
gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t));
gc_collect_end();
gc_dump_info();
}
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
return NULL;
}
mp_import_stat_t mp_import_stat(const char *path) {
return MP_IMPORT_STAT_NO_EXIST;
}
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
void nlr_jump_fail(void *val) {
}
void NORETURN __fatal_error(const char *msg) {
while (1);
}
#ifndef NDEBUG
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
__fatal_error("Assertion failed");
}
#endif
#if MICROPY_MIN_USE_CORTEX_CPU
// this is a minimal IRQ and reset framework for any Cortex-M CPU
extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss;
void Reset_Handler(void) __attribute__((naked));
void Reset_Handler(void) {
// stack pointer set by bootloader
// copy .data section from flash to RAM
for (uint32_t *src = &_sidata, *dest = &_sdata; dest < &_edata;) {
*dest++ = *src++;
}
// zero out .bss section
for (uint32_t *dest = &_sbss; dest < &_ebss;) {
*dest++ = 0;
}
// jump to board initialisation
void _start(void);
_start();
}
void Default_Handler(void) {
for (;;) {
}
}
uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = {
(uint32_t)&_estack,
(uint32_t)&Reset_Handler,
(uint32_t)&Default_Handler, // NMI_Handler
(uint32_t)&Default_Handler, // HardFault_Handler
(uint32_t)&Default_Handler, // MemManage_Handler
(uint32_t)&Default_Handler, // BusFault_Handler
(uint32_t)&Default_Handler, // UsageFault_Handler
0,
0,
0,
0,
(uint32_t)&Default_Handler, // SVC_Handler
(uint32_t)&Default_Handler, // DebugMon_Handler
0,
(uint32_t)&Default_Handler, // PendSV_Handler
(uint32_t)&Default_Handler, // SysTick_Handler
};
void _start(void) {
// when we get here: stack is initialised, bss is clear, data is copied
// initialise the cpu and peripherals
#if MICROPY_MIN_USE_SAMD21_MCU
void samd21_init(void);
samd21_init();
#endif
// now that we have a basic system up and running we can call main
main(0, NULL);
// we must not return
for (;;) {
}
}
#endif
#if MICROPY_MIN_USE_SAMD21_MCU
void samd21_init(void) {
}
#endif

95
atmel-samd/mpconfigport.h Normal file
View File

@ -0,0 +1,95 @@
#include <stdint.h>
// options to control how Micro Python is built
#define MICROPY_QSTR_BYTES_IN_HASH (1)
#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool
#define MICROPY_ALLOC_PATH_MAX (256)
#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16)
#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_COMP_MODULE_CONST (0)
#define MICROPY_COMP_CONST (0)
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_GC_ALLOC_THRESHOLD (0)
#define MICROPY_REPL_EVENT_DRIVEN (0)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_ENABLE_DOC_STRING (0)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
#define MICROPY_PY_ASYNC_AWAIT (0)
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
#define MICROPY_PY_BUILTINS_ENUMERATE (0)
#define MICROPY_PY_BUILTINS_FILTER (0)
#define MICROPY_PY_BUILTINS_FROZENSET (0)
#define MICROPY_PY_BUILTINS_REVERSED (0)
#define MICROPY_PY_BUILTINS_SET (0)
#define MICROPY_PY_BUILTINS_SLICE (0)
#define MICROPY_PY_BUILTINS_PROPERTY (0)
#define MICROPY_PY_BUILTINS_MIN_MAX (0)
#define MICROPY_PY___FILE__ (0)
#define MICROPY_PY_GC (0)
#define MICROPY_PY_ARRAY (0)
#define MICROPY_PY_ATTRTUPLE (0)
#define MICROPY_PY_COLLECTIONS (0)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (0)
#define MICROPY_PY_STRUCT (0)
#define MICROPY_PY_SYS (0)
#define MICROPY_MODULE_FROZEN_MPY (1)
#define MICROPY_CPYTHON_COMPAT (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
// type definitions for the specific machine
#define BYTES_PER_WORD (4)
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
// This port is intended to be 32-bit, but unfortunately, int32_t for
// different targets may be defined in different ways - either as int
// or as long. This requires different printf formatting specifiers
// to print such value. So, we avoid int32_t and use int directly.
#define UINT_FMT "%u"
#define INT_FMT "%d"
typedef int mp_int_t; // must be pointer size
typedef unsigned mp_uint_t; // must be pointer size
typedef long mp_off_t;
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
#define MICROPY_PORT_BUILTINS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
// We need to provide a declaration/definition of alloca()
#include <alloca.h>
#define MICROPY_HW_BOARD_NAME "atmel-samd"
#define MICROPY_HW_MCU_NAME "samd21"
#ifdef __linux__
#define MICROPY_MIN_USE_STDOUT (1)
#endif
#ifdef __thumb__
#define MICROPY_MIN_USE_CORTEX_CPU (1)
#define MICROPY_MIN_USE_STM32_MCU (1)
#endif
#define MP_STATE_PORT MP_STATE_VM
#define MICROPY_PORT_ROOT_POINTERS \
const char *readline_hist[8];

2
atmel-samd/mphalport.h Normal file
View File

@ -0,0 +1,2 @@
static inline mp_uint_t mp_hal_ticks_ms(void) { return 0; }
static inline void mp_hal_set_interrupt_char(char c) {}

View File

@ -0,0 +1 @@
// qstrs specific to this port

62
atmel-samd/samd21.ld Normal file
View File

@ -0,0 +1,62 @@
/*
GNU linker script for SAMD21
*/
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000-0x2000 /* First 8KB used by bootloader */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x008000 /* 32 KiB */
}
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
/* define output sections */
SECTIONS
{
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* isr vector table */
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
_sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
} >FLASH
/* This is the initialized data section
The program executes knowing that the data is in the RAM
but the loader puts the initial values in the FLASH (inidata).
It is one task of the startup to copy the initial values from FLASH to RAM. */
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
} >RAM
/* Uninitialized data section */
.bss :
{
. = ALIGN(4);
_sbss = .; /* define a global symbol at bss start; used by startup code */
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end; used by startup code */
} >RAM
.ARM.attributes 0 : { *(.ARM.attributes) }
}

44
atmel-samd/uart_core.c Normal file
View File

@ -0,0 +1,44 @@
#include <unistd.h>
#include "py/mpconfig.h"
/*
* Core UART functions to implement for a port
*/
#if MICROPY_MIN_USE_STM32_MCU
typedef struct {
volatile uint32_t SR;
volatile uint32_t DR;
} periph_uart_t;
#define USART1 ((periph_uart_t*)0x40011000)
#endif
// Receive single character
int mp_hal_stdin_rx_chr(void) {
unsigned char c = 0;
#if MICROPY_MIN_USE_STDOUT
int r = read(0, &c, 1);
(void)r;
#elif MICROPY_MIN_USE_SAMD21_MCU
// wait for RXNE
while ((USART1->SR & (1 << 5)) == 0) {
}
c = USART1->DR;
#endif
return c;
}
// Send string of given length
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
#if MICROPY_MIN_USE_STDOUT
int r = write(1, str, len);
(void)r;
#elif MICROPY_MIN_USE_SAMD21_MCU
while (len--) {
// wait for TXE
while ((USART1->SR & (1 << 7)) == 0) {
}
USART1->DR = *str++;
}
#endif
}