This commit is contained in:
blmorris 2014-07-21 12:50:10 -04:00
commit 721d6240c9
64 changed files with 9123 additions and 280 deletions

View File

@ -36,6 +36,8 @@
#include "runtime0.h"
#include "runtime.h"
#include "builtin.h"
#include "stream.h"
#include "pfenv.h"
#if MICROPY_PY_BUILTINS_FLOAT
#include <math.h>
@ -424,13 +426,36 @@ STATIC mp_obj_t mp_builtin_print(uint n_args, const mp_obj_t *args, mp_map_t *kw
if (end_elem != NULL && end_elem->value != mp_const_none) {
end_data = mp_obj_str_get_data(end_elem->value, &end_len);
}
#if MICROPY_PY_IO
mp_obj_t stream_obj = &mp_sys_stdout_obj;
mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
if (file_elem != NULL && file_elem->value != mp_const_none) {
stream_obj = file_elem->value;
}
pfenv_t pfenv;
pfenv.data = stream_obj;
pfenv.print_strn = (void (*)(void *, const char *, unsigned int))mp_stream_write;
#endif
for (int i = 0; i < n_args; i++) {
if (i > 0) {
#if MICROPY_PY_IO
mp_stream_write(stream_obj, sep_data, sep_len);
#else
printf("%.*s", sep_len, sep_data);
#endif
}
#if MICROPY_PY_IO
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[i], PRINT_STR);
#else
mp_obj_print(args[i], PRINT_STR);
#endif
}
#if MICROPY_PY_IO
mp_stream_write(stream_obj, end_data, end_len);
#else
printf("%.*s", end_len, end_data);
#endif
return mp_const_none;
}

View File

@ -81,5 +81,10 @@ extern const mp_obj_module_t mp_module_struct;
extern const mp_obj_module_t mp_module_sys;
extern const mp_obj_module_t mp_module_gc;
struct _dummy_t;
extern struct _dummy_t mp_sys_stdin_obj;
extern struct _dummy_t mp_sys_stdout_obj;
extern struct _dummy_t mp_sys_stderr_obj;
// extmod modules
extern const mp_obj_module_t mp_module_uctypes;

View File

@ -315,7 +315,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
uint reg_src = get_arg_reg(emit, op_str, pn_args[1], 15);
asm_thumb_mov_reg_reg(emit->as, reg_dest, reg_src);
} else if (strcmp(op_str, "and") == 0) {
} else if (strcmp(op_str, "and_") == 0) {
op_code = ASM_THUMB_FORMAT_4_AND;
uint reg_dest, reg_src;
op_format_4:
@ -323,7 +323,6 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
reg_src = get_arg_reg(emit, op_str, pn_args[1], 7);
asm_thumb_format_4(emit->as, op_code, reg_dest, reg_src);
// TODO probably uses less ROM if these ops are in a lookup table
} else if (strcmp(op_str, "and") == 0) { op_code = ASM_THUMB_FORMAT_4_AND; goto op_format_4;
} else if (strcmp(op_str, "eor") == 0) { op_code = ASM_THUMB_FORMAT_4_EOR; goto op_format_4;
} else if (strcmp(op_str, "lsl") == 0) { op_code = ASM_THUMB_FORMAT_4_LSL; goto op_format_4;
} else if (strcmp(op_str, "lsr") == 0) { op_code = ASM_THUMB_FORMAT_4_LSR; goto op_format_4;

View File

@ -75,7 +75,7 @@ int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char s
if (buf_size < 7) {
// Smallest exp notion is -9e+99 which is 6 chars plus terminating
// nulll.
// null.
if (buf_size >= 2) {
*s++ = '?';

View File

@ -44,9 +44,6 @@
// only addresses.
struct _dummy_t;
extern struct _dummy_t mp_sys_exit_obj;
extern struct _dummy_t mp_sys_stdin_obj;
extern struct _dummy_t mp_sys_stdout_obj;
extern struct _dummy_t mp_sys_stderr_obj;
extern mp_obj_int_t mp_maxsize_obj;

View File

@ -59,7 +59,7 @@ STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_array_t *o = o_in;
if (o->typecode == BYTEARRAY_TYPECODE) {
print(env, "bytearray(b", o->typecode);
print(env, "bytearray(b");
mp_str_print_quoted(print, env, o->items, o->len, true);
} else {
print(env, "array('%c'", o->typecode);

View File

@ -49,3 +49,6 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
#if MICROPY_PY_BUILTINS_FLOAT
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec);
#endif
//int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args);
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...);

199
py/pfenv_printf.c Normal file
View File

@ -0,0 +1,199 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "pfenv.h"
#if MICROPY_PY_BUILTINS_FLOAT
#include "formatfloat.h"
#endif
int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args) {
int chrs = 0;
for (;;) {
{
const char *f = fmt;
while (*f != '\0' && *f != '%') {
++f; // XXX UTF8 advance char
}
if (f > fmt) {
pfenv->print_strn(pfenv->data, fmt, f - fmt);
chrs += f - fmt;
fmt = f;
}
}
if (*fmt == '\0') {
break;
}
// move past % character
++fmt;
// parse flags, if they exist
int flags = 0;
char fill = ' ';
while (*fmt != '\0') {
if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST;
else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN;
else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN;
else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ;
else if (*fmt == '0') {
flags |= PF_FLAG_PAD_AFTER_SIGN;
fill = '0';
} else break;
++fmt;
}
// parse width, if it exists
int width = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
width = width * 10 + *fmt - '0';
}
// parse precision, if it exists
int prec = -1;
if (*fmt == '.') {
++fmt;
if (*fmt == '*') {
++fmt;
prec = va_arg(args, int);
} else {
prec = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
prec = prec * 10 + *fmt - '0';
}
}
if (prec < 0) {
prec = 0;
}
}
// parse long specifiers (current not used)
//bool long_arg = false;
if (*fmt == 'l') {
++fmt;
//long_arg = true;
}
if (*fmt == '\0') {
break;
}
switch (*fmt) {
case 'b':
if (va_arg(args, int)) {
chrs += pfenv_print_strn(pfenv, "true", 4, flags, fill, width);
} else {
chrs += pfenv_print_strn(pfenv, "false", 5, flags, fill, width);
}
break;
case 'c':
{
char str = va_arg(args, int);
chrs += pfenv_print_strn(pfenv, &str, 1, flags, fill, width);
break;
}
case 's':
{
const char *str = va_arg(args, const char*);
if (str) {
if (prec < 0) {
prec = strlen(str);
}
chrs += pfenv_print_strn(pfenv, str, prec, flags, fill, width);
} else {
chrs += pfenv_print_strn(pfenv, "(null)", 6, flags, fill, width);
}
break;
}
case 'u':
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 10, 'a', flags, fill, width);
break;
case 'd':
chrs += pfenv_print_int(pfenv, va_arg(args, int), 1, 10, 'a', flags, fill, width);
break;
case 'x':
case 'p': // ?
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'a', flags, fill, width);
break;
case 'X':
case 'P': // ?
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, fill, width);
break;
#if MICROPY_PY_BUILTINS_FLOAT
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
{
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
mp_float_t f = va_arg(args, double);
chrs += pfenv_print_float(pfenv, f, *fmt, flags, fill, width, prec);
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
// Currently pfenv_print_float uses snprintf, but snprintf
// itself may be implemented in terms of pfenv_vprintf() for
// some ports. So, for extra caution, this case is handled
// with assert below. Note that currently ports which
// use MICROPY_FLOAT_IMPL_DOUBLE, don't call pfenv_vprintf()
// with float format specifier at all.
// TODO: resolve this completely
assert(0);
//#error Calling pfenv_print_float with double not supported from within printf
#else
#error Unknown MICROPY FLOAT IMPL
#endif
break;
}
#endif
default:
pfenv->print_strn(pfenv->data, fmt, 1);
chrs += 1;
break;
}
++fmt;
}
return chrs;
}
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = pfenv_vprintf(pfenv, fmt, ap);
va_end(ap);
return ret;
}

View File

@ -102,6 +102,7 @@ PY_O_BASENAME = \
repl.o \
smallint.o \
pfenv.o \
pfenv_printf.o \
../extmod/moductypes.o
# prepend the build destination prefix to the py object files

View File

@ -413,6 +413,7 @@ Q(TextIOWrapper)
Q(StringIO)
Q(BytesIO)
Q(getvalue)
Q(file)
#endif
#if MICROPY_PY_GC

View File

@ -67,6 +67,9 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported"));
}
// What to do if sz < -1? Python docs don't specify this case.
// CPython does a readall, but here we silently let negatives through,
// and they will cause a MemoryError.
mp_int_t sz;
if (n_args == 1 || ((sz = mp_obj_get_int(args[1])) == -1)) {
return stream_readall(args[0]);
@ -74,7 +77,90 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
#if MICROPY_PY_BUILTINS_STR_UNICODE
if (!o->type->stream_p->is_bytes) {
mp_not_implemented("Reading from unicode text streams by character count");
// We need to read sz number of unicode characters. Because we don't have any
// buffering, and because the stream API can only read bytes, we must read here
// in units of bytes and must never over read. If we want sz chars, then reading
// sz bytes will never over-read, so we follow this approach, in a loop to keep
// reading until we have exactly enough chars. This will be 1 read for text
// with ASCII-only chars, and about 2 reads for text with a couple of non-ASCII
// chars. For text with lots of non-ASCII chars, it'll be pretty inefficient
// in time and memory.
vstr_t vstr;
vstr_init(&vstr, sz);
mp_uint_t more_bytes = sz;
mp_uint_t last_buf_offset = 0;
while (more_bytes > 0) {
char *p = vstr_add_len(&vstr, more_bytes);
if (p == NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory"));
}
int error;
mp_int_t out_sz = o->type->stream_p->read(o, p, more_bytes, &error);
if (out_sz == -1) {
vstr_cut_tail_bytes(&vstr, more_bytes);
if (is_nonblocking_error(error)) {
// With non-blocking streams, we read as much as we can.
// If we read nothing, return None, just like read().
// Otherwise, return data read so far.
// TODO what if we have read only half a non-ASCII char?
if (vstr.len == 0) {
vstr_clear(&vstr);
return mp_const_none;
}
break;
}
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
}
if (out_sz == 0) {
// Finish reading.
// TODO what if we have read only half a non-ASCII char?
vstr_cut_tail_bytes(&vstr, more_bytes);
break;
}
// count chars from bytes just read
for (mp_uint_t off = last_buf_offset;;) {
byte b = vstr.buf[off];
int n;
if (!UTF8_IS_NONASCII(b)) {
// 1-byte ASCII char
n = 1;
} else if ((b & 0xe0) == 0xc0) {
// 2-byte char
n = 2;
} else if ((b & 0xf0) == 0xe0) {
// 3-byte char
n = 3;
} else if ((b & 0xf8) == 0xf0) {
// 4-byte char
n = 4;
} else {
// TODO
n = 5;
}
if (off + n <= vstr.len) {
// got a whole char in n bytes
off += n;
sz -= 1;
last_buf_offset = off;
if (off >= vstr.len) {
more_bytes = sz;
break;
}
} else {
// didn't get a whole char, so work out how many extra bytes are needed for
// this partial char, plus bytes for additional chars that we want
more_bytes = (off + n - vstr.len) + (sz - 1);
break;
}
}
}
mp_obj_t ret = mp_obj_new_str_of_type(&mp_type_str, (byte*)vstr.buf, vstr.len);
vstr_clear(&vstr);
return ret;
}
#endif

View File

@ -41,7 +41,7 @@ extern const mp_obj_type_t mp_type_fileio;
extern const mp_obj_type_t mp_type_textio;
// this table converts from FRESULT to POSIX errno
STATIC const byte fresult_to_errno_table[] = {
const byte fresult_to_errno_table[20] = {
[FR_OK] = 0,
[FR_DISK_ERR] = EIO,
[FR_INT_ERR] = EIO,
@ -95,6 +95,13 @@ STATIC mp_int_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t size
return sz_out;
}
STATIC mp_obj_t file_obj_flush(mp_obj_t self_in) {
pyb_file_obj_t *self = self_in;
f_sync(&self->fp);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_flush_obj, file_obj_flush);
mp_obj_t file_obj_close(mp_obj_t self_in) {
pyb_file_obj_t *self = self_in;
f_close(&self->fp);
@ -218,6 +225,7 @@ STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
{ MP_OBJ_NEW_QSTR(MP_QSTR_readlines), (mp_obj_t)&mp_stream_unbuffered_readlines_obj},
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_flush), (mp_obj_t)&file_obj_flush_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&file_obj_close_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_seek), (mp_obj_t)&file_obj_seek_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_tell), (mp_obj_t)&file_obj_tell_obj },

View File

@ -24,4 +24,6 @@
* THE SOFTWARE.
*/
const byte fresult_to_errno_table[20];
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_open_obj);

View File

@ -43,7 +43,6 @@
#include "stackctrl.h"
#include "gc.h"
#include "gccollect.h"
#include "pybstdio.h"
#include "readline.h"
#include "pyexec.h"
#include "i2c.h"
@ -64,6 +63,7 @@
#include "servo.h"
#include "dac.h"
#include "pybwlan.h"
#include "pybstdio.h"
void SystemClock_Config(void);
@ -311,12 +311,10 @@ soft_reset:
MP_OBJ_NEW_SMALL_INT(PYB_UART_6),
MP_OBJ_NEW_SMALL_INT(115200),
};
pyb_uart_global_debug = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type,
MP_ARRAY_SIZE(args),
0, args);
pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);
}
#else
pyb_uart_global_debug = NULL;
pyb_stdio_uart = NULL;
#endif
// Micro Python init

View File

@ -32,10 +32,12 @@
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "objtuple.h"
#include "systick.h"
#include "rng.h"
#include "storage.h"
#include "ff.h"
#include "file.h"
#include "portmodules.h"
#if _USE_LFN
@ -107,8 +109,7 @@ STATIC mp_obj_t os_listdir(uint n_args, const mp_obj_t *args) {
return dir_list;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir);
STATIC mp_obj_t os_mkdir(mp_obj_t path_o) {
const char *path = mp_obj_str_get_str(path_o);
@ -123,8 +124,7 @@ STATIC mp_obj_t os_mkdir(mp_obj_t path_o) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error creating directory '%s'", path));
}
}
MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir);
STATIC mp_obj_t os_remove(mp_obj_t path_o) {
const char *path = mp_obj_str_get_str(path_o);
@ -137,8 +137,7 @@ STATIC mp_obj_t os_remove(mp_obj_t path_o) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing file '%s'", path));
}
}
MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove);
STATIC mp_obj_t os_rmdir(mp_obj_t path_o) {
const char *path = mp_obj_str_get_str(path_o);
@ -151,15 +150,57 @@ STATIC mp_obj_t os_rmdir(mp_obj_t path_o) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing directory '%s'", path));
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_rmdir_obj, os_rmdir);
MP_DEFINE_CONST_FUN_OBJ_1(os_rmdir_obj, os_rmdir);
STATIC mp_obj_t os_stat(mp_obj_t path_in) {
const char *path = mp_obj_str_get_str(path_in);
FILINFO fno;
#if _USE_LFN
fno.lfname = NULL;
fno.lfsize = 0;
#endif
FRESULT res = f_stat(path, &fno);
if (res != FR_OK) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
}
mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL);
mp_int_t mode = 0;
if (fno.fattrib & AM_DIR) {
mode |= 0x4000; // stat.S_IFDIR
} else {
mode |= 0x8000; // stat.S_IFREG
}
mp_int_t seconds = mod_time_seconds_since_2000(
1980 + ((fno.fdate >> 9) & 0x7f),
(fno.fdate >> 5) & 0x0f,
fno.fdate & 0x1f,
(fno.ftime >> 11) & 0x1f,
(fno.ftime >> 5) & 0x3f,
2 * (fno.ftime & 0x1f)
);
t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode
t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev
t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
t->items[6] = MP_OBJ_NEW_SMALL_INT(fno.fsize); // st_size
t->items[7] = MP_OBJ_NEW_SMALL_INT(seconds); // st_atime
t->items[8] = MP_OBJ_NEW_SMALL_INT(seconds); // st_mtime
t->items[9] = MP_OBJ_NEW_SMALL_INT(seconds); // st_ctime
return t;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);
STATIC mp_obj_t os_sync(void) {
storage_flush();
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync);
STATIC mp_obj_t os_urandom(mp_obj_t num) {
mp_int_t n = mp_obj_get_int(num);
@ -170,8 +211,7 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) {
}
return mp_obj_str_builder_end(o);
}
MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
STATIC const mp_map_elem_t os_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_os) },
@ -180,6 +220,7 @@ STATIC const mp_map_elem_t os_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkdir), (mp_obj_t)&os_mkdir_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&os_remove_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_rmdir), (mp_obj_t)&os_rmdir_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_stat), (mp_obj_t)&os_stat_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&os_remove_obj }, // unlink aliases to remove
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&os_sync_obj },

View File

@ -37,7 +37,6 @@
#include "gc.h"
#include "gccollect.h"
#include "systick.h"
#include "pybstdio.h"
#include "pyexec.h"
#include "led.h"
#include "pin.h"
@ -57,6 +56,7 @@
#include "dac.h"
#include "lcd.h"
#include "usb.h"
#include "pybstdio.h"
#include "ff.h"
#include "portmodules.h"
@ -307,16 +307,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc);
/// Get or set the UART object that the REPL is repeated on.
STATIC mp_obj_t pyb_repl_uart(uint n_args, const mp_obj_t *args) {
if (n_args == 0) {
if (pyb_uart_global_debug == NULL) {
if (pyb_stdio_uart == NULL) {
return mp_const_none;
} else {
return pyb_uart_global_debug;
return pyb_stdio_uart;
}
} else {
if (args[0] == mp_const_none) {
pyb_uart_global_debug = NULL;
pyb_stdio_uart = NULL;
} else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
pyb_uart_global_debug = args[0];
pyb_stdio_uart = args[0];
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a UART object"));
}

View File

@ -34,22 +34,36 @@
#include "portmodules.h"
#include "rtc.h"
STATIC const uint days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
STATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
STATIC bool is_leap_year(uint year) {
STATIC bool is_leap_year(mp_uint_t year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
// compute the day of the year, between 1 and 366
// month should be between 1 and 12, date should start at 1
STATIC uint year_day(uint year, uint month, uint date) {
uint yday = days_since_jan1[month - 1] + date;
mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) {
mp_uint_t yday = days_since_jan1[month - 1] + date;
if (month >= 3 && is_leap_year(year)) {
yday += 1;
}
return yday;
}
// returns the number of seconds, as an integer, since 1/1/2000
mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
return
second
+ minute * 60
+ hour * 3600
+ (mod_time_year_day(year, month, date) - 1
+ ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001
- ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001
+ ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001
) * 86400
+ (year - 2000) * 31536000;
}
// returns time stored in RTC as: (year, month, date, hour, minute, second, weekday)
// weekday is 0-6 for Mon-Sun
STATIC mp_obj_t time_localtime(void) {
@ -67,7 +81,7 @@ STATIC mp_obj_t time_localtime(void) {
mp_obj_new_int(time.Minutes),
mp_obj_new_int(time.Seconds),
mp_obj_new_int(date.WeekDay - 1),
mp_obj_new_int(year_day(2000 + date.Year, date.Month, date.Date)),
mp_obj_new_int(mod_time_year_day(2000 + date.Year, date.Month, date.Date)),
};
return mp_obj_new_tuple(8, tuple);
}
@ -95,17 +109,7 @@ STATIC mp_obj_t time_time(void) {
RTC_TimeTypeDef time;
HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);
HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN);
return mp_obj_new_int(
time.Seconds
+ time.Minutes * 60
+ time.Hours * 3600
+ (year_day(2000 + date.Year, date.Month, date.Date) - 1
+ ((date.Year + 3) / 4) // add a day each 4 years starting with 2001
- ((date.Year + 99) / 100) // subtract a day each 100 years starting with 2001
+ ((date.Year + 399) / 400) // add a day each 400 years starting with 2001
) * 86400
+ date.Year * 31536000
);
return mp_obj_new_int(mod_time_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds));
}
MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);

View File

@ -44,7 +44,7 @@
*/
#define MICROPY_ENABLE_LFN (1)
#define MICROPY_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_FROZENSET (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_STDFILES (1)

View File

@ -28,3 +28,8 @@ extern const mp_obj_module_t os_module;
extern const mp_obj_module_t pyb_module;
extern const mp_obj_module_t stm_module;
extern const mp_obj_module_t time_module;
// additional helper functions exported by the modules
mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date);
mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second);

View File

@ -40,184 +40,30 @@
#endif
#include "uart.h"
#include "usb.h"
#include "pybstdio.h"
#if MICROPY_PY_BUILTINS_FLOAT
#include "formatfloat.h"
#endif
void pfenv_prints(const pfenv_t *pfenv, const char *str) {
pfenv->print_strn(pfenv->data, str, strlen(str));
int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args);
STATIC void stdout_print_strn(void *dummy_env, const char *str, unsigned int len) {
stdout_tx_strn_cooked(str, len);
}
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, va_list args) {
int chrs = 0;
for (;;) {
{
const char *f = fmt;
while (*f != '\0' && *f != '%') {
++f; // XXX UTF8 advance char
}
if (f > fmt) {
pfenv->print_strn(pfenv->data, fmt, f - fmt);
chrs += f - fmt;
fmt = f;
}
}
if (*fmt == '\0') {
break;
}
// move past % character
++fmt;
// parse flags, if they exist
int flags = 0;
char fill = ' ';
while (*fmt != '\0') {
if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST;
else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN;
else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN;
else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ;
else if (*fmt == '0') {
flags |= PF_FLAG_PAD_AFTER_SIGN;
fill = '0';
} else break;
++fmt;
}
// parse width, if it exists
int width = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
width = width * 10 + *fmt - '0';
}
// parse precision, if it exists
int prec = -1;
if (*fmt == '.') {
++fmt;
if (*fmt == '*') {
++fmt;
prec = va_arg(args, int);
} else {
prec = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
prec = prec * 10 + *fmt - '0';
}
}
if (prec < 0) {
prec = 0;
}
}
// parse long specifiers (current not used)
//bool long_arg = false;
if (*fmt == 'l') {
++fmt;
//long_arg = true;
}
if (*fmt == '\0') {
break;
}
switch (*fmt) {
case 'b':
if (va_arg(args, int)) {
chrs += pfenv_print_strn(pfenv, "true", 4, flags, fill, width);
} else {
chrs += pfenv_print_strn(pfenv, "false", 5, flags, fill, width);
}
break;
case 'c':
{
char str = va_arg(args, int);
chrs += pfenv_print_strn(pfenv, &str, 1, flags, fill, width);
break;
}
case 's':
{
const char *str = va_arg(args, const char*);
if (str) {
if (prec < 0) {
prec = strlen(str);
}
chrs += pfenv_print_strn(pfenv, str, prec, flags, fill, width);
} else {
chrs += pfenv_print_strn(pfenv, "(null)", 6, flags, fill, width);
}
break;
}
case 'u':
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 10, 'a', flags, fill, width);
break;
case 'd':
chrs += pfenv_print_int(pfenv, va_arg(args, int), 1, 10, 'a', flags, fill, width);
break;
case 'x':
case 'p': // ?
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'a', flags, fill, width);
break;
case 'X':
case 'P': // ?
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, fill, width);
break;
#if MICROPY_PY_BUILTINS_FLOAT
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
{
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
mp_float_t f = va_arg(args, double);
chrs += pfenv_print_float(pfenv, f, *fmt, flags, fill, width, prec);
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
// Currently pfenv_print_float uses snprintf, so if you want
// to use pfenv_print_float with doubles then you'll need
// fix it to not use snprintf first. Otherwise you'll have
// inifinite recursion.
#error Calling pfenv_print_float with double not supported from within printf
#else
#error Unknown MICROPY FLOAT IMPL
#endif
break;
}
#endif
default:
pfenv->print_strn(pfenv->data, fmt, 1);
chrs += 1;
break;
}
++fmt;
}
return chrs;
}
STATIC void stdout_print_strn(void *data, const char *str, unsigned int len) {
// TODO this needs to be replaced with a proper stdio interface ala CPython
// send stdout to UART and USB CDC VCP
if (pyb_uart_global_debug != PYB_UART_NONE) {
uart_tx_strn_cooked(pyb_uart_global_debug, str, len);
}
if (usb_vcp_is_enabled()) {
usb_vcp_send_strn_cooked(str, len);
}
}
static const pfenv_t pfenv_stdout = {0, stdout_print_strn};
STATIC const pfenv_t pfenv_stdout = {0, stdout_print_strn};
int printf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = pfenv_printf(&pfenv_stdout, fmt, ap);
int ret = pfenv_vprintf(&pfenv_stdout, fmt, ap);
va_end(ap);
return ret;
}
int vprintf(const char *fmt, va_list ap) {
return pfenv_printf(&pfenv_stdout, fmt, ap);
return pfenv_vprintf(&pfenv_stdout, fmt, ap);
}
#if MICROPY_DEBUG_PRINTERS
@ -225,7 +71,7 @@ int DEBUG_printf(const char *fmt, ...) {
(void)stream;
va_list ap;
va_start(ap, fmt);
int ret = pfenv_printf(&pfenv_stdout, fmt, ap);
int ret = pfenv_vprintf(&pfenv_stdout, fmt, ap);
va_end(ap);
return ret;
}
@ -268,7 +114,7 @@ int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) {
pfenv_t pfenv;
pfenv.data = &strn_pfenv;
pfenv.print_strn = strn_print_strn;
int len = pfenv_printf(&pfenv, fmt, ap);
int len = pfenv_vprintf(&pfenv, fmt, ap);
// add terminating null byte
if (size > 0) {
if (strn_pfenv.remain == 0) {

View File

@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
@ -34,31 +35,41 @@
#include "obj.h"
#include "stream.h"
#include MICROPY_HAL_H
#include "pybstdio.h"
#include "usb.h"
#include "uart.h"
#include "pybstdio.h"
// TODO make stdin, stdout and stderr writable objects so they can
// be changed by Python code.
// be changed by Python code. This requires some changes, as these
// objects are in a read-only module (py/modsys.c).
// stdio is repeated on this UART object if it's not null
pyb_uart_obj_t *pyb_stdio_uart = NULL;
void stdout_tx_str(const char *str) {
if (pyb_uart_global_debug != PYB_UART_NONE) {
uart_tx_str(pyb_uart_global_debug, str);
}
#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
lcd_print_str(str);
#endif
usb_vcp_send_str(str);
stdout_tx_strn(str, strlen(str));
}
void stdout_tx_strn(const char *str, uint len) {
if (pyb_uart_global_debug != PYB_UART_NONE) {
uart_tx_strn(pyb_uart_global_debug, str, len);
void stdout_tx_strn(const char *str, mp_uint_t len) {
if (pyb_stdio_uart != PYB_UART_NONE) {
uart_tx_strn(pyb_stdio_uart, str, len);
}
#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
lcd_print_strn(str, len);
#endif
usb_vcp_send_strn(str, len);
if (usb_vcp_is_enabled()) {
usb_vcp_send_strn(str, len);
}
}
void stdout_tx_strn_cooked(const char *str, mp_uint_t len) {
// send stdout to UART and USB CDC VCP
if (pyb_stdio_uart != PYB_UART_NONE) {
uart_tx_strn_cooked(pyb_stdio_uart, str, len);
}
if (usb_vcp_is_enabled()) {
usb_vcp_send_strn_cooked(str, len);
}
}
int stdin_rx_chr(void) {
@ -74,14 +85,13 @@ int stdin_rx_chr(void) {
#endif
if (usb_vcp_rx_num() != 0) {
return usb_vcp_rx_get();
} else if (pyb_uart_global_debug != PYB_UART_NONE && uart_rx_any(pyb_uart_global_debug)) {
return uart_rx_char(pyb_uart_global_debug);
} else if (pyb_stdio_uart != PYB_UART_NONE && uart_rx_any(pyb_stdio_uart)) {
return uart_rx_char(pyb_stdio_uart);
}
__WFI();
}
}
/******************************************************************************/
// Micro Python bindings
@ -120,7 +130,7 @@ STATIC mp_int_t stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *err
STATIC mp_int_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
pyb_stdio_obj_t *self = self_in;
if (self->fd == STDIO_FD_OUT || self->fd == STDIO_FD_ERR) {
stdout_tx_strn(buf, size);
stdout_tx_strn_cooked(buf, size);
*errcode = 0;
return size;
} else {

View File

@ -24,6 +24,9 @@
* THE SOFTWARE.
*/
extern pyb_uart_obj_t *pyb_stdio_uart;
void stdout_tx_str(const char *str);
void stdout_tx_strn(const char *str, uint len);
void stdout_tx_strn(const char *str, mp_uint_t len);
void stdout_tx_strn_cooked(const char *str, mp_uint_t len);
int stdin_rx_chr(void);

View File

@ -44,10 +44,11 @@
#include "gccollect.h"
#include MICROPY_HAL_H
#include "systick.h"
#include "pybstdio.h"
#include "readline.h"
#include "pyexec.h"
#include "usb.h"
#include "uart.h"
#include "pybstdio.h"
#include "genhdr/py-version.h"
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;

View File

@ -61,6 +61,7 @@ Q(rng)
Q(SD)
Q(SDcard)
Q(FileIO)
Q(flush)
// Entries for sys.path
Q(0:/)
Q(0:/lib)
@ -238,6 +239,7 @@ Q(remove)
Q(rmdir)
Q(unlink)
Q(sep)
Q(stat)
Q(urandom)
// for time module

View File

@ -34,9 +34,10 @@
#include "misc.h"
#include "obj.h"
#include MICROPY_HAL_H
#include "pybstdio.h"
#include "readline.h"
#include "usb.h"
#include "uart.h"
#include "pybstdio.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)

View File

@ -65,8 +65,6 @@ struct _pyb_uart_obj_t {
UART_HandleTypeDef uart;
};
pyb_uart_obj_t *pyb_uart_global_debug = NULL;
// assumes Init parameters have been set up correctly
bool uart_init2(pyb_uart_obj_t *uart_obj) {
USART_TypeDef *UARTx = NULL;
@ -219,10 +217,6 @@ void uart_tx_char(pyb_uart_obj_t *uart_obj, int c) {
HAL_UART_Transmit(&uart_obj->uart, &ch, 1, 100000);
}
void uart_tx_str(pyb_uart_obj_t *uart_obj, const char *str) {
HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, strlen(str), 100000);
}
void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, len, 100000);
}

View File

@ -43,14 +43,11 @@ typedef enum {
} pyb_uart_t;
typedef struct _pyb_uart_obj_t pyb_uart_obj_t;
extern pyb_uart_obj_t *pyb_uart_global_debug;
extern const mp_obj_type_t pyb_uart_type;
bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate);
bool uart_rx_any(pyb_uart_obj_t *uart_obj);
int uart_rx_char(pyb_uart_obj_t *uart_obj);
void uart_tx_str(pyb_uart_obj_t *uart_obj, const char *str);
void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len);
void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len);

View File

@ -107,10 +107,6 @@ char usb_vcp_rx_get(void) {
return USBD_CDC_RxGet();
}
void usb_vcp_send_str(const char *str) {
usb_vcp_send_strn(str, strlen(str));
}
void usb_vcp_send_strn(const char *str, int len) {
#ifdef USE_DEVICE_MODE
if (dev_is_enabled) {

View File

@ -48,7 +48,6 @@ bool usb_vcp_is_connected(void);
void usb_vcp_set_interrupt_char(int c);
int usb_vcp_rx_num(void);
char usb_vcp_rx_get(void);
void usb_vcp_send_str(const char* str);
void usb_vcp_send_strn(const char* str, int len);
void usb_vcp_send_strn_cooked(const char *str, int len);
void usb_hid_send_report(uint8_t *buf); // 4 bytes for mouse: ?, x, y, ?

View File

@ -6,14 +6,7 @@ QSTR_DEFS = qstrdefsport.h
# include py core make definitions
include ../py/py.mk
ifeq ($(ARDUINO),)
$(error Please define ARDUINO (where TeensyDuino is installed))
endif
TOOLS_PATH = $(ARDUINO)/hardware/tools
COMPILER_PATH = $(TOOLS_PATH)/arm-none-eabi/bin
CORE_PATH = $(ARDUINO)/hardware/teensy/cores/teensy3
CROSS_COMPILE = $(COMPILER_PATH)/arm-none-eabi-
CROSS_COMPILE = arm-none-eabi-
CFLAGS_TEENSY = -DF_CPU=96000000 -DUSB_SERIAL -D__MK20DX256__
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -fsingle-precision-constant -Wdouble-promotion $(CFLAGS_TEENSY)
@ -22,13 +15,26 @@ INC = -I.
INC += -I$(PY_SRC)
INC += -I../stmhal
INC += -I$(BUILD)
INC += -I$(CORE_PATH)
INC += -Icore
CFLAGS = $(INC) -Wall -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4)
LDFLAGS = -nostdlib -T mk20dx256.ld
LIBS = -L $(COMPILER_PATH)/../arm-none-eabi/lib/thumb2 -lm
LIBS += -L $(COMPILER_PATH)/../arm-none-eabi/lib/thumb2 -lc
LIBS += -L $(COMPILER_PATH)/../lib/gcc/arm-none-eabi/4.7.2/thumb2 -lgcc
LIBGCC_FILE_NAME = $(shell $(CC) -print-libgcc-file-name)
LIBM_FILE_NAME = $(shell $(CC) -print-file-name=libm.a)
LIBC_FILE_NAME = $(shell $(CC) -print-file-name=libc.a)
#$(info %%%%% LIBGCC_FILE_NAME = $(LIBGCC_FILE_NAME))
#$(info %%%%% LIBM_FILE_NAME = $(LIBM_FILE_NAME))
#$(info %%%%% LIBC_FILE_NAME = $(LIBC_FILE_NAME))
#$(info %%%%% dirname LIBGCC_FILE_NAME = $(dir $(LIBGCC_FILE_NAME)))
#$(info %%%%% dirname LIBM_FILE_NAME = $(dir $(LIBM_FILE_NAME)))
#$(info %%%%% dirname LIBC_FILE_NAME = $(dir $(LIBC_FILE_NAME)))
LIBS = -L $(dir $(LIBM_FILE_NAME)) -lm
LIBS += -L $(dir $(LIBC_FILE_NAME)) -lc
LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc
#Debugging/Optimization
ifdef DEBUG
@ -67,7 +73,7 @@ STM_SRC_S = $(addprefix stmhal/,\
gchelper.s \
)
SRC_TEENSY = \
SRC_TEENSY = $(addprefix core/,\
mk20dx128.c \
pins_teensy.c \
analog.c \
@ -76,6 +82,7 @@ SRC_TEENSY = \
usb_mem.c \
usb_serial.c \
yield.c \
)
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(STM_SRC_C:.c=.o) $(STM_SRC_S:.s=.o) $(SRC_TEENSY:.c=.o))
OBJ += $(BUILD)/pins_gen.o
@ -83,6 +90,18 @@ OBJ += $(BUILD)/pins_gen.o
all: hex
hex: $(BUILD)/micropython-mz.hex
ifeq ($(ARDUINO),)
post_compile: $(BUILD)/micropython-mz.hex
$(ECHO) "Please define ARDUINO (where TeensyDuino is installed)"
exit 1
reboot:
$(ECHO) "Please define ARDUINO (where TeensyDuino is installed)"
exit 1
else
TOOLS_PATH = $(ARDUINO)/hardware/tools
post_compile: $(BUILD)/micropython-mz.hex
$(ECHO) "Preparing $@ for upload"
$(Q)$(TOOLS_PATH)/teensy_post_compile -file="$(basename $(<F))" -path="$(<D)" -tools="$(TOOLS_PATH)"
@ -90,8 +109,10 @@ post_compile: $(BUILD)/micropython-mz.hex
reboot:
$(ECHO) "REBOOT"
-$(Q)$(TOOLS_PATH)/teensy_reboot
endif
upload: post_compile reboot
.PHONY: deploy
deploy: post_compile reboot
$(BUILD)/micropython.elf: $(OBJ)
$(ECHO) "LINK $@"
@ -110,9 +131,6 @@ $(BUILD)/%.hex: $(BUILD)/%.elf
$(ECHO) "HEX $<"
$(Q)$(OBJCOPY) -O ihex -R .eeprom "$<" "$@"
$(BUILD)/%.o: $(CORE_PATH)/%.c
$(call compile_c)
MAKE_PINS = make-pins.py
BOARD_PINS = teensy-pins.csv
AF_FILE = mk20dx256-af.csv

3
teensy/core/Arduino.h Normal file
View File

@ -0,0 +1,3 @@
//#include "WProgram.h"
#include "core_pins.h"
#include "pins_arduino.h"

View File

@ -0,0 +1,227 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef HardwareSerial_h
#define HardwareSerial_h
#include "mk20dx128.h"
#include <inttypes.h>
// uncomment to enable 9 bit formats
//#define SERIAL_9BIT_SUPPORT
#define SERIAL_7E1 0x02
#define SERIAL_7O1 0x03
#define SERIAL_8N1 0x00
#define SERIAL_8N2 0x04
#define SERIAL_8E1 0x06
#define SERIAL_8O1 0x07
#define SERIAL_7E1_RXINV 0x12
#define SERIAL_7O1_RXINV 0x13
#define SERIAL_8N1_RXINV 0x10
#define SERIAL_8N2_RXINV 0x14
#define SERIAL_8E1_RXINV 0x16
#define SERIAL_8O1_RXINV 0x17
#define SERIAL_7E1_TXINV 0x22
#define SERIAL_7O1_TXINV 0x23
#define SERIAL_8N1_TXINV 0x20
#define SERIAL_8N2_TXINV 0x24
#define SERIAL_8E1_TXINV 0x26
#define SERIAL_8O1_TXINV 0x27
#define SERIAL_7E1_RXINV_TXINV 0x32
#define SERIAL_7O1_RXINV_TXINV 0x33
#define SERIAL_8N1_RXINV_TXINV 0x30
#define SERIAL_8N2_RXINV_TXINV 0x34
#define SERIAL_8E1_RXINV_TXINV 0x36
#define SERIAL_8O1_RXINV_TXINV 0x37
#ifdef SERIAL_9BIT_SUPPORT
#define SERIAL_9N1 0x84
#define SERIAL_9E1 0x8E
#define SERIAL_9O1 0x8F
#define SERIAL_9N1_RXINV 0x94
#define SERIAL_9E1_RXINV 0x9E
#define SERIAL_9O1_RXINV 0x9F
#define SERIAL_9N1_TXINV 0xA4
#define SERIAL_9E1_TXINV 0xAE
#define SERIAL_9O1_TXINV 0xAF
#define SERIAL_9N1_RXINV_TXINV 0xB4
#define SERIAL_9E1_RXINV_TXINV 0xBE
#define SERIAL_9O1_RXINV_TXINV 0xBF
#endif
// bit0: parity, 0=even, 1=odd
// bit1: parity, 0=disable, 1=enable
// bit2: mode, 1=9bit, 0=8bit
// bit3: mode10: 1=10bit, 0=8bit
// bit4: rxinv, 0=normal, 1=inverted
// bit5: txinv, 0=normal, 1=inverted
// bit6: unused
// bit7: actual data goes into 9th bit
#define BAUD2DIV(baud) (((F_CPU * 2) + ((baud) >> 1)) / (baud))
#define BAUD2DIV3(baud) (((F_BUS * 2) + ((baud) >> 1)) / (baud))
// C language implementation
//
#ifdef __cplusplus
extern "C" {
#endif
void serial_begin(uint32_t divisor);
void serial_format(uint32_t format);
void serial_end(void);
void serial_set_transmit_pin(uint8_t pin);
void serial_putchar(uint32_t c);
void serial_write(const void *buf, unsigned int count);
void serial_flush(void);
int serial_available(void);
int serial_getchar(void);
int serial_peek(void);
void serial_clear(void);
void serial_print(const char *p);
void serial_phex(uint32_t n);
void serial_phex16(uint32_t n);
void serial_phex32(uint32_t n);
void serial2_begin(uint32_t divisor);
void serial2_format(uint32_t format);
void serial2_end(void);
void serial2_putchar(uint32_t c);
void serial2_write(const void *buf, unsigned int count);
void serial2_flush(void);
int serial2_available(void);
int serial2_getchar(void);
int serial2_peek(void);
void serial2_clear(void);
void serial3_begin(uint32_t divisor);
void serial3_format(uint32_t format);
void serial3_end(void);
void serial3_putchar(uint32_t c);
void serial3_write(const void *buf, unsigned int count);
void serial3_flush(void);
int serial3_available(void);
int serial3_getchar(void);
int serial3_peek(void);
void serial3_clear(void);
#ifdef __cplusplus
}
#endif
// C++ interface
//
#ifdef __cplusplus
#include "Stream.h"
class HardwareSerial : public Stream
{
public:
virtual void begin(uint32_t baud) { serial_begin(BAUD2DIV(baud)); }
virtual void begin(uint32_t baud, uint32_t format) {
serial_begin(BAUD2DIV(baud));
serial_format(format); }
virtual void end(void) { serial_end(); }
virtual void transmitterEnable(uint8_t pin) { serial_set_transmit_pin(pin); }
virtual int available(void) { return serial_available(); }
virtual int peek(void) { return serial_peek(); }
virtual int read(void) { return serial_getchar(); }
virtual void flush(void) { serial_flush(); }
virtual void clear(void) { serial_clear(); }
virtual size_t write(uint8_t c) { serial_putchar(c); return 1; }
virtual size_t write(unsigned long n) { return write((uint8_t)n); }
virtual size_t write(long n) { return write((uint8_t)n); }
virtual size_t write(unsigned int n) { return write((uint8_t)n); }
virtual size_t write(int n) { return write((uint8_t)n); }
virtual size_t write(const uint8_t *buffer, size_t size)
{ serial_write(buffer, size); return size; }
virtual size_t write(const char *str) { size_t len = strlen(str);
serial_write((const uint8_t *)str, len);
return len; }
virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; }
};
extern HardwareSerial Serial1;
class HardwareSerial2 : public HardwareSerial
{
public:
virtual void begin(uint32_t baud) { serial2_begin(BAUD2DIV(baud)); }
virtual void begin(uint32_t baud, uint32_t format) {
serial2_begin(BAUD2DIV(baud));
serial2_format(format); }
virtual void end(void) { serial2_end(); }
virtual int available(void) { return serial2_available(); }
virtual int peek(void) { return serial2_peek(); }
virtual int read(void) { return serial2_getchar(); }
virtual void flush(void) { serial2_flush(); }
virtual void clear(void) { serial2_clear(); }
virtual size_t write(uint8_t c) { serial2_putchar(c); return 1; }
virtual size_t write(unsigned long n) { return write((uint8_t)n); }
virtual size_t write(long n) { return write((uint8_t)n); }
virtual size_t write(unsigned int n) { return write((uint8_t)n); }
virtual size_t write(int n) { return write((uint8_t)n); }
virtual size_t write(const uint8_t *buffer, size_t size)
{ serial2_write(buffer, size); return size; }
virtual size_t write(const char *str) { size_t len = strlen(str);
serial2_write((const uint8_t *)str, len);
return len; }
virtual size_t write9bit(uint32_t c) { serial2_putchar(c); return 1; }
};
extern HardwareSerial2 Serial2;
class HardwareSerial3 : public HardwareSerial
{
public:
virtual void begin(uint32_t baud) { serial3_begin(BAUD2DIV3(baud)); }
virtual void begin(uint32_t baud, uint32_t format) {
serial3_begin(BAUD2DIV3(baud));
serial3_format(format); }
virtual void end(void) { serial3_end(); }
virtual int available(void) { return serial3_available(); }
virtual int peek(void) { return serial3_peek(); }
virtual int read(void) { return serial3_getchar(); }
virtual void flush(void) { serial3_flush(); }
virtual void clear(void) { serial3_clear(); }
virtual size_t write(uint8_t c) { serial3_putchar(c); return 1; }
virtual size_t write(unsigned long n) { return write((uint8_t)n); }
virtual size_t write(long n) { return write((uint8_t)n); }
virtual size_t write(unsigned int n) { return write((uint8_t)n); }
virtual size_t write(int n) { return write((uint8_t)n); }
virtual size_t write(const uint8_t *buffer, size_t size)
{ serial3_write(buffer, size); return size; }
virtual size_t write(const char *str) { size_t len = strlen(str);
serial3_write((const uint8_t *)str, len);
return len; }
virtual size_t write9bit(uint32_t c) { serial3_putchar(c); return 1; }
};
extern HardwareSerial3 Serial3;
#endif
#endif

463
teensy/core/analog.c Normal file
View File

@ -0,0 +1,463 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "core_pins.h"
//#include "HardwareSerial.h"
static uint8_t calibrating;
static uint8_t analog_right_shift = 0;
static uint8_t analog_config_bits = 10;
static uint8_t analog_num_average = 4;
static uint8_t analog_reference_internal = 0;
// the alternate clock is connected to OSCERCLK (16 MHz).
// datasheet says ADC clock should be 2 to 12 MHz for 16 bit mode
// datasheet says ADC clock should be 1 to 18 MHz for 8-12 bit mode
#if F_BUS == 60000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 7.5 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz
#elif F_BUS == 56000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 7 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 MHz
#elif F_BUS == 48000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 12 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 12 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 12 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 24 MHz
#elif F_BUS == 40000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 10 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 10 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 10 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 20 MHz
#elif F_BUS == 36000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 9 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 18 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 18 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 18 MHz
#elif F_BUS == 24000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(0) // 12 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(0) // 12 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(0) // 12 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 24 MHz
#elif F_BUS == 16000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 16 MHz
#elif F_BUS == 8000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz
#elif F_BUS == 4000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 4 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 4 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 4 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 4 MHz
#elif F_BUS == 2000000
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz
#else
#error "F_BUS must be 60, 56, 48, 40, 36, 24, 4 or 2 MHz"
#endif
void analog_init(void)
{
uint32_t num;
VREF_TRM = 0x60;
VREF_SC = 0xE1; // enable 1.2 volt ref
if (analog_config_bits == 8) {
ADC0_CFG1 = ADC_CFG1_8BIT + ADC_CFG1_MODE(0);
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
#if defined(__MK20DX256__)
ADC1_CFG1 = ADC_CFG1_8BIT + ADC_CFG1_MODE(0);
ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
#endif
} else if (analog_config_bits == 10) {
ADC0_CFG1 = ADC_CFG1_10BIT + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP;
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
#if defined(__MK20DX256__)
ADC1_CFG1 = ADC_CFG1_10BIT + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP;
ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
#endif
} else if (analog_config_bits == 12) {
ADC0_CFG1 = ADC_CFG1_12BIT + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP;
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
#if defined(__MK20DX256__)
ADC1_CFG1 = ADC_CFG1_12BIT + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP;
ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
#endif
} else {
ADC0_CFG1 = ADC_CFG1_16BIT + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP;
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
#if defined(__MK20DX256__)
ADC1_CFG1 = ADC_CFG1_16BIT + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP;
ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
#endif
}
if (analog_reference_internal) {
ADC0_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref
#if defined(__MK20DX256__)
ADC1_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref
#endif
} else {
ADC0_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref
#if defined(__MK20DX256__)
ADC1_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref
#endif
}
num = analog_num_average;
if (num <= 1) {
ADC0_SC3 = ADC_SC3_CAL; // begin cal
#if defined(__MK20DX256__)
ADC1_SC3 = ADC_SC3_CAL; // begin cal
#endif
} else if (num <= 4) {
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0);
#if defined(__MK20DX256__)
ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0);
#endif
} else if (num <= 8) {
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1);
#if defined(__MK20DX256__)
ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1);
#endif
} else if (num <= 16) {
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2);
#if defined(__MK20DX256__)
ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2);
#endif
} else {
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3);
#if defined(__MK20DX256__)
ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3);
#endif
}
calibrating = 1;
}
static void wait_for_cal(void)
{
uint16_t sum;
//serial_print("wait_for_cal\n");
#if defined(__MK20DX128__)
while (ADC0_SC3 & ADC_SC3_CAL) {
// wait
}
#elif defined(__MK20DX256__)
while ((ADC0_SC3 & ADC_SC3_CAL) || (ADC1_SC3 & ADC_SC3_CAL)) {
// wait
}
#endif
__disable_irq();
if (calibrating) {
//serial_print("\n");
sum = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0;
sum = (sum / 2) | 0x8000;
ADC0_PG = sum;
//serial_print("ADC0_PG = ");
//serial_phex16(sum);
//serial_print("\n");
sum = ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0;
sum = (sum / 2) | 0x8000;
ADC0_MG = sum;
//serial_print("ADC0_MG = ");
//serial_phex16(sum);
//serial_print("\n");
#if defined(__MK20DX256__)
sum = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0;
sum = (sum / 2) | 0x8000;
ADC1_PG = sum;
sum = ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0;
sum = (sum / 2) | 0x8000;
ADC1_MG = sum;
#endif
calibrating = 0;
}
__enable_irq();
}
// ADCx_SC2[REFSEL] bit selects the voltage reference sources for ADC.
// VREFH/VREFL - connected as the primary reference option
// 1.2 V VREF_OUT - connected as the VALT reference option
#define DEFAULT 0
#define INTERNAL 2
#define INTERNAL1V2 2
#define INTERNAL1V1 2
#define EXTERNAL 0
void analogReference(uint8_t type)
{
if (type) {
// internal reference requested
if (!analog_reference_internal) {
analog_reference_internal = 1;
if (calibrating) {
ADC0_SC3 = 0; // cancel cal
#if defined(__MK20DX256__)
ADC1_SC3 = 0; // cancel cal
#endif
}
analog_init();
}
} else {
// vcc or external reference requested
if (analog_reference_internal) {
analog_reference_internal = 0;
if (calibrating) {
ADC0_SC3 = 0; // cancel cal
#if defined(__MK20DX256__)
ADC1_SC3 = 0; // cancel cal
#endif
}
analog_init();
}
}
}
void analogReadRes(unsigned int bits)
{
unsigned int config;
if (bits >= 13) {
if (bits > 16) bits = 16;
config = 16;
} else if (bits >= 11) {
config = 12;
} else if (bits >= 9) {
config = 10;
} else {
config = 8;
}
analog_right_shift = config - bits;
if (config != analog_config_bits) {
analog_config_bits = config;
if (calibrating) ADC0_SC3 = 0; // cancel cal
analog_init();
}
}
void analogReadAveraging(unsigned int num)
{
if (calibrating) wait_for_cal();
if (num <= 1) {
num = 0;
ADC0_SC3 = 0;
} else if (num <= 4) {
num = 4;
ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0);
} else if (num <= 8) {
num = 8;
ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1);
} else if (num <= 16) {
num = 16;
ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2);
} else {
num = 32;
ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3);
}
analog_num_average = num;
}
// The SC1A register is used for both software and hardware trigger modes of operation.
#if defined(__MK20DX128__)
static const uint8_t channel2sc1a[] = {
5, 14, 8, 9, 13, 12, 6, 7, 15, 4,
0, 19, 3, 21, 26, 22, 23
};
#elif defined(__MK20DX256__)
static const uint8_t channel2sc1a[] = {
5, 14, 8, 9, 13, 12, 6, 7, 15, 4,
0, 19, 3, 19+128, 26, 18+128, 23,
5+192, 5+128, 4+128, 6+128, 7+128, 4+192
// A15 26 E1 ADC1_SE5a 5+64
// A16 27 C9 ADC1_SE5b 5
// A17 28 C8 ADC1_SE4b 4
// A18 29 C10 ADC1_SE6b 6
// A19 30 C11 ADC1_SE7b 7
// A20 31 E0 ADC1_SE4a 4+64
};
#endif
// TODO: perhaps this should store the NVIC priority, so it works recursively?
static volatile uint8_t analogReadBusyADC0 = 0;
#if defined(__MK20DX256__)
static volatile uint8_t analogReadBusyADC1 = 0;
#endif
int analogRead(uint8_t pin)
{
int result;
uint8_t index, channel;
//serial_phex(pin);
//serial_print(" ");
if (pin <= 13) {
index = pin; // 0-13 refer to A0-A13
} else if (pin <= 23) {
index = pin - 14; // 14-23 are A0-A9
#if defined(__MK20DX256__)
} else if (pin >= 26 && pin <= 31) {
index = pin - 9; // 26-31 are A15-A20
#endif
} else if (pin >= 34 && pin <= 40) {
index = pin - 24; // 34-37 are A10-A13, 38 is temp sensor,
// 39 is vref, 40 is unused (A14 on Teensy 3.1)
} else {
return 0; // all others are invalid
}
//serial_phex(index);
//serial_print(" ");
channel = channel2sc1a[index];
//serial_phex(channel);
//serial_print(" ");
//serial_print("analogRead");
//return 0;
if (calibrating) wait_for_cal();
//pin = 5; // PTD1/SE5b, pin 14, analog 0
#if defined(__MK20DX256__)
if (channel & 0x80) goto beginADC1;
#endif
__disable_irq();
startADC0:
//serial_print("startADC0\n");
ADC0_SC1A = channel;
analogReadBusyADC0 = 1;
__enable_irq();
while (1) {
__disable_irq();
if ((ADC0_SC1A & ADC_SC1_COCO)) {
result = ADC0_RA;
analogReadBusyADC0 = 0;
__enable_irq();
result >>= analog_right_shift;
return result;
}
// detect if analogRead was used from an interrupt
// if so, our analogRead got canceled, so it must
// be restarted.
if (!analogReadBusyADC0) goto startADC0;
__enable_irq();
yield();
}
#if defined(__MK20DX256__)
beginADC1:
__disable_irq();
startADC1:
//serial_print("startADC0\n");
// ADC1_CFG2[MUXSEL] bit selects between ADCx_SEn channels a and b.
if (channel & 0x40) {
ADC1_CFG2 &= ~ADC_CFG2_MUXSEL;
} else {
ADC1_CFG2 |= ADC_CFG2_MUXSEL;
}
ADC1_SC1A = channel & 0x3F;
analogReadBusyADC1 = 1;
__enable_irq();
while (1) {
__disable_irq();
if ((ADC1_SC1A & ADC_SC1_COCO)) {
result = ADC1_RA;
analogReadBusyADC1 = 0;
__enable_irq();
result >>= analog_right_shift;
return result;
}
// detect if analogRead was used from an interrupt
// if so, our analogRead got canceled, so it must
// be restarted.
if (!analogReadBusyADC1) goto startADC1;
__enable_irq();
yield();
}
#endif
}
void analogWriteDAC0(int val)
{
#if defined(__MK20DX256__)
SIM_SCGC2 |= SIM_SCGC2_DAC0;
if (analog_reference_internal) {
DAC0_C0 = DAC_C0_DACEN; // 1.2V ref is DACREF_1
} else {
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2
}
if (val < 0) val = 0; // TODO: saturate instruction?
else if (val > 4095) val = 4095;
*(int16_t *)&(DAC0_DAT0L) = val;
#endif
}

107
teensy/core/avr_functions.h Normal file
View File

@ -0,0 +1,107 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _avr_functions_h_
#define _avr_functions_h_
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
void eeprom_initialize(void);
uint8_t eeprom_read_byte(const uint8_t *addr) __attribute__ ((pure));
uint16_t eeprom_read_word(const uint16_t *addr) __attribute__ ((pure));
uint32_t eeprom_read_dword(const uint32_t *addr) __attribute__ ((pure));
void eeprom_read_block(void *buf, const void *addr, uint32_t len);
void eeprom_write_byte(uint8_t *addr, uint8_t value);
void eeprom_write_word(uint16_t *addr, uint16_t value);
void eeprom_write_dword(uint32_t *addr, uint32_t value);
void eeprom_write_block(const void *buf, void *addr, uint32_t len);
int eeprom_is_ready(void);
#define eeprom_busy_wait() do {} while (!eeprom_is_ready())
static inline float eeprom_read_float(const float *addr) __attribute__((pure, always_inline, unused));
static inline float eeprom_read_float(const float *addr)
{
union {float f; uint32_t u32;} u;
u.u32 = eeprom_read_dword((const uint32_t *)addr);
return u.f;
}
static inline void eeprom_write_float(float *addr, float value) __attribute__((always_inline, unused));
static inline void eeprom_write_float(float *addr, float value)
{
union {float f; uint32_t u32;} u;
u.f = value;
eeprom_write_dword((uint32_t *)addr, u.u32);
}
static inline void eeprom_update_byte(uint8_t *addr, uint8_t value) __attribute__((always_inline, unused));
static inline void eeprom_update_byte(uint8_t *addr, uint8_t value)
{
eeprom_write_byte(addr, value);
}
static inline void eeprom_update_word(uint16_t *addr, uint16_t value) __attribute__((always_inline, unused));
static inline void eeprom_update_word(uint16_t *addr, uint16_t value)
{
eeprom_write_word(addr, value);
}
static inline void eeprom_update_dword(uint32_t *addr, uint32_t value) __attribute__((always_inline, unused));
static inline void eeprom_update_dword(uint32_t *addr, uint32_t value)
{
eeprom_write_dword(addr, value);
}
static inline void eeprom_update_float(float *addr, float value) __attribute__((always_inline, unused));
static inline void eeprom_update_float(float *addr, float value)
{
union {float f; uint32_t u32;} u;
u.f = value;
eeprom_write_dword((uint32_t *)addr, u.u32);
}
static inline void eeprom_update_block(const void *buf, void *addr, uint32_t len) __attribute__((always_inline, unused));
static inline void eeprom_update_block(const void *buf, void *addr, uint32_t len)
{
eeprom_write_block(buf, addr, len);
}
char * ultoa(unsigned long val, char *buf, int radix);
char * ltoa(long val, char *buf, int radix);
static inline char * utoa(unsigned int val, char *buf, int radix) __attribute__((always_inline, unused));
static inline char * utoa(unsigned int val, char *buf, int radix) { return ultoa(val, buf, radix); }
static inline char * itoa(int val, char *buf, int radix) __attribute__((always_inline, unused));
static inline char * itoa(int val, char *buf, int radix) { return ltoa(val, buf, radix); }
char * dtostrf(float val, int width, unsigned int precision, char *buf);
#ifdef __cplusplus
}
#endif
#endif

841
teensy/core/core_pins.h Normal file
View File

@ -0,0 +1,841 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _core_pins_h_
#define _core_pins_h_
#include "mk20dx128.h"
#include "pins_arduino.h"
#define HIGH 1
#define LOW 0
#define INPUT 0
#define OUTPUT 1
#define INPUT_PULLUP 2
#define LSBFIRST 0
#define MSBFIRST 1
#define _BV(n) (1<<(n))
#define CHANGE 4
#define FALLING 2
#define RISING 3
// Pin Arduino
// 0 B16 RXD
// 1 B17 TXD
// 2 D0
// 3 A12 FTM1_CH0
// 4 A13 FTM1_CH1
// 5 D7 FTM0_CH7 OC0B/T1
// 6 D4 FTM0_CH4 OC0A
// 7 D2
// 8 D3 ICP1
// 9 C3 FTM0_CH2 OC1A
// 10 C4 FTM0_CH3 SS/OC1B
// 11 C6 MOSI/OC2A
// 12 C7 MISO
// 13 C5 SCK
// 14 D1
// 15 C0
// 16 B0 (FTM1_CH0)
// 17 B1 (FTM1_CH1)
// 18 B3 SDA
// 19 B2 SCL
// 20 D5 FTM0_CH5
// 21 D6 FTM0_CH6
// 22 C1 FTM0_CH0
// 23 C2 FTM0_CH1
// 24 A5 (FTM0_CH2)
// 25 B19
// 26 E1
// 27 C9
// 28 C8
// 29 C10
// 30 C11
// 31 E0
// 32 B18
// 33 A4 (FTM0_CH1)
// (34) analog only
// (35) analog only
// (36) analog only
// (37) analog only
// not available to user:
// A0 FTM0_CH5 SWD Clock
// A1 FTM0_CH6 USB ID
// A2 FTM0_CH7 SWD Trace
// A3 FTM0_CH0 SWD Data
#define CORE_NUM_TOTAL_PINS 34
#define CORE_NUM_DIGITAL 34
#define CORE_NUM_INTERRUPT 34
#if defined(__MK20DX128__)
#define CORE_NUM_ANALOG 14
#define CORE_NUM_PWM 10
#elif defined(__MK20DX256__)
#define CORE_NUM_ANALOG 21
#define CORE_NUM_PWM 12
#endif
#define CORE_PIN0_BIT 16
#define CORE_PIN1_BIT 17
#define CORE_PIN2_BIT 0
#define CORE_PIN3_BIT 12
#define CORE_PIN4_BIT 13
#define CORE_PIN5_BIT 7
#define CORE_PIN6_BIT 4
#define CORE_PIN7_BIT 2
#define CORE_PIN8_BIT 3
#define CORE_PIN9_BIT 3
#define CORE_PIN10_BIT 4
#define CORE_PIN11_BIT 6
#define CORE_PIN12_BIT 7
#define CORE_PIN13_BIT 5
#define CORE_PIN14_BIT 1
#define CORE_PIN15_BIT 0
#define CORE_PIN16_BIT 0
#define CORE_PIN17_BIT 1
#define CORE_PIN18_BIT 3
#define CORE_PIN19_BIT 2
#define CORE_PIN20_BIT 5
#define CORE_PIN21_BIT 6
#define CORE_PIN22_BIT 1
#define CORE_PIN23_BIT 2
#define CORE_PIN24_BIT 5
#define CORE_PIN25_BIT 19
#define CORE_PIN26_BIT 1
#define CORE_PIN27_BIT 9
#define CORE_PIN28_BIT 8
#define CORE_PIN29_BIT 10
#define CORE_PIN30_BIT 11
#define CORE_PIN31_BIT 0
#define CORE_PIN32_BIT 18
#define CORE_PIN33_BIT 4
#define CORE_PIN0_BITMASK (1<<(CORE_PIN0_BIT))
#define CORE_PIN1_BITMASK (1<<(CORE_PIN1_BIT))
#define CORE_PIN2_BITMASK (1<<(CORE_PIN2_BIT))
#define CORE_PIN3_BITMASK (1<<(CORE_PIN3_BIT))
#define CORE_PIN4_BITMASK (1<<(CORE_PIN4_BIT))
#define CORE_PIN5_BITMASK (1<<(CORE_PIN5_BIT))
#define CORE_PIN6_BITMASK (1<<(CORE_PIN6_BIT))
#define CORE_PIN7_BITMASK (1<<(CORE_PIN7_BIT))
#define CORE_PIN8_BITMASK (1<<(CORE_PIN8_BIT))
#define CORE_PIN9_BITMASK (1<<(CORE_PIN9_BIT))
#define CORE_PIN10_BITMASK (1<<(CORE_PIN10_BIT))
#define CORE_PIN11_BITMASK (1<<(CORE_PIN11_BIT))
#define CORE_PIN12_BITMASK (1<<(CORE_PIN12_BIT))
#define CORE_PIN13_BITMASK (1<<(CORE_PIN13_BIT))
#define CORE_PIN14_BITMASK (1<<(CORE_PIN14_BIT))
#define CORE_PIN15_BITMASK (1<<(CORE_PIN15_BIT))
#define CORE_PIN16_BITMASK (1<<(CORE_PIN16_BIT))
#define CORE_PIN17_BITMASK (1<<(CORE_PIN17_BIT))
#define CORE_PIN18_BITMASK (1<<(CORE_PIN18_BIT))
#define CORE_PIN19_BITMASK (1<<(CORE_PIN19_BIT))
#define CORE_PIN20_BITMASK (1<<(CORE_PIN20_BIT))
#define CORE_PIN21_BITMASK (1<<(CORE_PIN21_BIT))
#define CORE_PIN22_BITMASK (1<<(CORE_PIN22_BIT))
#define CORE_PIN23_BITMASK (1<<(CORE_PIN23_BIT))
#define CORE_PIN24_BITMASK (1<<(CORE_PIN24_BIT))
#define CORE_PIN25_BITMASK (1<<(CORE_PIN25_BIT))
#define CORE_PIN26_BITMASK (1<<(CORE_PIN26_BIT))
#define CORE_PIN27_BITMASK (1<<(CORE_PIN27_BIT))
#define CORE_PIN28_BITMASK (1<<(CORE_PIN28_BIT))
#define CORE_PIN29_BITMASK (1<<(CORE_PIN29_BIT))
#define CORE_PIN30_BITMASK (1<<(CORE_PIN30_BIT))
#define CORE_PIN31_BITMASK (1<<(CORE_PIN31_BIT))
#define CORE_PIN32_BITMASK (1<<(CORE_PIN32_BIT))
#define CORE_PIN33_BITMASK (1<<(CORE_PIN33_BIT))
#define CORE_PIN0_PORTREG GPIOB_PDOR
#define CORE_PIN1_PORTREG GPIOB_PDOR
#define CORE_PIN2_PORTREG GPIOD_PDOR
#define CORE_PIN3_PORTREG GPIOA_PDOR
#define CORE_PIN4_PORTREG GPIOA_PDOR
#define CORE_PIN5_PORTREG GPIOD_PDOR
#define CORE_PIN6_PORTREG GPIOD_PDOR
#define CORE_PIN7_PORTREG GPIOD_PDOR
#define CORE_PIN8_PORTREG GPIOD_PDOR
#define CORE_PIN9_PORTREG GPIOC_PDOR
#define CORE_PIN10_PORTREG GPIOC_PDOR
#define CORE_PIN11_PORTREG GPIOC_PDOR
#define CORE_PIN12_PORTREG GPIOC_PDOR
#define CORE_PIN13_PORTREG GPIOC_PDOR
#define CORE_PIN14_PORTREG GPIOD_PDOR
#define CORE_PIN15_PORTREG GPIOC_PDOR
#define CORE_PIN16_PORTREG GPIOB_PDOR
#define CORE_PIN17_PORTREG GPIOB_PDOR
#define CORE_PIN18_PORTREG GPIOB_PDOR
#define CORE_PIN19_PORTREG GPIOB_PDOR
#define CORE_PIN20_PORTREG GPIOD_PDOR
#define CORE_PIN21_PORTREG GPIOD_PDOR
#define CORE_PIN22_PORTREG GPIOC_PDOR
#define CORE_PIN23_PORTREG GPIOC_PDOR
#define CORE_PIN24_PORTREG GPIOA_PDOR
#define CORE_PIN25_PORTREG GPIOB_PDOR
#define CORE_PIN26_PORTREG GPIOE_PDOR
#define CORE_PIN27_PORTREG GPIOC_PDOR
#define CORE_PIN28_PORTREG GPIOC_PDOR
#define CORE_PIN29_PORTREG GPIOC_PDOR
#define CORE_PIN30_PORTREG GPIOC_PDOR
#define CORE_PIN31_PORTREG GPIOE_PDOR
#define CORE_PIN32_PORTREG GPIOB_PDOR
#define CORE_PIN33_PORTREG GPIOA_PDOR
#define CORE_PIN0_PORTSET GPIOB_PSOR
#define CORE_PIN1_PORTSET GPIOB_PSOR
#define CORE_PIN2_PORTSET GPIOD_PSOR
#define CORE_PIN3_PORTSET GPIOA_PSOR
#define CORE_PIN4_PORTSET GPIOA_PSOR
#define CORE_PIN5_PORTSET GPIOD_PSOR
#define CORE_PIN6_PORTSET GPIOD_PSOR
#define CORE_PIN7_PORTSET GPIOD_PSOR
#define CORE_PIN8_PORTSET GPIOD_PSOR
#define CORE_PIN9_PORTSET GPIOC_PSOR
#define CORE_PIN10_PORTSET GPIOC_PSOR
#define CORE_PIN11_PORTSET GPIOC_PSOR
#define CORE_PIN12_PORTSET GPIOC_PSOR
#define CORE_PIN13_PORTSET GPIOC_PSOR
#define CORE_PIN14_PORTSET GPIOD_PSOR
#define CORE_PIN15_PORTSET GPIOC_PSOR
#define CORE_PIN16_PORTSET GPIOB_PSOR
#define CORE_PIN17_PORTSET GPIOB_PSOR
#define CORE_PIN18_PORTSET GPIOB_PSOR
#define CORE_PIN19_PORTSET GPIOB_PSOR
#define CORE_PIN20_PORTSET GPIOD_PSOR
#define CORE_PIN21_PORTSET GPIOD_PSOR
#define CORE_PIN22_PORTSET GPIOC_PSOR
#define CORE_PIN23_PORTSET GPIOC_PSOR
#define CORE_PIN24_PORTSET GPIOA_PSOR
#define CORE_PIN25_PORTSET GPIOB_PSOR
#define CORE_PIN26_PORTSET GPIOE_PSOR
#define CORE_PIN27_PORTSET GPIOC_PSOR
#define CORE_PIN28_PORTSET GPIOC_PSOR
#define CORE_PIN29_PORTSET GPIOC_PSOR
#define CORE_PIN30_PORTSET GPIOC_PSOR
#define CORE_PIN31_PORTSET GPIOE_PSOR
#define CORE_PIN32_PORTSET GPIOB_PSOR
#define CORE_PIN33_PORTSET GPIOA_PSOR
#define CORE_PIN0_PORTCLEAR GPIOB_PCOR
#define CORE_PIN1_PORTCLEAR GPIOB_PCOR
#define CORE_PIN2_PORTCLEAR GPIOD_PCOR
#define CORE_PIN3_PORTCLEAR GPIOA_PCOR
#define CORE_PIN4_PORTCLEAR GPIOA_PCOR
#define CORE_PIN5_PORTCLEAR GPIOD_PCOR
#define CORE_PIN6_PORTCLEAR GPIOD_PCOR
#define CORE_PIN7_PORTCLEAR GPIOD_PCOR
#define CORE_PIN8_PORTCLEAR GPIOD_PCOR
#define CORE_PIN9_PORTCLEAR GPIOC_PCOR
#define CORE_PIN10_PORTCLEAR GPIOC_PCOR
#define CORE_PIN11_PORTCLEAR GPIOC_PCOR
#define CORE_PIN12_PORTCLEAR GPIOC_PCOR
#define CORE_PIN13_PORTCLEAR GPIOC_PCOR
#define CORE_PIN14_PORTCLEAR GPIOD_PCOR
#define CORE_PIN15_PORTCLEAR GPIOC_PCOR
#define CORE_PIN16_PORTCLEAR GPIOB_PCOR
#define CORE_PIN17_PORTCLEAR GPIOB_PCOR
#define CORE_PIN18_PORTCLEAR GPIOB_PCOR
#define CORE_PIN19_PORTCLEAR GPIOB_PCOR
#define CORE_PIN20_PORTCLEAR GPIOD_PCOR
#define CORE_PIN21_PORTCLEAR GPIOD_PCOR
#define CORE_PIN22_PORTCLEAR GPIOC_PCOR
#define CORE_PIN23_PORTCLEAR GPIOC_PCOR
#define CORE_PIN24_PORTCLEAR GPIOA_PCOR
#define CORE_PIN25_PORTCLEAR GPIOB_PCOR
#define CORE_PIN26_PORTCLEAR GPIOE_PCOR
#define CORE_PIN27_PORTCLEAR GPIOC_PCOR
#define CORE_PIN28_PORTCLEAR GPIOC_PCOR
#define CORE_PIN29_PORTCLEAR GPIOC_PCOR
#define CORE_PIN30_PORTCLEAR GPIOC_PCOR
#define CORE_PIN31_PORTCLEAR GPIOE_PCOR
#define CORE_PIN32_PORTCLEAR GPIOB_PCOR
#define CORE_PIN33_PORTCLEAR GPIOA_PCOR
#define CORE_PIN0_DDRREG GPIOB_PDDR
#define CORE_PIN1_DDRREG GPIOB_PDDR
#define CORE_PIN2_DDRREG GPIOD_PDDR
#define CORE_PIN3_DDRREG GPIOA_PDDR
#define CORE_PIN4_DDRREG GPIOA_PDDR
#define CORE_PIN5_DDRREG GPIOD_PDDR
#define CORE_PIN6_DDRREG GPIOD_PDDR
#define CORE_PIN7_DDRREG GPIOD_PDDR
#define CORE_PIN8_DDRREG GPIOD_PDDR
#define CORE_PIN9_DDRREG GPIOC_PDDR
#define CORE_PIN10_DDRREG GPIOC_PDDR
#define CORE_PIN11_DDRREG GPIOC_PDDR
#define CORE_PIN12_DDRREG GPIOC_PDDR
#define CORE_PIN13_DDRREG GPIOC_PDDR
#define CORE_PIN14_DDRREG GPIOD_PDDR
#define CORE_PIN15_DDRREG GPIOC_PDDR
#define CORE_PIN16_DDRREG GPIOB_PDDR
#define CORE_PIN17_DDRREG GPIOB_PDDR
#define CORE_PIN18_DDRREG GPIOB_PDDR
#define CORE_PIN19_DDRREG GPIOB_PDDR
#define CORE_PIN20_DDRREG GPIOD_PDDR
#define CORE_PIN21_DDRREG GPIOD_PDDR
#define CORE_PIN22_DDRREG GPIOC_PDDR
#define CORE_PIN23_DDRREG GPIOC_PDDR
#define CORE_PIN24_DDRREG GPIOA_PDDR
#define CORE_PIN25_DDRREG GPIOB_PDDR
#define CORE_PIN26_DDRREG GPIOE_PDDR
#define CORE_PIN27_DDRREG GPIOC_PDDR
#define CORE_PIN28_DDRREG GPIOC_PDDR
#define CORE_PIN29_DDRREG GPIOC_PDDR
#define CORE_PIN30_DDRREG GPIOC_PDDR
#define CORE_PIN31_DDRREG GPIOE_PDDR
#define CORE_PIN32_DDRREG GPIOB_PDDR
#define CORE_PIN33_DDRREG GPIOA_PDDR
#define CORE_PIN0_PINREG GPIOB_PDIR
#define CORE_PIN1_PINREG GPIOB_PDIR
#define CORE_PIN2_PINREG GPIOD_PDIR
#define CORE_PIN3_PINREG GPIOA_PDIR
#define CORE_PIN4_PINREG GPIOA_PDIR
#define CORE_PIN5_PINREG GPIOD_PDIR
#define CORE_PIN6_PINREG GPIOD_PDIR
#define CORE_PIN7_PINREG GPIOD_PDIR
#define CORE_PIN8_PINREG GPIOD_PDIR
#define CORE_PIN9_PINREG GPIOC_PDIR
#define CORE_PIN10_PINREG GPIOC_PDIR
#define CORE_PIN11_PINREG GPIOC_PDIR
#define CORE_PIN12_PINREG GPIOC_PDIR
#define CORE_PIN13_PINREG GPIOC_PDIR
#define CORE_PIN14_PINREG GPIOD_PDIR
#define CORE_PIN15_PINREG GPIOC_PDIR
#define CORE_PIN16_PINREG GPIOB_PDIR
#define CORE_PIN17_PINREG GPIOB_PDIR
#define CORE_PIN18_PINREG GPIOB_PDIR
#define CORE_PIN19_PINREG GPIOB_PDIR
#define CORE_PIN20_PINREG GPIOD_PDIR
#define CORE_PIN21_PINREG GPIOD_PDIR
#define CORE_PIN22_PINREG GPIOC_PDIR
#define CORE_PIN23_PINREG GPIOC_PDIR
#define CORE_PIN24_PINREG GPIOA_PDIR
#define CORE_PIN25_PINREG GPIOB_PDIR
#define CORE_PIN26_PINREG GPIOE_PDIR
#define CORE_PIN27_PINREG GPIOC_PDIR
#define CORE_PIN28_PINREG GPIOC_PDIR
#define CORE_PIN29_PINREG GPIOC_PDIR
#define CORE_PIN30_PINREG GPIOC_PDIR
#define CORE_PIN31_PINREG GPIOE_PDIR
#define CORE_PIN32_PINREG GPIOB_PDIR
#define CORE_PIN33_PINREG GPIOA_PDIR
#define CORE_PIN0_CONFIG PORTB_PCR16
#define CORE_PIN1_CONFIG PORTB_PCR17
#define CORE_PIN2_CONFIG PORTD_PCR0
#define CORE_PIN3_CONFIG PORTA_PCR12
#define CORE_PIN4_CONFIG PORTA_PCR13
#define CORE_PIN5_CONFIG PORTD_PCR7
#define CORE_PIN6_CONFIG PORTD_PCR4
#define CORE_PIN7_CONFIG PORTD_PCR2
#define CORE_PIN8_CONFIG PORTD_PCR3
#define CORE_PIN9_CONFIG PORTC_PCR3
#define CORE_PIN10_CONFIG PORTC_PCR4
#define CORE_PIN11_CONFIG PORTC_PCR6
#define CORE_PIN12_CONFIG PORTC_PCR7
#define CORE_PIN13_CONFIG PORTC_PCR5
#define CORE_PIN14_CONFIG PORTD_PCR1
#define CORE_PIN15_CONFIG PORTC_PCR0
#define CORE_PIN16_CONFIG PORTB_PCR0
#define CORE_PIN17_CONFIG PORTB_PCR1
#define CORE_PIN18_CONFIG PORTB_PCR3
#define CORE_PIN19_CONFIG PORTB_PCR2
#define CORE_PIN20_CONFIG PORTD_PCR5
#define CORE_PIN21_CONFIG PORTD_PCR6
#define CORE_PIN22_CONFIG PORTC_PCR1
#define CORE_PIN23_CONFIG PORTC_PCR2
#define CORE_PIN24_CONFIG PORTA_PCR5
#define CORE_PIN25_CONFIG PORTB_PCR19
#define CORE_PIN26_CONFIG PORTE_PCR1
#define CORE_PIN27_CONFIG PORTC_PCR9
#define CORE_PIN28_CONFIG PORTC_PCR8
#define CORE_PIN29_CONFIG PORTC_PCR10
#define CORE_PIN30_CONFIG PORTC_PCR11
#define CORE_PIN31_CONFIG PORTE_PCR0
#define CORE_PIN32_CONFIG PORTB_PCR18
#define CORE_PIN33_CONFIG PORTA_PCR4
#define CORE_ADC0_PIN 14
#define CORE_ADC1_PIN 15
#define CORE_ADC2_PIN 16
#define CORE_ADC3_PIN 17
#define CORE_ADC4_PIN 18
#define CORE_ADC5_PIN 19
#define CORE_ADC6_PIN 20
#define CORE_ADC7_PIN 21
#define CORE_ADC8_PIN 22
#define CORE_ADC9_PIN 23
#define CORE_ADC10_PIN 34
#define CORE_ADC11_PIN 35
#define CORE_ADC12_PIN 36
#define CORE_ADC13_PIN 37
#define CORE_RXD0_PIN 0
#define CORE_TXD0_PIN 1
#define CORE_RXD1_PIN 9
#define CORE_TXD1_PIN 10
#define CORE_RXD2_PIN 7
#define CORE_TXD2_PIN 8
#define CORE_INT0_PIN 0
#define CORE_INT1_PIN 1
#define CORE_INT2_PIN 2
#define CORE_INT3_PIN 3
#define CORE_INT4_PIN 4
#define CORE_INT5_PIN 5
#define CORE_INT6_PIN 6
#define CORE_INT7_PIN 7
#define CORE_INT8_PIN 8
#define CORE_INT9_PIN 9
#define CORE_INT10_PIN 10
#define CORE_INT11_PIN 11
#define CORE_INT12_PIN 12
#define CORE_INT13_PIN 13
#define CORE_INT14_PIN 14
#define CORE_INT15_PIN 15
#define CORE_INT16_PIN 16
#define CORE_INT17_PIN 17
#define CORE_INT18_PIN 18
#define CORE_INT19_PIN 19
#define CORE_INT20_PIN 20
#define CORE_INT21_PIN 21
#define CORE_INT22_PIN 22
#define CORE_INT23_PIN 23
#define CORE_INT24_PIN 24
#define CORE_INT25_PIN 25
#define CORE_INT26_PIN 26
#define CORE_INT27_PIN 27
#define CORE_INT28_PIN 28
#define CORE_INT29_PIN 29
#define CORE_INT30_PIN 30
#define CORE_INT31_PIN 31
#define CORE_INT32_PIN 32
#define CORE_INT33_PIN 33
#define CORE_INT_EVERY_PIN 1
#ifdef __cplusplus
extern "C" {
#endif
void digitalWrite(uint8_t pin, uint8_t val);
static inline void digitalWriteFast(uint8_t pin, uint8_t val) __attribute__((always_inline, unused));
static inline void digitalWriteFast(uint8_t pin, uint8_t val)
{
if (__builtin_constant_p(pin)) {
if (val) {
if (pin == 0) {
CORE_PIN0_PORTSET = CORE_PIN0_BITMASK;
} else if (pin == 1) {
CORE_PIN1_PORTSET = CORE_PIN1_BITMASK;
} else if (pin == 2) {
CORE_PIN2_PORTSET = CORE_PIN2_BITMASK;
} else if (pin == 3) {
CORE_PIN3_PORTSET = CORE_PIN3_BITMASK;
} else if (pin == 4) {
CORE_PIN4_PORTSET = CORE_PIN4_BITMASK;
} else if (pin == 5) {
CORE_PIN5_PORTSET = CORE_PIN5_BITMASK;
} else if (pin == 6) {
CORE_PIN6_PORTSET = CORE_PIN6_BITMASK;
} else if (pin == 7) {
CORE_PIN7_PORTSET = CORE_PIN7_BITMASK;
} else if (pin == 8) {
CORE_PIN8_PORTSET = CORE_PIN8_BITMASK;
} else if (pin == 9) {
CORE_PIN9_PORTSET = CORE_PIN9_BITMASK;
} else if (pin == 10) {
CORE_PIN10_PORTSET = CORE_PIN10_BITMASK;
} else if (pin == 11) {
CORE_PIN11_PORTSET = CORE_PIN11_BITMASK;
} else if (pin == 12) {
CORE_PIN12_PORTSET = CORE_PIN12_BITMASK;
} else if (pin == 13) {
CORE_PIN13_PORTSET = CORE_PIN13_BITMASK;
} else if (pin == 14) {
CORE_PIN14_PORTSET = CORE_PIN14_BITMASK;
} else if (pin == 15) {
CORE_PIN15_PORTSET = CORE_PIN15_BITMASK;
} else if (pin == 16) {
CORE_PIN16_PORTSET = CORE_PIN16_BITMASK;
} else if (pin == 17) {
CORE_PIN17_PORTSET = CORE_PIN17_BITMASK;
} else if (pin == 18) {
CORE_PIN18_PORTSET = CORE_PIN18_BITMASK;
} else if (pin == 19) {
CORE_PIN19_PORTSET = CORE_PIN19_BITMASK;
} else if (pin == 20) {
CORE_PIN20_PORTSET = CORE_PIN20_BITMASK;
} else if (pin == 21) {
CORE_PIN21_PORTSET = CORE_PIN21_BITMASK;
} else if (pin == 22) {
CORE_PIN22_PORTSET = CORE_PIN22_BITMASK;
} else if (pin == 23) {
CORE_PIN23_PORTSET = CORE_PIN23_BITMASK;
} else if (pin == 24) {
CORE_PIN24_PORTSET = CORE_PIN24_BITMASK;
} else if (pin == 25) {
CORE_PIN25_PORTSET = CORE_PIN25_BITMASK;
} else if (pin == 26) {
CORE_PIN26_PORTSET = CORE_PIN26_BITMASK;
} else if (pin == 27) {
CORE_PIN27_PORTSET = CORE_PIN27_BITMASK;
} else if (pin == 28) {
CORE_PIN28_PORTSET = CORE_PIN28_BITMASK;
} else if (pin == 29) {
CORE_PIN29_PORTSET = CORE_PIN29_BITMASK;
} else if (pin == 30) {
CORE_PIN30_PORTSET = CORE_PIN30_BITMASK;
} else if (pin == 31) {
CORE_PIN31_PORTSET = CORE_PIN31_BITMASK;
} else if (pin == 32) {
CORE_PIN32_PORTSET = CORE_PIN32_BITMASK;
} else if (pin == 33) {
CORE_PIN33_PORTSET = CORE_PIN33_BITMASK;
}
} else {
if (pin == 0) {
CORE_PIN0_PORTCLEAR = CORE_PIN0_BITMASK;
} else if (pin == 1) {
CORE_PIN1_PORTCLEAR = CORE_PIN1_BITMASK;
} else if (pin == 2) {
CORE_PIN2_PORTCLEAR = CORE_PIN2_BITMASK;
} else if (pin == 3) {
CORE_PIN3_PORTCLEAR = CORE_PIN3_BITMASK;
} else if (pin == 4) {
CORE_PIN4_PORTCLEAR = CORE_PIN4_BITMASK;
} else if (pin == 5) {
CORE_PIN5_PORTCLEAR = CORE_PIN5_BITMASK;
} else if (pin == 6) {
CORE_PIN6_PORTCLEAR = CORE_PIN6_BITMASK;
} else if (pin == 7) {
CORE_PIN7_PORTCLEAR = CORE_PIN7_BITMASK;
} else if (pin == 8) {
CORE_PIN8_PORTCLEAR = CORE_PIN8_BITMASK;
} else if (pin == 9) {
CORE_PIN9_PORTCLEAR = CORE_PIN9_BITMASK;
} else if (pin == 10) {
CORE_PIN10_PORTCLEAR = CORE_PIN10_BITMASK;
} else if (pin == 11) {
CORE_PIN11_PORTCLEAR = CORE_PIN11_BITMASK;
} else if (pin == 12) {
CORE_PIN12_PORTCLEAR = CORE_PIN12_BITMASK;
} else if (pin == 13) {
CORE_PIN13_PORTCLEAR = CORE_PIN13_BITMASK;
} else if (pin == 14) {
CORE_PIN14_PORTCLEAR = CORE_PIN14_BITMASK;
} else if (pin == 15) {
CORE_PIN15_PORTCLEAR = CORE_PIN15_BITMASK;
} else if (pin == 16) {
CORE_PIN16_PORTCLEAR = CORE_PIN16_BITMASK;
} else if (pin == 17) {
CORE_PIN17_PORTCLEAR = CORE_PIN17_BITMASK;
} else if (pin == 18) {
CORE_PIN18_PORTCLEAR = CORE_PIN18_BITMASK;
} else if (pin == 19) {
CORE_PIN19_PORTCLEAR = CORE_PIN19_BITMASK;
} else if (pin == 20) {
CORE_PIN20_PORTCLEAR = CORE_PIN20_BITMASK;
} else if (pin == 21) {
CORE_PIN21_PORTCLEAR = CORE_PIN21_BITMASK;
} else if (pin == 22) {
CORE_PIN22_PORTCLEAR = CORE_PIN22_BITMASK;
} else if (pin == 23) {
CORE_PIN23_PORTCLEAR = CORE_PIN23_BITMASK;
} else if (pin == 24) {
CORE_PIN24_PORTCLEAR = CORE_PIN24_BITMASK;
} else if (pin == 25) {
CORE_PIN25_PORTCLEAR = CORE_PIN25_BITMASK;
} else if (pin == 26) {
CORE_PIN26_PORTCLEAR = CORE_PIN26_BITMASK;
} else if (pin == 27) {
CORE_PIN27_PORTCLEAR = CORE_PIN27_BITMASK;
} else if (pin == 28) {
CORE_PIN28_PORTCLEAR = CORE_PIN28_BITMASK;
} else if (pin == 29) {
CORE_PIN29_PORTCLEAR = CORE_PIN29_BITMASK;
} else if (pin == 30) {
CORE_PIN30_PORTCLEAR = CORE_PIN30_BITMASK;
} else if (pin == 31) {
CORE_PIN31_PORTCLEAR = CORE_PIN31_BITMASK;
} else if (pin == 32) {
CORE_PIN32_PORTCLEAR = CORE_PIN32_BITMASK;
} else if (pin == 33) {
CORE_PIN33_PORTCLEAR = CORE_PIN33_BITMASK;
}
}
} else {
if (val) {
*portSetRegister(pin) = 1;
} else {
*portClearRegister(pin) = 1;
}
}
}
uint8_t digitalRead(uint8_t pin);
static inline uint8_t digitalReadFast(uint8_t pin) __attribute__((always_inline, unused));
static inline uint8_t digitalReadFast(uint8_t pin)
{
if (__builtin_constant_p(pin)) {
if (pin == 0) {
return (CORE_PIN0_PINREG & CORE_PIN0_BITMASK) ? 1 : 0;
} else if (pin == 1) {
return (CORE_PIN1_PINREG & CORE_PIN1_BITMASK) ? 1 : 0;
} else if (pin == 2) {
return (CORE_PIN2_PINREG & CORE_PIN2_BITMASK) ? 1 : 0;
} else if (pin == 3) {
return (CORE_PIN3_PINREG & CORE_PIN3_BITMASK) ? 1 : 0;
} else if (pin == 4) {
return (CORE_PIN4_PINREG & CORE_PIN4_BITMASK) ? 1 : 0;
} else if (pin == 5) {
return (CORE_PIN5_PINREG & CORE_PIN5_BITMASK) ? 1 : 0;
} else if (pin == 6) {
return (CORE_PIN6_PINREG & CORE_PIN6_BITMASK) ? 1 : 0;
} else if (pin == 7) {
return (CORE_PIN7_PINREG & CORE_PIN7_BITMASK) ? 1 : 0;
} else if (pin == 8) {
return (CORE_PIN8_PINREG & CORE_PIN8_BITMASK) ? 1 : 0;
} else if (pin == 9) {
return (CORE_PIN9_PINREG & CORE_PIN9_BITMASK) ? 1 : 0;
} else if (pin == 10) {
return (CORE_PIN10_PINREG & CORE_PIN10_BITMASK) ? 1 : 0;
} else if (pin == 11) {
return (CORE_PIN11_PINREG & CORE_PIN11_BITMASK) ? 1 : 0;
} else if (pin == 12) {
return (CORE_PIN12_PINREG & CORE_PIN12_BITMASK) ? 1 : 0;
} else if (pin == 13) {
return (CORE_PIN13_PINREG & CORE_PIN13_BITMASK) ? 1 : 0;
} else if (pin == 14) {
return (CORE_PIN14_PINREG & CORE_PIN14_BITMASK) ? 1 : 0;
} else if (pin == 15) {
return (CORE_PIN15_PINREG & CORE_PIN15_BITMASK) ? 1 : 0;
} else if (pin == 16) {
return (CORE_PIN16_PINREG & CORE_PIN16_BITMASK) ? 1 : 0;
} else if (pin == 17) {
return (CORE_PIN17_PINREG & CORE_PIN17_BITMASK) ? 1 : 0;
} else if (pin == 18) {
return (CORE_PIN18_PINREG & CORE_PIN18_BITMASK) ? 1 : 0;
} else if (pin == 19) {
return (CORE_PIN19_PINREG & CORE_PIN19_BITMASK) ? 1 : 0;
} else if (pin == 20) {
return (CORE_PIN20_PINREG & CORE_PIN20_BITMASK) ? 1 : 0;
} else if (pin == 21) {
return (CORE_PIN21_PINREG & CORE_PIN21_BITMASK) ? 1 : 0;
} else if (pin == 22) {
return (CORE_PIN22_PINREG & CORE_PIN22_BITMASK) ? 1 : 0;
} else if (pin == 23) {
return (CORE_PIN23_PINREG & CORE_PIN23_BITMASK) ? 1 : 0;
} else if (pin == 24) {
return (CORE_PIN24_PINREG & CORE_PIN24_BITMASK) ? 1 : 0;
} else if (pin == 25) {
return (CORE_PIN25_PINREG & CORE_PIN25_BITMASK) ? 1 : 0;
} else if (pin == 26) {
return (CORE_PIN26_PINREG & CORE_PIN26_BITMASK) ? 1 : 0;
} else if (pin == 27) {
return (CORE_PIN27_PINREG & CORE_PIN27_BITMASK) ? 1 : 0;
} else if (pin == 28) {
return (CORE_PIN28_PINREG & CORE_PIN28_BITMASK) ? 1 : 0;
} else if (pin == 29) {
return (CORE_PIN29_PINREG & CORE_PIN29_BITMASK) ? 1 : 0;
} else if (pin == 30) {
return (CORE_PIN30_PINREG & CORE_PIN30_BITMASK) ? 1 : 0;
} else if (pin == 31) {
return (CORE_PIN31_PINREG & CORE_PIN31_BITMASK) ? 1 : 0;
} else if (pin == 32) {
return (CORE_PIN32_PINREG & CORE_PIN32_BITMASK) ? 1 : 0;
} else if (pin == 33) {
return (CORE_PIN33_PINREG & CORE_PIN33_BITMASK) ? 1 : 0;
} else {
return 0;
}
} else {
return *portInputRegister(pin);
}
}
void pinMode(uint8_t pin, uint8_t mode);
void init_pins(void);
void analogWrite(uint8_t pin, int val);
void analogWriteRes(uint32_t bits);
static inline void analogWriteResolution(uint32_t bits) { analogWriteRes(bits); }
void analogWriteFrequency(uint8_t pin, uint32_t frequency);
void analogWriteDAC0(int val);
void attachInterrupt(uint8_t pin, void (*function)(void), int mode);
void detachInterrupt(uint8_t pin);
void _init_Teensyduino_internal_(void);
int analogRead(uint8_t pin);
void analogReference(uint8_t type);
void analogReadRes(unsigned int bits);
static inline void analogReadResolution(unsigned int bits) { analogReadRes(bits); }
void analogReadAveraging(unsigned int num);
void analog_init(void);
#define DEFAULT 0
#define INTERNAL 2
#define INTERNAL1V2 2
#define INTERNAL1V1 2
#define EXTERNAL 0
int touchRead(uint8_t pin);
static inline void shiftOut(uint8_t, uint8_t, uint8_t, uint8_t) __attribute__((always_inline, unused));
extern void _shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t value) __attribute__((noinline));
extern void shiftOut_lsbFirst(uint8_t dataPin, uint8_t clockPin, uint8_t value) __attribute__((noinline));
extern void shiftOut_msbFirst(uint8_t dataPin, uint8_t clockPin, uint8_t value) __attribute__((noinline));
static inline void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t value)
{
if (__builtin_constant_p(bitOrder)) {
if (bitOrder == LSBFIRST) {
shiftOut_lsbFirst(dataPin, clockPin, value);
} else {
shiftOut_msbFirst(dataPin, clockPin, value);
}
} else {
_shiftOut(dataPin, clockPin, bitOrder, value);
}
}
static inline uint8_t shiftIn(uint8_t, uint8_t, uint8_t) __attribute__((always_inline, unused));
extern uint8_t _shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) __attribute__((noinline));
extern uint8_t shiftIn_lsbFirst(uint8_t dataPin, uint8_t clockPin) __attribute__((noinline));
extern uint8_t shiftIn_msbFirst(uint8_t dataPin, uint8_t clockPin) __attribute__((noinline));
static inline uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder)
{
if (__builtin_constant_p(bitOrder)) {
if (bitOrder == LSBFIRST) {
return shiftIn_lsbFirst(dataPin, clockPin);
} else {
return shiftIn_msbFirst(dataPin, clockPin);
}
} else {
return _shiftIn(dataPin, clockPin, bitOrder);
}
}
void _reboot_Teensyduino_(void) __attribute__((noreturn));
void _restart_Teensyduino_(void) __attribute__((noreturn));
void yield(void);
void delay(uint32_t msec);
extern volatile uint32_t systick_millis_count;
static inline uint32_t millis(void) __attribute__((always_inline, unused));
static inline uint32_t millis(void)
{
volatile uint32_t ret = systick_millis_count; // single aligned 32 bit is atomic;
return ret;
}
uint32_t micros(void);
static inline void delayMicroseconds(uint32_t) __attribute__((always_inline, unused));
static inline void delayMicroseconds(uint32_t usec)
{
#if F_CPU == 168000000
uint32_t n = usec * 56;
#elif F_CPU == 144000000
uint32_t n = usec * 48;
#elif F_CPU == 120000000
uint32_t n = usec * 40;
#elif F_CPU == 96000000
uint32_t n = usec << 5;
#elif F_CPU == 72000000
uint32_t n = usec * 24;
#elif F_CPU == 48000000
uint32_t n = usec << 4;
#elif F_CPU == 24000000
uint32_t n = usec << 3;
#elif F_CPU == 16000000
uint32_t n = usec << 2;
#elif F_CPU == 8000000
uint32_t n = usec << 1;
#elif F_CPU == 4000000
uint32_t n = usec;
#elif F_CPU == 2000000
uint32_t n = usec >> 1;
#endif
// changed because a delay of 1 micro Sec @ 2MHz will be 0
if (n == 0) return;
__asm__ volatile(
"L_%=_delayMicroseconds:" "\n\t"
#if F_CPU < 24000000
"nop" "\n\t"
#endif
"subs %0, #1" "\n\t"
"bne L_%=_delayMicroseconds" "\n"
: "+r" (n) :
);
}
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
extern "C" {
#endif
unsigned long rtc_get(void);
void rtc_set(unsigned long t);
void rtc_compensate(int adjust);
#ifdef __cplusplus
}
class teensy3_clock_class
{
public:
static unsigned long get(void) __attribute__((always_inline)) { return rtc_get(); }
static void set(unsigned long t) __attribute__((always_inline)) { rtc_set(t); }
static void compensate(int adj) __attribute__((always_inline)) { rtc_compensate(adj); }
};
extern teensy3_clock_class Teensy3Clock;
#endif
#endif

662
teensy/core/mk20dx128.c Normal file
View File

@ -0,0 +1,662 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "mk20dx128.h"
extern unsigned long _stext;
extern unsigned long _etext;
extern unsigned long _sdata;
extern unsigned long _edata;
extern unsigned long _sbss;
extern unsigned long _ebss;
extern unsigned long _estack;
//extern void __init_array_start(void);
//extern void __init_array_end(void);
extern int main (void);
void ResetHandler(void);
void _init_Teensyduino_internal_(void);
void __libc_init_array(void);
void fault_isr(void)
{
while (1) {
// keep polling some communication while in fault
// mode, so we don't completely die.
if (SIM_SCGC4 & SIM_SCGC4_USBOTG) usb_isr();
if (SIM_SCGC4 & SIM_SCGC4_UART0) uart0_status_isr();
if (SIM_SCGC4 & SIM_SCGC4_UART1) uart1_status_isr();
if (SIM_SCGC4 & SIM_SCGC4_UART2) uart2_status_isr();
}
}
void unused_isr(void)
{
fault_isr();
}
extern volatile uint32_t systick_millis_count;
void systick_default_isr(void)
{
systick_millis_count++;
}
void nmi_isr(void) __attribute__ ((weak, alias("unused_isr")));
void hard_fault_isr(void) __attribute__ ((weak, alias("unused_isr")));
void memmanage_fault_isr(void) __attribute__ ((weak, alias("unused_isr")));
void bus_fault_isr(void) __attribute__ ((weak, alias("unused_isr")));
void usage_fault_isr(void) __attribute__ ((weak, alias("unused_isr")));
void svcall_isr(void) __attribute__ ((weak, alias("unused_isr")));
void debugmonitor_isr(void) __attribute__ ((weak, alias("unused_isr")));
void pendablesrvreq_isr(void) __attribute__ ((weak, alias("unused_isr")));
void systick_isr(void) __attribute__ ((weak, alias("systick_default_isr")));
void dma_ch0_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch1_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch2_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch3_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch4_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch5_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch6_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch7_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch8_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch9_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch10_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch11_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch12_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch13_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch14_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_ch15_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dma_error_isr(void) __attribute__ ((weak, alias("unused_isr")));
void mcm_isr(void) __attribute__ ((weak, alias("unused_isr")));
void flash_cmd_isr(void) __attribute__ ((weak, alias("unused_isr")));
void flash_error_isr(void) __attribute__ ((weak, alias("unused_isr")));
void low_voltage_isr(void) __attribute__ ((weak, alias("unused_isr")));
void wakeup_isr(void) __attribute__ ((weak, alias("unused_isr")));
void watchdog_isr(void) __attribute__ ((weak, alias("unused_isr")));
void i2c0_isr(void) __attribute__ ((weak, alias("unused_isr")));
void i2c1_isr(void) __attribute__ ((weak, alias("unused_isr")));
void i2c2_isr(void) __attribute__ ((weak, alias("unused_isr")));
void spi0_isr(void) __attribute__ ((weak, alias("unused_isr")));
void spi1_isr(void) __attribute__ ((weak, alias("unused_isr")));
void spi2_isr(void) __attribute__ ((weak, alias("unused_isr")));
void sdhc_isr(void) __attribute__ ((weak, alias("unused_isr")));
void can0_message_isr(void) __attribute__ ((weak, alias("unused_isr")));
void can0_bus_off_isr(void) __attribute__ ((weak, alias("unused_isr")));
void can0_error_isr(void) __attribute__ ((weak, alias("unused_isr")));
void can0_tx_warn_isr(void) __attribute__ ((weak, alias("unused_isr")));
void can0_rx_warn_isr(void) __attribute__ ((weak, alias("unused_isr")));
void can0_wakeup_isr(void) __attribute__ ((weak, alias("unused_isr")));
void i2s0_tx_isr(void) __attribute__ ((weak, alias("unused_isr")));
void i2s0_rx_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart0_lon_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart0_status_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart0_error_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart1_status_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart1_error_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart2_status_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart2_error_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart3_status_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart3_error_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart4_status_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart4_error_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart5_status_isr(void) __attribute__ ((weak, alias("unused_isr")));
void uart5_error_isr(void) __attribute__ ((weak, alias("unused_isr")));
void adc0_isr(void) __attribute__ ((weak, alias("unused_isr")));
void adc1_isr(void) __attribute__ ((weak, alias("unused_isr")));
void cmp0_isr(void) __attribute__ ((weak, alias("unused_isr")));
void cmp1_isr(void) __attribute__ ((weak, alias("unused_isr")));
void cmp2_isr(void) __attribute__ ((weak, alias("unused_isr")));
void ftm0_isr(void) __attribute__ ((weak, alias("unused_isr")));
void ftm1_isr(void) __attribute__ ((weak, alias("unused_isr")));
void ftm2_isr(void) __attribute__ ((weak, alias("unused_isr")));
void ftm3_isr(void) __attribute__ ((weak, alias("unused_isr")));
void cmt_isr(void) __attribute__ ((weak, alias("unused_isr")));
void rtc_alarm_isr(void) __attribute__ ((weak, alias("unused_isr")));
void rtc_seconds_isr(void) __attribute__ ((weak, alias("unused_isr")));
void pit0_isr(void) __attribute__ ((weak, alias("unused_isr")));
void pit1_isr(void) __attribute__ ((weak, alias("unused_isr")));
void pit2_isr(void) __attribute__ ((weak, alias("unused_isr")));
void pit3_isr(void) __attribute__ ((weak, alias("unused_isr")));
void pdb_isr(void) __attribute__ ((weak, alias("unused_isr")));
void usb_isr(void) __attribute__ ((weak, alias("unused_isr")));
void usb_charge_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dac0_isr(void) __attribute__ ((weak, alias("unused_isr")));
void dac1_isr(void) __attribute__ ((weak, alias("unused_isr")));
void tsi0_isr(void) __attribute__ ((weak, alias("unused_isr")));
void mcg_isr(void) __attribute__ ((weak, alias("unused_isr")));
void lptmr_isr(void) __attribute__ ((weak, alias("unused_isr")));
void porta_isr(void) __attribute__ ((weak, alias("unused_isr")));
void portb_isr(void) __attribute__ ((weak, alias("unused_isr")));
void portc_isr(void) __attribute__ ((weak, alias("unused_isr")));
void portd_isr(void) __attribute__ ((weak, alias("unused_isr")));
void porte_isr(void) __attribute__ ((weak, alias("unused_isr")));
void software_isr(void) __attribute__ ((weak, alias("unused_isr")));
// TODO: create AVR-stype ISR() macro, with default linkage to undefined handler
//
__attribute__ ((section(".vectors"), used))
void (* const gVectors[])(void) =
{
(void (*)(void))((unsigned long)&_estack), // 0 ARM: Initial Stack Pointer
ResetHandler, // 1 ARM: Initial Program Counter
nmi_isr, // 2 ARM: Non-maskable Interrupt (NMI)
hard_fault_isr, // 3 ARM: Hard Fault
memmanage_fault_isr, // 4 ARM: MemManage Fault
bus_fault_isr, // 5 ARM: Bus Fault
usage_fault_isr, // 6 ARM: Usage Fault
fault_isr, // 7 --
fault_isr, // 8 --
fault_isr, // 9 --
fault_isr, // 10 --
svcall_isr, // 11 ARM: Supervisor call (SVCall)
debugmonitor_isr, // 12 ARM: Debug Monitor
fault_isr, // 13 --
pendablesrvreq_isr, // 14 ARM: Pendable req serv(PendableSrvReq)
systick_isr, // 15 ARM: System tick timer (SysTick)
#if defined(__MK20DX128__)
dma_ch0_isr, // 16 DMA channel 0 transfer complete
dma_ch1_isr, // 17 DMA channel 1 transfer complete
dma_ch2_isr, // 18 DMA channel 2 transfer complete
dma_ch3_isr, // 19 DMA channel 3 transfer complete
dma_error_isr, // 20 DMA error interrupt channel
unused_isr, // 21 DMA --
flash_cmd_isr, // 22 Flash Memory Command complete
flash_error_isr, // 23 Flash Read collision
low_voltage_isr, // 24 Low-voltage detect/warning
wakeup_isr, // 25 Low Leakage Wakeup
watchdog_isr, // 26 Both EWM and WDOG interrupt
i2c0_isr, // 27 I2C0
spi0_isr, // 28 SPI0
i2s0_tx_isr, // 29 I2S0 Transmit
i2s0_rx_isr, // 30 I2S0 Receive
uart0_lon_isr, // 31 UART0 CEA709.1-B (LON) status
uart0_status_isr, // 32 UART0 status
uart0_error_isr, // 33 UART0 error
uart1_status_isr, // 34 UART1 status
uart1_error_isr, // 35 UART1 error
uart2_status_isr, // 36 UART2 status
uart2_error_isr, // 37 UART2 error
adc0_isr, // 38 ADC0
cmp0_isr, // 39 CMP0
cmp1_isr, // 40 CMP1
ftm0_isr, // 41 FTM0
ftm1_isr, // 42 FTM1
cmt_isr, // 43 CMT
rtc_alarm_isr, // 44 RTC Alarm interrupt
rtc_seconds_isr, // 45 RTC Seconds interrupt
pit0_isr, // 46 PIT Channel 0
pit1_isr, // 47 PIT Channel 1
pit2_isr, // 48 PIT Channel 2
pit3_isr, // 49 PIT Channel 3
pdb_isr, // 50 PDB Programmable Delay Block
usb_isr, // 51 USB OTG
usb_charge_isr, // 52 USB Charger Detect
tsi0_isr, // 53 TSI0
mcg_isr, // 54 MCG
lptmr_isr, // 55 Low Power Timer
porta_isr, // 56 Pin detect (Port A)
portb_isr, // 57 Pin detect (Port B)
portc_isr, // 58 Pin detect (Port C)
portd_isr, // 59 Pin detect (Port D)
porte_isr, // 60 Pin detect (Port E)
software_isr, // 61 Software interrupt
#elif defined(__MK20DX256__)
dma_ch0_isr, // 16 DMA channel 0 transfer complete
dma_ch1_isr, // 17 DMA channel 1 transfer complete
dma_ch2_isr, // 18 DMA channel 2 transfer complete
dma_ch3_isr, // 19 DMA channel 3 transfer complete
dma_ch4_isr, // 20 DMA channel 4 transfer complete
dma_ch5_isr, // 21 DMA channel 5 transfer complete
dma_ch6_isr, // 22 DMA channel 6 transfer complete
dma_ch7_isr, // 23 DMA channel 7 transfer complete
dma_ch8_isr, // 24 DMA channel 8 transfer complete
dma_ch9_isr, // 25 DMA channel 9 transfer complete
dma_ch10_isr, // 26 DMA channel 10 transfer complete
dma_ch11_isr, // 27 DMA channel 10 transfer complete
dma_ch12_isr, // 28 DMA channel 10 transfer complete
dma_ch13_isr, // 29 DMA channel 10 transfer complete
dma_ch14_isr, // 30 DMA channel 10 transfer complete
dma_ch15_isr, // 31 DMA channel 10 transfer complete
dma_error_isr, // 32 DMA error interrupt channel
unused_isr, // 33 --
flash_cmd_isr, // 34 Flash Memory Command complete
flash_error_isr, // 35 Flash Read collision
low_voltage_isr, // 36 Low-voltage detect/warning
wakeup_isr, // 37 Low Leakage Wakeup
watchdog_isr, // 38 Both EWM and WDOG interrupt
unused_isr, // 39 --
i2c0_isr, // 40 I2C0
i2c1_isr, // 41 I2C1
spi0_isr, // 42 SPI0
spi1_isr, // 43 SPI1
unused_isr, // 44 --
can0_message_isr, // 45 CAN OR'ed Message buffer (0-15)
can0_bus_off_isr, // 46 CAN Bus Off
can0_error_isr, // 47 CAN Error
can0_tx_warn_isr, // 48 CAN Transmit Warning
can0_rx_warn_isr, // 49 CAN Receive Warning
can0_wakeup_isr, // 50 CAN Wake Up
i2s0_tx_isr, // 51 I2S0 Transmit
i2s0_rx_isr, // 52 I2S0 Receive
unused_isr, // 53 --
unused_isr, // 54 --
unused_isr, // 55 --
unused_isr, // 56 --
unused_isr, // 57 --
unused_isr, // 58 --
unused_isr, // 59 --
uart0_lon_isr, // 60 UART0 CEA709.1-B (LON) status
uart0_status_isr, // 61 UART0 status
uart0_error_isr, // 62 UART0 error
uart1_status_isr, // 63 UART1 status
uart1_error_isr, // 64 UART1 error
uart2_status_isr, // 65 UART2 status
uart2_error_isr, // 66 UART2 error
unused_isr, // 67 --
unused_isr, // 68 --
unused_isr, // 69 --
unused_isr, // 70 --
unused_isr, // 71 --
unused_isr, // 72 --
adc0_isr, // 73 ADC0
adc1_isr, // 74 ADC1
cmp0_isr, // 75 CMP0
cmp1_isr, // 76 CMP1
cmp2_isr, // 77 CMP2
ftm0_isr, // 78 FTM0
ftm1_isr, // 79 FTM1
ftm2_isr, // 80 FTM2
cmt_isr, // 81 CMT
rtc_alarm_isr, // 82 RTC Alarm interrupt
rtc_seconds_isr, // 83 RTC Seconds interrupt
pit0_isr, // 84 PIT Channel 0
pit1_isr, // 85 PIT Channel 1
pit2_isr, // 86 PIT Channel 2
pit3_isr, // 87 PIT Channel 3
pdb_isr, // 88 PDB Programmable Delay Block
usb_isr, // 89 USB OTG
usb_charge_isr, // 90 USB Charger Detect
unused_isr, // 91 --
unused_isr, // 92 --
unused_isr, // 93 --
unused_isr, // 94 --
unused_isr, // 95 --
unused_isr, // 96 --
dac0_isr, // 97 DAC0
unused_isr, // 98 --
tsi0_isr, // 99 TSI0
mcg_isr, // 100 MCG
lptmr_isr, // 101 Low Power Timer
unused_isr, // 102 --
porta_isr, // 103 Pin detect (Port A)
portb_isr, // 104 Pin detect (Port B)
portc_isr, // 105 Pin detect (Port C)
portd_isr, // 106 Pin detect (Port D)
porte_isr, // 107 Pin detect (Port E)
unused_isr, // 108 --
unused_isr, // 109 --
software_isr, // 110 Software interrupt
#endif
};
//void usb_isr(void)
//{
//}
__attribute__ ((section(".flashconfig"), used))
const uint8_t flashconfigbytes[16] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF
};
// Automatically initialize the RTC. When the build defines the compile
// time, and the user has added a crystal, the RTC will automatically
// begin at the time of the first upload.
#ifndef TIME_T
#define TIME_T 1349049600 // default 1 Oct 2012 (never used, Arduino sets this)
#endif
extern void rtc_set(unsigned long t);
static void startup_default_early_hook(void) { WDOG_STCTRLH = WDOG_STCTRLH_ALLOWUPDATE; }
static void startup_default_late_hook(void) {}
void startup_early_hook(void) __attribute__ ((weak, alias("startup_default_early_hook")));
void startup_late_hook(void) __attribute__ ((weak, alias("startup_default_late_hook")));
__attribute__ ((section(".startup")))
void ResetHandler(void)
{
uint32_t *src = &_etext;
uint32_t *dest = &_sdata;
unsigned int i;
#if F_CPU <= 2000000
volatile int n;
#endif
WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;
WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
__asm__ volatile ("nop");
__asm__ volatile ("nop");
// programs using the watchdog timer or needing to initialize hardware as
// early as possible can implement startup_early_hook()
startup_early_hook();
// enable clocks to always-used peripherals
#if defined(__MK20DX128__)
SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO
SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTFL;
#elif defined(__MK20DX256__)
SIM_SCGC3 = SIM_SCGC3_ADC1 | SIM_SCGC3_FTM2;
SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO
SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTFL;
#endif
// if the RTC oscillator isn't enabled, get it started early
if (!(RTC_CR & RTC_CR_OSCE)) {
RTC_SR = 0;
RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE;
}
// release I/O pins hold, if we woke up from VLLS mode
if (PMC_REGSC & PMC_REGSC_ACKISO) PMC_REGSC |= PMC_REGSC_ACKISO;
// since this is a write once register, make it visible to all F_CPU's
// so we can into other sleep modes in the future at any speed
SMC_PMPROT = SMC_PMPROT_AVLP | SMC_PMPROT_ALLS | SMC_PMPROT_AVLLS;
// TODO: do this while the PLL is waiting to lock....
while (dest < &_edata) *dest++ = *src++;
dest = &_sbss;
while (dest < &_ebss) *dest++ = 0;
SCB_VTOR = 0; // use vector table in flash
// default all interrupts to medium priority level
for (i=0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_PRIORITY(i, 128);
// hardware always starts in FEI mode
// C1[CLKS] bits are written to 00
// C1[IREFS] bit is written to 1
// C6[PLLS] bit is written to 0
// MCG_SC[FCDIV] defaults to divide by two for internal ref clock
// I tried changing MSG_SC to divide by 1, it didn't work for me
#if F_CPU <= 2000000
// use the internal oscillator
MCG_C1 = MCG_C1_CLKS(1) | MCG_C1_IREFS;
// wait for MCGOUT to use oscillator
while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(1)) ;
for (n=0; n<10; n++) ; // TODO: why do we get 2 mA extra without this delay?
MCG_C2 = MCG_C2_IRCS;
while (!(MCG_S & MCG_S_IRCST)) ;
// now in FBI mode:
// C1[CLKS] bits are written to 01
// C1[IREFS] bit is written to 1
// C6[PLLS] is written to 0
// C2[LP] is written to 0
MCG_C2 = MCG_C2_IRCS | MCG_C2_LP;
// now in BLPI mode:
// C1[CLKS] bits are written to 01
// C1[IREFS] bit is written to 1
// C6[PLLS] bit is written to 0
// C2[LP] bit is written to 1
#else
// enable capacitors for crystal
OSC0_CR = OSC_SC8P | OSC_SC2P;
// enable osc, 8-32 MHz range, low power mode
MCG_C2 = MCG_C2_RANGE0(2) | MCG_C2_EREFS;
// switch to crystal as clock source, FLL input = 16 MHz / 512
MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(4);
// wait for crystal oscillator to begin
while ((MCG_S & MCG_S_OSCINIT0) == 0) ;
// wait for FLL to use oscillator
while ((MCG_S & MCG_S_IREFST) != 0) ;
// wait for MCGOUT to use oscillator
while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) ;
// now in FBE mode
// C1[CLKS] bits are written to 10
// C1[IREFS] bit is written to 0
// C1[FRDIV] must be written to divide xtal to 31.25-39 kHz
// C6[PLLS] bit is written to 0
// C2[LP] is written to 0
#if F_CPU <= 16000000
// if the crystal is fast enough, use it directly (no FLL or PLL)
MCG_C2 = MCG_C2_RANGE0(2) | MCG_C2_EREFS | MCG_C2_LP;
// BLPE mode:
// C1[CLKS] bits are written to 10
// C1[IREFS] bit is written to 0
// C2[LP] bit is written to 1
#else
// if we need faster than the crystal, turn on the PLL
#if F_CPU == 72000000
MCG_C5 = MCG_C5_PRDIV0(5); // config PLL input for 16 MHz Crystal / 6 = 2.667 Hz
#else
MCG_C5 = MCG_C5_PRDIV0(3); // config PLL input for 16 MHz Crystal / 4 = 4 MHz
#endif
#if F_CPU == 168000000
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(18); // config PLL for 168 MHz output
#elif F_CPU == 144000000
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(12); // config PLL for 144 MHz output
#elif F_CPU == 120000000
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(6); // config PLL for 120 MHz output
#elif F_CPU == 72000000
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(3); // config PLL for 72 MHz output
#else
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0); // config PLL for 96 MHz output
#endif
// wait for PLL to start using xtal as its input
while (!(MCG_S & MCG_S_PLLST)) ;
// wait for PLL to lock
while (!(MCG_S & MCG_S_LOCK0)) ;
// now we're in PBE mode
#endif
#endif
// now program the clock dividers
#if F_CPU == 168000000
// config divisors: 168 MHz core, 56 MHz bus, 33.6 MHz flash, USB = 168 * 2 / 7
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(4);
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(6) | SIM_CLKDIV2_USBFRAC;
#elif F_CPU == 144000000
// config divisors: 144 MHz core, 48 MHz bus, 28.8 MHz flash, USB = 144 / 3
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(4);
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(2);
#elif F_CPU == 120000000
// config divisors: 120 MHz core, 60 MHz bus, 24 MHz flash, USB = 128 * 2 / 5
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(4);
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(4) | SIM_CLKDIV2_USBFRAC;
#elif F_CPU == 96000000
// config divisors: 96 MHz core, 48 MHz bus, 24 MHz flash, USB = 96 / 2
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3);
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1);
#elif F_CPU == 72000000
// config divisors: 72 MHz core, 36 MHz bus, 24 MHz flash, USB = 72 * 2 / 3
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(2);
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(2) | SIM_CLKDIV2_USBFRAC;
#elif F_CPU == 48000000
// config divisors: 48 MHz core, 48 MHz bus, 24 MHz flash, USB = 96 / 2
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3);
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1);
#elif F_CPU == 24000000
// config divisors: 24 MHz core, 24 MHz bus, 24 MHz flash, USB = 96 / 2
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(3);
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1);
#elif F_CPU == 16000000
// config divisors: 16 MHz core, 16 MHz bus, 16 MHz flash
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(0);
#elif F_CPU == 8000000
// config divisors: 8 MHz core, 8 MHz bus, 8 MHz flash
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(1);
#elif F_CPU == 4000000
// config divisors: 4 MHz core, 4 MHz bus, 2 MHz flash
// since we are running from external clock 16MHz
// fix outdiv too -> cpu 16/4, bus 16/4, flash 16/4
// here we can go into vlpr?
// config divisors: 4 MHz core, 4 MHz bus, 4 MHz flash
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(3);
#elif F_CPU == 2000000
// since we are running from the fast internal reference clock 4MHz
// but is divided down by 2 so we actually have a 2MHz, MCG_SC[FCDIV] default is 2
// fix outdiv -> cpu 2/1, bus 2/1, flash 2/2
// config divisors: 2 MHz core, 2 MHz bus, 1 MHz flash
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(1);
#else
#error "Error, F_CPU must be 168, 144, 120, 96, 72, 48, 24, 16, 8, 4, or 2 MHz"
#endif
#if F_CPU > 16000000
// switch to PLL as clock source, FLL input = 16 MHz / 512
MCG_C1 = MCG_C1_CLKS(0) | MCG_C1_FRDIV(4);
// wait for PLL clock to be used
while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ;
// now we're in PEE mode
// USB uses PLL clock, trace is CPU clock, CLKOUT=OSCERCLK0
SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6);
#else
SIM_SOPT2 = SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(3);
#endif
#if F_CPU <= 2000000
// since we are not going into "stop mode" i removed it
SMC_PMCTRL = SMC_PMCTRL_RUNM(2); // VLPR mode :-)
#endif
// initialize the SysTick counter
SYST_RVR = (F_CPU / 1000) - 1;
SYST_CSR = SYST_CSR_CLKSOURCE | SYST_CSR_TICKINT | SYST_CSR_ENABLE;
//init_pins();
__enable_irq();
_init_Teensyduino_internal_();
if (RTC_SR & RTC_SR_TIF) {
// TODO: this should probably set the time more agressively, if
// we could reliably detect the first reboot after programming.
rtc_set(TIME_T);
}
__libc_init_array();
startup_late_hook();
main();
while (1) ;
}
char *__brkval = (char *)&_ebss;
void * _sbrk(int incr)
{
char *prev = __brkval;
__brkval += incr;
return prev;
}
__attribute__((weak))
int _read(int file, char *ptr, int len)
{
return 0;
}
__attribute__((weak))
int _close(int fd)
{
return -1;
}
#include <sys/stat.h>
__attribute__((weak))
int _fstat(int fd, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
__attribute__((weak))
int _isatty(int fd)
{
return 1;
}
__attribute__((weak))
int _lseek(int fd, long long offset, int whence)
{
return -1;
}
__attribute__((weak))
void _exit(int status)
{
while (1);
}
__attribute__((weak))
void __cxa_pure_virtual()
{
while (1);
}
__attribute__((weak))
int __cxa_guard_acquire (char *g)
{
return !(*g);
}
__attribute__((weak))
void __cxa_guard_release(char *g)
{
*g = 1;
}
int nvic_execution_priority(void)
{
int priority=256;
uint32_t primask, faultmask, basepri, ipsr;
// full algorithm in ARM DDI0403D, page B1-639
// this isn't quite complete, but hopefully good enough
__asm__ volatile("mrs %0, faultmask\n" : "=r" (faultmask)::);
if (faultmask) return -1;
__asm__ volatile("mrs %0, primask\n" : "=r" (primask)::);
if (primask) return 0;
__asm__ volatile("mrs %0, ipsr\n" : "=r" (ipsr)::);
if (ipsr) {
if (ipsr < 16) priority = 0; // could be non-zero
else priority = NVIC_GET_PRIORITY(ipsr - 16);
}
__asm__ volatile("mrs %0, basepri\n" : "=r" (basepri)::);
if (basepri > 0 && basepri < priority) priority = basepri;
return priority;
}

2385
teensy/core/mk20dx128.h Normal file

File diff suppressed because it is too large Load Diff

113
teensy/core/pins_arduino.h Normal file
View File

@ -0,0 +1,113 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef pins_macros_for_arduino_compatibility_h
#define pins_macros_for_arduino_compatibility_h
#include <stdint.h>
const static uint8_t A0 = 14;
const static uint8_t A1 = 15;
const static uint8_t A2 = 16;
const static uint8_t A3 = 17;
const static uint8_t A4 = 18;
const static uint8_t A5 = 19;
const static uint8_t A6 = 20;
const static uint8_t A7 = 21;
const static uint8_t A8 = 22;
const static uint8_t A9 = 23;
const static uint8_t A10 = 34;
const static uint8_t A11 = 35;
const static uint8_t A12 = 36;
const static uint8_t A13 = 37;
const static uint8_t A14 = 40;
const static uint8_t A15 = 26;
const static uint8_t A16 = 27;
const static uint8_t A17 = 28;
const static uint8_t A18 = 29;
const static uint8_t A19 = 30;
const static uint8_t A20 = 31;
const static uint8_t SS = 10;
const static uint8_t MOSI = 11;
const static uint8_t MISO = 12;
const static uint8_t SCK = 13;
const static uint8_t LED_BUILTIN = 13;
const static uint8_t SDA = 18;
const static uint8_t SCL = 19;
#define NUM_DIGITAL_PINS 34
#define NUM_ANALOG_INPUTS 14
#define analogInputToDigitalPin(p) (((p) < 10) ? (p) + 14 : -1)
#define digitalPinHasPWM(p) (((p) >= 3 && (p) <= 6) || (p) == 9 || (p) == 10 || ((p) >= 20 && (p) <= 23))
#define NOT_AN_INTERRUPT -1
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1)
struct digital_pin_bitband_and_config_table_struct {
volatile uint32_t *reg;
volatile uint32_t *config;
};
extern const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[];
// compatibility macros
#define digitalPinToPort(pin) (pin)
#define digitalPinToBitMask(pin) (1)
#define portOutputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 0))
#define portSetRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 32))
#define portClearRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 64))
#define portToggleRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 96))
#define portInputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 128))
#define portModeRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 160))
#define portConfigRegister(pin) ((volatile uint32_t *)(digital_pin_to_info_PGM[(pin)].config))
#define digitalPinToPortReg(pin) (portOutputRegister(pin))
#define digitalPinToBit(pin) (1)
#define NOT_ON_TIMER 0
static inline uint8_t digitalPinToTimer(uint8_t) __attribute__((always_inline, unused));
static inline uint8_t digitalPinToTimer(uint8_t pin)
{
if (pin >= 3 && pin <= 6) return pin - 2;
if (pin >= 9 && pin <= 10) return pin - 4;
if (pin >= 20 && pin <= 23) return pin - 13;
return NOT_ON_TIMER;
}
#endif

817
teensy/core/pins_teensy.c Normal file
View File

@ -0,0 +1,817 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "core_pins.h"
#include "pins_arduino.h"
#include "HardwareSerial.h"
#if 0
// moved to pins_arduino.h
struct digital_pin_bitband_and_config_table_struct {
volatile uint32_t *reg;
volatile uint32_t *config;
};
const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[];
// compatibility macros
#define digitalPinToPort(pin) (pin)
#define digitalPinToBitMask(pin) (1)
#define portOutputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 0))
#define portSetRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 32))
#define portClearRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 64))
#define portToggleRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 96))
#define portInputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 128))
#define portModeRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 160))
#define portConfigRegister(pin) ((volatile uint32_t *)(digital_pin_to_info_PGM[(pin)].config))
#endif
//#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
//#define analogInPinToBit(P) (P)
#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000)
#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit)))
//#define GPIO_SET_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 1)
//#define GPIO_CLR_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 0)
const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[] = {
{GPIO_BITBAND_PTR(CORE_PIN0_PORTREG, CORE_PIN0_BIT), &CORE_PIN0_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN1_PORTREG, CORE_PIN1_BIT), &CORE_PIN1_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN2_PORTREG, CORE_PIN2_BIT), &CORE_PIN2_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN3_PORTREG, CORE_PIN3_BIT), &CORE_PIN3_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN4_PORTREG, CORE_PIN4_BIT), &CORE_PIN4_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN5_PORTREG, CORE_PIN5_BIT), &CORE_PIN5_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN6_PORTREG, CORE_PIN6_BIT), &CORE_PIN6_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN7_PORTREG, CORE_PIN7_BIT), &CORE_PIN7_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN8_PORTREG, CORE_PIN8_BIT), &CORE_PIN8_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN9_PORTREG, CORE_PIN9_BIT), &CORE_PIN9_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN10_PORTREG, CORE_PIN10_BIT), &CORE_PIN10_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN11_PORTREG, CORE_PIN11_BIT), &CORE_PIN11_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN12_PORTREG, CORE_PIN12_BIT), &CORE_PIN12_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN13_PORTREG, CORE_PIN13_BIT), &CORE_PIN13_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN14_PORTREG, CORE_PIN14_BIT), &CORE_PIN14_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN15_PORTREG, CORE_PIN15_BIT), &CORE_PIN15_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN16_PORTREG, CORE_PIN16_BIT), &CORE_PIN16_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN17_PORTREG, CORE_PIN17_BIT), &CORE_PIN17_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN18_PORTREG, CORE_PIN18_BIT), &CORE_PIN18_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN19_PORTREG, CORE_PIN19_BIT), &CORE_PIN19_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN20_PORTREG, CORE_PIN20_BIT), &CORE_PIN20_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN21_PORTREG, CORE_PIN21_BIT), &CORE_PIN21_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN22_PORTREG, CORE_PIN22_BIT), &CORE_PIN22_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN23_PORTREG, CORE_PIN23_BIT), &CORE_PIN23_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN24_PORTREG, CORE_PIN24_BIT), &CORE_PIN24_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN25_PORTREG, CORE_PIN25_BIT), &CORE_PIN25_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN26_PORTREG, CORE_PIN26_BIT), &CORE_PIN26_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN27_PORTREG, CORE_PIN27_BIT), &CORE_PIN27_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN28_PORTREG, CORE_PIN28_BIT), &CORE_PIN28_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN29_PORTREG, CORE_PIN29_BIT), &CORE_PIN29_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN30_PORTREG, CORE_PIN30_BIT), &CORE_PIN30_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN31_PORTREG, CORE_PIN31_BIT), &CORE_PIN31_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN32_PORTREG, CORE_PIN32_BIT), &CORE_PIN32_CONFIG},
{GPIO_BITBAND_PTR(CORE_PIN33_PORTREG, CORE_PIN33_BIT), &CORE_PIN33_CONFIG}
};
typedef void (*voidFuncPtr)(void);
volatile static voidFuncPtr intFunc[CORE_NUM_DIGITAL];
void init_pin_interrupts(void)
{
//SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO
NVIC_ENABLE_IRQ(IRQ_PORTA);
NVIC_ENABLE_IRQ(IRQ_PORTB);
NVIC_ENABLE_IRQ(IRQ_PORTC);
NVIC_ENABLE_IRQ(IRQ_PORTD);
NVIC_ENABLE_IRQ(IRQ_PORTE);
// TODO: maybe these should be set to a lower priority
// so if the user puts lots of slow code on attachInterrupt
// fast interrupts will still be serviced quickly?
}
void attachInterrupt(uint8_t pin, void (*function)(void), int mode)
{
volatile uint32_t *config;
uint32_t cfg, mask;
if (pin >= CORE_NUM_DIGITAL) return;
switch (mode) {
case CHANGE: mask = 0x0B; break;
case RISING: mask = 0x09; break;
case FALLING: mask = 0x0A; break;
case LOW: mask = 0x08; break;
case HIGH: mask = 0x0C; break;
default: return;
}
mask = (mask << 16) | 0x01000000;
config = portConfigRegister(pin);
__disable_irq();
cfg = *config;
cfg &= ~0x000F0000; // disable any previous interrupt
*config = cfg;
intFunc[pin] = function; // set the function pointer
cfg |= mask;
*config = cfg; // enable the new interrupt
__enable_irq();
}
void detachInterrupt(uint8_t pin)
{
volatile uint32_t *config;
config = portConfigRegister(pin);
__disable_irq();
*config = ((*config & ~0x000F0000) | 0x01000000);
intFunc[pin] = NULL;
__enable_irq();
}
void porta_isr(void)
{
uint32_t isfr = PORTA_ISFR;
PORTA_ISFR = isfr;
if ((isfr & CORE_PIN3_BITMASK) && intFunc[3]) intFunc[3]();
if ((isfr & CORE_PIN4_BITMASK) && intFunc[4]) intFunc[4]();
if ((isfr & CORE_PIN24_BITMASK) && intFunc[24]) intFunc[24]();
if ((isfr & CORE_PIN33_BITMASK) && intFunc[33]) intFunc[33]();
}
void portb_isr(void)
{
uint32_t isfr = PORTB_ISFR;
PORTB_ISFR = isfr;
if ((isfr & CORE_PIN0_BITMASK) && intFunc[0]) intFunc[0]();
if ((isfr & CORE_PIN1_BITMASK) && intFunc[1]) intFunc[1]();
if ((isfr & CORE_PIN16_BITMASK) && intFunc[16]) intFunc[16]();
if ((isfr & CORE_PIN17_BITMASK) && intFunc[17]) intFunc[17]();
if ((isfr & CORE_PIN18_BITMASK) && intFunc[18]) intFunc[18]();
if ((isfr & CORE_PIN19_BITMASK) && intFunc[19]) intFunc[19]();
if ((isfr & CORE_PIN25_BITMASK) && intFunc[25]) intFunc[25]();
if ((isfr & CORE_PIN32_BITMASK) && intFunc[32]) intFunc[32]();
}
void portc_isr(void)
{
// TODO: these are inefficent. Use CLZ somehow....
uint32_t isfr = PORTC_ISFR;
PORTC_ISFR = isfr;
if ((isfr & CORE_PIN9_BITMASK) && intFunc[9]) intFunc[9]();
if ((isfr & CORE_PIN10_BITMASK) && intFunc[10]) intFunc[10]();
if ((isfr & CORE_PIN11_BITMASK) && intFunc[11]) intFunc[11]();
if ((isfr & CORE_PIN12_BITMASK) && intFunc[12]) intFunc[12]();
if ((isfr & CORE_PIN13_BITMASK) && intFunc[13]) intFunc[13]();
if ((isfr & CORE_PIN15_BITMASK) && intFunc[15]) intFunc[15]();
if ((isfr & CORE_PIN22_BITMASK) && intFunc[22]) intFunc[22]();
if ((isfr & CORE_PIN23_BITMASK) && intFunc[23]) intFunc[23]();
if ((isfr & CORE_PIN27_BITMASK) && intFunc[27]) intFunc[27]();
if ((isfr & CORE_PIN28_BITMASK) && intFunc[28]) intFunc[28]();
if ((isfr & CORE_PIN29_BITMASK) && intFunc[29]) intFunc[29]();
if ((isfr & CORE_PIN30_BITMASK) && intFunc[30]) intFunc[30]();
}
void portd_isr(void)
{
uint32_t isfr = PORTD_ISFR;
PORTD_ISFR = isfr;
if ((isfr & CORE_PIN2_BITMASK) && intFunc[2]) intFunc[2]();
if ((isfr & CORE_PIN5_BITMASK) && intFunc[5]) intFunc[5]();
if ((isfr & CORE_PIN6_BITMASK) && intFunc[6]) intFunc[6]();
if ((isfr & CORE_PIN7_BITMASK) && intFunc[7]) intFunc[7]();
if ((isfr & CORE_PIN8_BITMASK) && intFunc[8]) intFunc[8]();
if ((isfr & CORE_PIN14_BITMASK) && intFunc[14]) intFunc[14]();
if ((isfr & CORE_PIN20_BITMASK) && intFunc[20]) intFunc[20]();
if ((isfr & CORE_PIN21_BITMASK) && intFunc[21]) intFunc[21]();
}
void porte_isr(void)
{
uint32_t isfr = PORTE_ISFR;
PORTE_ISFR = isfr;
if ((isfr & CORE_PIN26_BITMASK) && intFunc[26]) intFunc[26]();
if ((isfr & CORE_PIN31_BITMASK) && intFunc[31]) intFunc[31]();
}
unsigned long rtc_get(void)
{
return RTC_TSR;
}
void rtc_set(unsigned long t)
{
RTC_SR = 0;
RTC_TPR = 0;
RTC_TSR = t;
RTC_SR = RTC_SR_TCE;
}
// adjust is the amount of crystal error to compensate, 1 = 0.1192 ppm
// For example, adjust = -100 is slows the clock by 11.92 ppm
//
void rtc_compensate(int adjust)
{
uint32_t comp, interval, tcr;
// This simple approach tries to maximize the interval.
// Perhaps minimizing TCR would be better, so the
// compensation is distributed more evenly across
// many seconds, rather than saving it all up and then
// altering one second up to +/- 0.38%
if (adjust >= 0) {
comp = adjust;
interval = 256;
while (1) {
tcr = comp * interval;
if (tcr < 128*256) break;
if (--interval == 1) break;
}
tcr = tcr >> 8;
} else {
comp = -adjust;
interval = 256;
while (1) {
tcr = comp * interval;
if (tcr < 129*256) break;
if (--interval == 1) break;
}
tcr = tcr >> 8;
tcr = 256 - tcr;
}
RTC_TCR = ((interval - 1) << 8) | tcr;
}
#if 0
// TODO: build system should define this
// so RTC is automatically initialized to approx correct time
// at least when the program begins running right after upload
#ifndef TIME_T
#define TIME_T 1350160272
#endif
void init_rtc(void)
{
serial_print("init_rtc\n");
//SIM_SCGC6 |= SIM_SCGC6_RTC;
// enable the RTC crystal oscillator, for approx 12pf crystal
if (!(RTC_CR & RTC_CR_OSCE)) {
serial_print("start RTC oscillator\n");
RTC_SR = 0;
RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE;
}
// should wait for crystal to stabilize.....
serial_print("SR=");
serial_phex32(RTC_SR);
serial_print("\n");
serial_print("CR=");
serial_phex32(RTC_CR);
serial_print("\n");
serial_print("TSR=");
serial_phex32(RTC_TSR);
serial_print("\n");
serial_print("TCR=");
serial_phex32(RTC_TCR);
serial_print("\n");
if (RTC_SR & RTC_SR_TIF) {
// enable the RTC
RTC_SR = 0;
RTC_TPR = 0;
RTC_TSR = TIME_T;
RTC_SR = RTC_SR_TCE;
}
}
#endif
extern void usb_init(void);
// create a default PWM at the same 488.28 Hz as Arduino Uno
#if F_BUS == 60000000
#define DEFAULT_FTM_MOD (61440 - 1)
#define DEFAULT_FTM_PRESCALE 1
#elif F_BUS == 56000000
#define DEFAULT_FTM_MOD (57344 - 1)
#define DEFAULT_FTM_PRESCALE 1
#elif F_BUS == 48000000
#define DEFAULT_FTM_MOD (49152 - 1)
#define DEFAULT_FTM_PRESCALE 1
#elif F_BUS == 40000000
#define DEFAULT_FTM_MOD (40960 - 1)
#define DEFAULT_FTM_PRESCALE 1
#elif F_BUS == 36000000
#define DEFAULT_FTM_MOD (36864 - 1)
#define DEFAULT_FTM_PRESCALE 1
#elif F_BUS == 24000000
#define DEFAULT_FTM_MOD (49152 - 1)
#define DEFAULT_FTM_PRESCALE 0
#elif F_BUS == 16000000
#define DEFAULT_FTM_MOD (32768 - 1)
#define DEFAULT_FTM_PRESCALE 0
#elif F_BUS == 8000000
#define DEFAULT_FTM_MOD (16384 - 1)
#define DEFAULT_FTM_PRESCALE 0
#elif F_BUS == 4000000
#define DEFAULT_FTM_MOD (8192 - 1)
#define DEFAULT_FTM_PRESCALE 0
#elif F_BUS == 2000000
#define DEFAULT_FTM_MOD (4096 - 1)
#define DEFAULT_FTM_PRESCALE 0
#endif
//void init_pins(void)
void _init_Teensyduino_internal_(void)
{
init_pin_interrupts();
//SIM_SCGC6 |= SIM_SCGC6_FTM0; // TODO: use bitband for atomic read-mod-write
//SIM_SCGC6 |= SIM_SCGC6_FTM1;
FTM0_CNT = 0;
FTM0_MOD = DEFAULT_FTM_MOD;
FTM0_C0SC = 0x28; // MSnB:MSnA = 10, ELSnB:ELSnA = 10
FTM0_C1SC = 0x28;
FTM0_C2SC = 0x28;
FTM0_C3SC = 0x28;
FTM0_C4SC = 0x28;
FTM0_C5SC = 0x28;
FTM0_C6SC = 0x28;
FTM0_C7SC = 0x28;
FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(DEFAULT_FTM_PRESCALE);
FTM1_CNT = 0;
FTM1_MOD = DEFAULT_FTM_MOD;
FTM1_C0SC = 0x28;
FTM1_C1SC = 0x28;
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(DEFAULT_FTM_PRESCALE);
#if defined(__MK20DX256__)
FTM2_CNT = 0;
FTM2_MOD = DEFAULT_FTM_MOD;
FTM2_C0SC = 0x28;
FTM2_C1SC = 0x28;
FTM2_SC = FTM_SC_CLKS(1) | FTM_SC_PS(DEFAULT_FTM_PRESCALE);
#endif
analog_init();
//delay(100); // TODO: this is not necessary, right?
delay(4);
usb_init();
}
static uint8_t analog_write_res = 8;
// SOPT4 is SIM select clocks?
// FTM is clocked by the bus clock, either 24 or 48 MHz
// input capture can be FTM1_CH0, CMP0 or CMP1 or USB start of frame
// 24 MHz with reload 49152 to match Arduino's speed = 488.28125 Hz
void analogWrite(uint8_t pin, int val)
{
uint32_t cval, max;
#if defined(__MK20DX256__)
if (pin == A14) {
uint8_t res = analog_write_res;
if (res < 12) {
val <<= 12 - res;
} else if (res > 12) {
val >>= res - 12;
}
analogWriteDAC0(val);
return;
}
#endif
max = 1 << analog_write_res;
if (val <= 0) {
digitalWrite(pin, LOW);
pinMode(pin, OUTPUT); // TODO: implement OUTPUT_LOW
return;
} else if (val >= max) {
digitalWrite(pin, HIGH);
pinMode(pin, OUTPUT); // TODO: implement OUTPUT_HIGH
return;
}
//serial_print("analogWrite\n");
//serial_print("val = ");
//serial_phex32(val);
//serial_print("\n");
//serial_print("analog_write_res = ");
//serial_phex(analog_write_res);
//serial_print("\n");
if (pin == 3 || pin == 4) {
cval = ((uint32_t)val * (uint32_t)(FTM1_MOD + 1)) >> analog_write_res;
#if defined(__MK20DX256__)
} else if (pin == 25 || pin == 32) {
cval = ((uint32_t)val * (uint32_t)(FTM2_MOD + 1)) >> analog_write_res;
#endif
} else {
cval = ((uint32_t)val * (uint32_t)(FTM0_MOD + 1)) >> analog_write_res;
}
//serial_print("cval = ");
//serial_phex32(cval);
//serial_print("\n");
switch (pin) {
case 3: // PTA12, FTM1_CH0
FTM1_C0V = cval;
CORE_PIN3_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 4: // PTA13, FTM1_CH1
FTM1_C1V = cval;
CORE_PIN4_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 5: // PTD7, FTM0_CH7
FTM0_C7V = cval;
CORE_PIN5_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 6: // PTD4, FTM0_CH4
FTM0_C4V = cval;
CORE_PIN6_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 9: // PTC3, FTM0_CH2
FTM0_C2V = cval;
CORE_PIN9_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 10: // PTC4, FTM0_CH3
FTM0_C3V = cval;
CORE_PIN10_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 20: // PTD5, FTM0_CH5
FTM0_C5V = cval;
CORE_PIN20_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 21: // PTD6, FTM0_CH6
FTM0_C6V = cval;
CORE_PIN21_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 22: // PTC1, FTM0_CH0
FTM0_C0V = cval;
CORE_PIN22_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 23: // PTC2, FTM0_CH1
FTM0_C1V = cval;
CORE_PIN23_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
#if defined(__MK20DX256__)
case 32: // PTB18, FTM2_CH0
FTM2_C0V = cval;
CORE_PIN32_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
case 25: // PTB19, FTM1_CH1
FTM2_C1V = cval;
CORE_PIN25_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
break;
#endif
default:
digitalWrite(pin, (val > 127) ? HIGH : LOW);
pinMode(pin, OUTPUT);
}
}
void analogWriteRes(uint32_t bits)
{
if (bits < 1) {
bits = 1;
} else if (bits > 16) {
bits = 16;
}
analog_write_res = bits;
}
void analogWriteFrequency(uint8_t pin, uint32_t frequency)
{
uint32_t minfreq, prescale, mod;
//serial_print("analogWriteFrequency: pin = ");
//serial_phex(pin);
//serial_print(", freq = ");
//serial_phex32(frequency);
//serial_print("\n");
for (prescale = 0; prescale < 7; prescale++) {
minfreq = (F_BUS >> 16) >> prescale;
if (frequency > minfreq) break;
}
//serial_print("F_BUS = ");
//serial_phex32(F_BUS >> prescale);
//serial_print("\n");
//serial_print("prescale = ");
//serial_phex(prescale);
//serial_print("\n");
//mod = ((F_BUS >> prescale) / frequency) - 1;
mod = (((F_BUS >> prescale) + (frequency >> 1)) / frequency) - 1;
if (mod > 65535) mod = 65535;
//serial_print("mod = ");
//serial_phex32(mod);
//serial_print("\n");
if (pin == 3 || pin == 4) {
FTM1_SC = 0;
FTM1_CNT = 0;
FTM1_MOD = mod;
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(prescale);
} else if (pin == 5 || pin == 6 || pin == 9 || pin == 10 ||
(pin >= 20 && pin <= 23)) {
FTM0_SC = 0;
FTM0_CNT = 0;
FTM0_MOD = mod;
FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(prescale);
}
}
// TODO: startup code needs to initialize all pins to GPIO mode, input by default
void digitalWrite(uint8_t pin, uint8_t val)
{
if (pin >= CORE_NUM_DIGITAL) return;
if (*portModeRegister(pin)) {
if (val) {
*portSetRegister(pin) = 1;
} else {
*portClearRegister(pin) = 1;
}
} else {
volatile uint32_t *config = portConfigRegister(pin);
if (val) {
// TODO use bitband for atomic read-mod-write
*config |= (PORT_PCR_PE | PORT_PCR_PS);
//*config = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS;
} else {
// TODO use bitband for atomic read-mod-write
*config &= ~(PORT_PCR_PE);
//*config = PORT_PCR_MUX(1);
}
}
}
uint8_t digitalRead(uint8_t pin)
{
if (pin >= CORE_NUM_DIGITAL) return 0;
return *portInputRegister(pin);
}
void pinMode(uint8_t pin, uint8_t mode)
{
volatile uint32_t *config;
if (pin >= CORE_NUM_DIGITAL) return;
config = portConfigRegister(pin);
if (mode == OUTPUT) {
*portModeRegister(pin) = 1;
*config = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
} else {
*portModeRegister(pin) = 0;
if (mode == INPUT) {
*config = PORT_PCR_MUX(1);
} else {
*config = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; // pullup
}
}
}
void _shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t value)
{
if (bitOrder == LSBFIRST) {
shiftOut_lsbFirst(dataPin, clockPin, value);
} else {
shiftOut_msbFirst(dataPin, clockPin, value);
}
}
void shiftOut_lsbFirst(uint8_t dataPin, uint8_t clockPin, uint8_t value)
{
uint8_t mask;
for (mask=0x01; mask; mask <<= 1) {
digitalWrite(dataPin, value & mask);
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}
void shiftOut_msbFirst(uint8_t dataPin, uint8_t clockPin, uint8_t value)
{
uint8_t mask;
for (mask=0x80; mask; mask >>= 1) {
digitalWrite(dataPin, value & mask);
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}
uint8_t _shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder)
{
if (bitOrder == LSBFIRST) {
return shiftIn_lsbFirst(dataPin, clockPin);
} else {
return shiftIn_msbFirst(dataPin, clockPin);
}
}
uint8_t shiftIn_lsbFirst(uint8_t dataPin, uint8_t clockPin)
{
uint8_t mask, value=0;
for (mask=0x01; mask; mask <<= 1) {
digitalWrite(clockPin, HIGH);
if (digitalRead(dataPin)) value |= mask;
digitalWrite(clockPin, LOW);
}
return value;
}
uint8_t shiftIn_msbFirst(uint8_t dataPin, uint8_t clockPin)
{
uint8_t mask, value=0;
for (mask=0x80; mask; mask >>= 1) {
digitalWrite(clockPin, HIGH);
if (digitalRead(dataPin)) value |= mask;
digitalWrite(clockPin, LOW);
}
return value;
}
// the systick interrupt is supposed to increment this at 1 kHz rate
volatile uint32_t systick_millis_count = 0;
//uint32_t systick_current, systick_count, systick_istatus; // testing only
uint32_t micros(void)
{
uint32_t count, current, istatus;
__disable_irq();
current = SYST_CVR;
count = systick_millis_count;
istatus = SCB_ICSR; // bit 26 indicates if systick exception pending
__enable_irq();
//systick_current = current;
//systick_count = count;
//systick_istatus = istatus & SCB_ICSR_PENDSTSET ? 1 : 0;
if ((istatus & SCB_ICSR_PENDSTSET) && current > 50) count++;
current = ((F_CPU / 1000) - 1) - current;
return count * 1000 + current / (F_CPU / 1000000);
}
void delay(uint32_t ms)
{
uint32_t start = micros();
if (ms > 0) {
while (1) {
if ((micros() - start) >= 1000) {
ms--;
if (ms == 0) return;
start += 1000;
}
yield();
}
}
}
// TODO: verify these result in correct timeouts...
#if F_CPU == 168000000
#define PULSEIN_LOOPS_PER_USEC 25
#elif F_CPU == 144000000
#define PULSEIN_LOOPS_PER_USEC 21
#elif F_CPU == 120000000
#define PULSEIN_LOOPS_PER_USEC 18
#elif F_CPU == 96000000
#define PULSEIN_LOOPS_PER_USEC 14
#elif F_CPU == 72000000
#define PULSEIN_LOOPS_PER_USEC 10
#elif F_CPU == 48000000
#define PULSEIN_LOOPS_PER_USEC 7
#elif F_CPU == 24000000
#define PULSEIN_LOOPS_PER_USEC 4
#elif F_CPU == 16000000
#define PULSEIN_LOOPS_PER_USEC 1
#elif F_CPU == 8000000
#define PULSEIN_LOOPS_PER_USEC 1
#elif F_CPU == 4000000
#define PULSEIN_LOOPS_PER_USEC 1
#elif F_CPU == 2000000
#define PULSEIN_LOOPS_PER_USEC 1
#endif
uint32_t pulseIn_high(volatile uint8_t *reg, uint32_t timeout)
{
uint32_t timeout_count = timeout * PULSEIN_LOOPS_PER_USEC;
uint32_t usec_start, usec_stop;
// wait for any previous pulse to end
while (*reg) {
if (--timeout_count == 0) return 0;
}
// wait for the pulse to start
while (!*reg) {
if (--timeout_count == 0) return 0;
}
usec_start = micros();
// wait for the pulse to stop
while (*reg) {
if (--timeout_count == 0) return 0;
}
usec_stop = micros();
return usec_stop - usec_start;
}
uint32_t pulseIn_low(volatile uint8_t *reg, uint32_t timeout)
{
uint32_t timeout_count = timeout * PULSEIN_LOOPS_PER_USEC;
uint32_t usec_start, usec_stop;
// wait for any previous pulse to end
while (!*reg) {
if (--timeout_count == 0) return 0;
}
// wait for the pulse to start
while (*reg) {
if (--timeout_count == 0) return 0;
}
usec_start = micros();
// wait for the pulse to stop
while (!*reg) {
if (--timeout_count == 0) return 0;
}
usec_stop = micros();
return usec_stop - usec_start;
}
// TODO: an inline version should handle the common case where state is const
uint32_t pulseIn(uint8_t pin, uint8_t state, uint32_t timeout)
{
if (pin >= CORE_NUM_DIGITAL) return 0;
if (state) return pulseIn_high(portInputRegister(pin), timeout);
return pulseIn_low(portInputRegister(pin), timeout);;
}

895
teensy/core/usb_desc.c Normal file
View File

@ -0,0 +1,895 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#if F_CPU >= 20000000
#include "usb_desc.h"
#include "usb_names.h"
#include "mk20dx128.h"
#include "avr_functions.h"
// USB Descriptors are binary data which the USB host reads to
// automatically detect a USB device's capabilities. The format
// and meaning of every field is documented in numerous USB
// standards. When working with USB descriptors, despite the
// complexity of the standards and poor writing quality in many
// of those documents, remember descriptors are nothing more
// than constant binary data that tells the USB host what the
// device can do. Computers will load drivers based on this data.
// Those drivers then communicate on the endpoints specified by
// the descriptors.
// To configure a new combination of interfaces or make minor
// changes to existing configuration (eg, change the name or ID
// numbers), usually you would edit "usb_desc.h". This file
// is meant to be configured by the header, so generally it is
// only edited to add completely new USB interfaces or features.
// **************************************************************
// USB Device
// **************************************************************
#define LSB(n) ((n) & 255)
#define MSB(n) (((n) >> 8) & 255)
// USB Device Descriptor. The USB host reads this first, to learn
// what type of device is connected.
static uint8_t device_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x00, 0x02, // bcdUSB
#ifdef DEVICE_CLASS
DEVICE_CLASS, // bDeviceClass
#else
0,
#endif
#ifdef DEVICE_SUBCLASS
DEVICE_SUBCLASS, // bDeviceSubClass
#else
0,
#endif
#ifdef DEVICE_PROTOCOL
DEVICE_PROTOCOL, // bDeviceProtocol
#else
0,
#endif
EP0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
0x00, 0x01, // bcdDevice
1, // iManufacturer
2, // iProduct
3, // iSerialNumber
1 // bNumConfigurations
};
// These descriptors must NOT be "const", because the USB DMA
// has trouble accessing flash memory with enough bandwidth
// while the processor is executing from flash.
// **************************************************************
// HID Report Descriptors
// **************************************************************
// Each HID interface needs a special report descriptor that tells
// the meaning and format of the data.
#ifdef KEYBOARD_INTERFACE
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
static uint8_t keyboard_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
0x95, 0x08, // Report Count (8),
0x75, 0x01, // Report Size (1),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x05, 0x0C, // Usage Page (Consumer),
0x09, 0xE9, // Usage (Volume Increment),
0x09, 0xEA, // Usage (Volume Decrement),
0x09, 0xE2, // Usage (Mute),
0x09, 0xCD, // Usage (Play/Pause),
0x09, 0xB5, // Usage (Scan Next Track),
0x09, 0xB6, // Usage (Scan Previous Track),
0x09, 0xB7, // Usage (Stop),
0x09, 0xB8, // Usage (Eject),
0x81, 0x02, // Input (Data, Variable, Absolute), ;Media keys
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x05, 0x08, // Usage Page (LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x03, // Output (Constant), ;LED report padding
0x95, 0x06, // Report Count (6),
0x75, 0x08, // Report Size (8),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x7F, // Logical Maximum(104),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, 0x7F, // Usage Maximum (104),
0x81, 0x00, // Input (Data, Array), ;Normal keys
0xc0 // End Collection
};
#endif
#ifdef MOUSE_INTERFACE
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
static uint8_t mouse_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // REPORT_ID (1)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button #1)
0x29, 0x08, // Usage Maximum (Button #8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x08, // Report Count (8)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8),
0x95, 0x03, // Report Count (3),
0x81, 0x06, // Input (Data, Variable, Relative)
0xC0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x85, 0x02, // REPORT_ID (2)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
0x75, 0x10, // Report Size (16),
0x95, 0x02, // Report Count (2),
0x81, 0x02, // Input (Data, Variable, Absolute)
0xC0 // End Collection
};
#endif
#ifdef JOYSTICK_INTERFACE
static uint8_t joystick_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x20, // Report Count (32)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button #1)
0x29, 0x20, // Usage Maximum (Button #32)
0x81, 0x02, // Input (variable,absolute)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x65, 0x14, // Unit (20)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (variable,absolute,null_state)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection ()
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x04, // Report Count (4)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x81, 0x02, // Input (variable,absolute)
0xC0, // End Collection
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x02, // Report Count (2)
0x09, 0x36, // Usage (Slider)
0x09, 0x36, // Usage (Slider)
0x81, 0x02, // Input (variable,absolute)
0xC0 // End Collection
};
#endif
#ifdef SEREMU_INTERFACE
static uint8_t seremu_report_desc[] = {
0x06, 0xC9, 0xFF, // Usage Page 0xFFC9 (vendor defined)
0x09, 0x04, // Usage 0x04
0xA1, 0x5C, // Collection 0x5C
0x75, 0x08, // report size = 8 bits (global)
0x15, 0x00, // logical minimum = 0 (global)
0x26, 0xFF, 0x00, // logical maximum = 255 (global)
0x95, SEREMU_TX_SIZE, // report count (global)
0x09, 0x75, // usage (local)
0x81, 0x02, // Input
0x95, SEREMU_RX_SIZE, // report count (global)
0x09, 0x76, // usage (local)
0x91, 0x02, // Output
0x95, 0x04, // report count (global)
0x09, 0x76, // usage (local)
0xB1, 0x02, // Feature
0xC0 // end collection
};
#endif
#ifdef RAWHID_INTERFACE
static uint8_t rawhid_report_desc[] = {
0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE),
0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE),
0xA1, 0x01, // Collection 0x01
0x75, 0x08, // report size = 8 bits
0x15, 0x00, // logical minimum = 0
0x26, 0xFF, 0x00, // logical maximum = 255
0x95, RAWHID_TX_SIZE, // report count
0x09, 0x01, // usage
0x81, 0x02, // Input (array)
0x95, RAWHID_RX_SIZE, // report count
0x09, 0x02, // usage
0x91, 0x02, // Output (array)
0xC0 // end collection
};
#endif
#ifdef FLIGHTSIM_INTERFACE
static uint8_t flightsim_report_desc[] = {
0x06, 0x1C, 0xFF, // Usage page = 0xFF1C
0x0A, 0x39, 0xA7, // Usage = 0xA739
0xA1, 0x01, // Collection 0x01
0x75, 0x08, // report size = 8 bits
0x15, 0x00, // logical minimum = 0
0x26, 0xFF, 0x00, // logical maximum = 255
0x95, FLIGHTSIM_TX_SIZE, // report count
0x09, 0x01, // usage
0x81, 0x02, // Input (array)
0x95, FLIGHTSIM_RX_SIZE, // report count
0x09, 0x02, // usage
0x91, 0x02, // Output (array)
0xC0 // end collection
};
#endif
// **************************************************************
// USB Configuration
// **************************************************************
// USB Configuration Descriptor. This huge descriptor tells all
// of the devices capbilities.
static uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG_DESC_SIZE), // wTotalLength
MSB(CONFIG_DESC_SIZE),
NUM_INTERFACE, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0xC0, // bmAttributes
50, // bMaxPower
#ifdef CDC_IAD_DESCRIPTOR
// interface association descriptor, USB ECN, Table 9-Z
8, // bLength
11, // bDescriptorType
CDC_STATUS_INTERFACE, // bFirstInterface
2, // bInterfaceCount
0x02, // bFunctionClass
0x02, // bFunctionSubClass
0x01, // bFunctionProtocol
4, // iFunction
#endif
#ifdef CDC_DATA_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
CDC_STATUS_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x02, // bInterfaceClass
0x02, // bInterfaceSubClass
0x01, // bInterfaceProtocol
0, // iInterface
// CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26
5, // bFunctionLength
0x24, // bDescriptorType
0x00, // bDescriptorSubtype
0x10, 0x01, // bcdCDC
// Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27
5, // bFunctionLength
0x24, // bDescriptorType
0x01, // bDescriptorSubtype
0x01, // bmCapabilities
1, // bDataInterface
// Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28
4, // bFunctionLength
0x24, // bDescriptorType
0x02, // bDescriptorSubtype
0x06, // bmCapabilities
// Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33
5, // bFunctionLength
0x24, // bDescriptorType
0x06, // bDescriptorSubtype
CDC_STATUS_INTERFACE, // bMasterInterface
CDC_DATA_INTERFACE, // bSlaveInterface0
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
CDC_ACM_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
CDC_ACM_SIZE, 0, // wMaxPacketSize
64, // bInterval
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
CDC_DATA_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
2, // bNumEndpoints
0x0A, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
CDC_RX_ENDPOINT, // bEndpointAddress
0x02, // bmAttributes (0x02=bulk)
CDC_RX_SIZE, 0, // wMaxPacketSize
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
CDC_TX_ENDPOINT | 0x80, // bEndpointAddress
0x02, // bmAttributes (0x02=bulk)
CDC_TX_SIZE, 0, // wMaxPacketSize
0, // bInterval
#endif // CDC_DATA_INTERFACE
#ifdef MIDI_INTERFACE
// Standard MS Interface Descriptor,
9, // bLength
4, // bDescriptorType
MIDI_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
2, // bNumEndpoints
0x01, // bInterfaceClass (0x01 = Audio)
0x03, // bInterfaceSubClass (0x03 = MIDI)
0x00, // bInterfaceProtocol (unused for MIDI)
0, // iInterface
// MIDI MS Interface Header, USB MIDI 6.1.2.1, page 21, Table 6-2
7, // bLength
0x24, // bDescriptorType = CS_INTERFACE
0x01, // bDescriptorSubtype = MS_HEADER
0x00, 0x01, // bcdMSC = revision 01.00
0x41, 0x00, // wTotalLength
// MIDI IN Jack Descriptor, B.4.3, Table B-7 (embedded), page 40
6, // bLength
0x24, // bDescriptorType = CS_INTERFACE
0x02, // bDescriptorSubtype = MIDI_IN_JACK
0x01, // bJackType = EMBEDDED
1, // bJackID, ID = 1
0, // iJack
// MIDI IN Jack Descriptor, B.4.3, Table B-8 (external), page 40
6, // bLength
0x24, // bDescriptorType = CS_INTERFACE
0x02, // bDescriptorSubtype = MIDI_IN_JACK
0x02, // bJackType = EXTERNAL
2, // bJackID, ID = 2
0, // iJack
// MIDI OUT Jack Descriptor, B.4.4, Table B-9, page 41
9,
0x24, // bDescriptorType = CS_INTERFACE
0x03, // bDescriptorSubtype = MIDI_OUT_JACK
0x01, // bJackType = EMBEDDED
3, // bJackID, ID = 3
1, // bNrInputPins = 1 pin
2, // BaSourceID(1) = 2
1, // BaSourcePin(1) = first pin
0, // iJack
// MIDI OUT Jack Descriptor, B.4.4, Table B-10, page 41
9,
0x24, // bDescriptorType = CS_INTERFACE
0x03, // bDescriptorSubtype = MIDI_OUT_JACK
0x02, // bJackType = EXTERNAL
4, // bJackID, ID = 4
1, // bNrInputPins = 1 pin
1, // BaSourceID(1) = 1
1, // BaSourcePin(1) = first pin
0, // iJack
// Standard Bulk OUT Endpoint Descriptor, B.5.1, Table B-11, pae 42
9, // bLength
5, // bDescriptorType = ENDPOINT
MIDI_RX_ENDPOINT, // bEndpointAddress
0x02, // bmAttributes (0x02=bulk)
MIDI_RX_SIZE, 0, // wMaxPacketSize
0, // bInterval
0, // bRefresh
0, // bSynchAddress
// Class-specific MS Bulk OUT Endpoint Descriptor, B.5.2, Table B-12, page 42
5, // bLength
0x25, // bDescriptorSubtype = CS_ENDPOINT
0x01, // bJackType = MS_GENERAL
1, // bNumEmbMIDIJack = 1 jack
1, // BaAssocJackID(1) = jack ID #1
// Standard Bulk IN Endpoint Descriptor, B.5.1, Table B-11, pae 42
9, // bLength
5, // bDescriptorType = ENDPOINT
MIDI_TX_ENDPOINT | 0x80, // bEndpointAddress
0x02, // bmAttributes (0x02=bulk)
MIDI_TX_SIZE, 0, // wMaxPacketSize
0, // bInterval
0, // bRefresh
0, // bSynchAddress
// Class-specific MS Bulk IN Endpoint Descriptor, B.5.2, Table B-12, page 42
5, // bLength
0x25, // bDescriptorSubtype = CS_ENDPOINT
0x01, // bJackType = MS_GENERAL
1, // bNumEmbMIDIJack = 1 jack
3, // BaAssocJackID(1) = jack ID #3
#endif // MIDI_INTERFACE
#ifdef KEYBOARD_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
KEYBOARD_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x01, // bInterfaceSubClass (0x01 = Boot)
0x01, // bInterfaceProtocol (0x01 = Keyboard)
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
LSB(sizeof(keyboard_report_desc)), // wDescriptorLength
MSB(sizeof(keyboard_report_desc)),
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
KEYBOARD_SIZE, 0, // wMaxPacketSize
KEYBOARD_INTERVAL, // bInterval
#endif // KEYBOARD_INTERFACE
#ifdef MOUSE_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
MOUSE_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass (0x01 = Boot)
0x00, // bInterfaceProtocol (0x02 = Mouse)
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
LSB(sizeof(mouse_report_desc)), // wDescriptorLength
MSB(sizeof(mouse_report_desc)),
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
MOUSE_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
MOUSE_SIZE, 0, // wMaxPacketSize
MOUSE_INTERVAL, // bInterval
#endif // MOUSE_INTERFACE
#ifdef RAWHID_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
RAWHID_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
2, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
LSB(sizeof(rawhid_report_desc)), // wDescriptorLength
MSB(sizeof(rawhid_report_desc)),
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
RAWHID_TX_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
RAWHID_TX_SIZE, 0, // wMaxPacketSize
RAWHID_TX_INTERVAL, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
RAWHID_RX_ENDPOINT, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
RAWHID_RX_SIZE, 0, // wMaxPacketSize
RAWHID_RX_INTERVAL, // bInterval
#endif // RAWHID_INTERFACE
#ifdef FLIGHTSIM_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
FLIGHTSIM_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
2, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
LSB(sizeof(flightsim_report_desc)), // wDescriptorLength
MSB(sizeof(flightsim_report_desc)),
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
FLIGHTSIM_TX_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
FLIGHTSIM_TX_SIZE, 0, // wMaxPacketSize
FLIGHTSIM_TX_INTERVAL, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
FLIGHTSIM_RX_ENDPOINT, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
FLIGHTSIM_RX_SIZE, 0, // wMaxPacketSize
FLIGHTSIM_RX_INTERVAL, // bInterval
#endif // FLIGHTSIM_INTERFACE
#ifdef SEREMU_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
SEREMU_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
2, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
LSB(sizeof(seremu_report_desc)), // wDescriptorLength
MSB(sizeof(seremu_report_desc)),
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
SEREMU_TX_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
SEREMU_TX_SIZE, 0, // wMaxPacketSize
SEREMU_TX_INTERVAL, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
SEREMU_RX_ENDPOINT, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
SEREMU_RX_SIZE, 0, // wMaxPacketSize
SEREMU_RX_INTERVAL, // bInterval
#endif // SEREMU_INTERFACE
#ifdef JOYSTICK_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
JOYSTICK_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
LSB(sizeof(joystick_report_desc)), // wDescriptorLength
MSB(sizeof(joystick_report_desc)),
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
JOYSTICK_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
JOYSTICK_SIZE, 0, // wMaxPacketSize
JOYSTICK_INTERVAL, // bInterval
#endif // JOYSTICK_INTERFACE
};
// **************************************************************
// String Descriptors
// **************************************************************
// The descriptors above can provide human readable strings,
// referenced by index numbers. These descriptors are the
// actual string data
/* defined in usb_names.h
struct usb_string_descriptor_struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wString[];
};
*/
extern struct usb_string_descriptor_struct usb_string_manufacturer_name
__attribute__ ((weak, alias("usb_string_manufacturer_name_default")));
extern struct usb_string_descriptor_struct usb_string_product_name
__attribute__ ((weak, alias("usb_string_product_name_default")));
extern struct usb_string_descriptor_struct usb_string_serial_number
__attribute__ ((weak, alias("usb_string_serial_number_default")));
struct usb_string_descriptor_struct string0 = {
4,
3,
{0x0409}
};
struct usb_string_descriptor_struct usb_string_manufacturer_name_default = {
2 + MANUFACTURER_NAME_LEN * 2,
3,
MANUFACTURER_NAME
};
struct usb_string_descriptor_struct usb_string_product_name_default = {
2 + PRODUCT_NAME_LEN * 2,
3,
PRODUCT_NAME
};
struct usb_string_descriptor_struct usb_string_serial_number_default = {
12,
3,
{0,0,0,0,0,0,0,0,0,0}
};
void usb_init_serialnumber(void)
{
char buf[11];
uint32_t i, num;
__disable_irq();
FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
FTFL_FCCOB0 = 0x41;
FTFL_FCCOB1 = 15;
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
num = *(uint32_t *)&FTFL_FCCOB7;
__enable_irq();
// add extra zero to work around OS-X CDC-ACM driver bug
if (num < 10000000) num = num * 10;
ultoa(num, buf, 10);
for (i=0; i<10; i++) {
char c = buf[i];
if (!c) break;
usb_string_serial_number_default.wString[i] = c;
}
usb_string_serial_number_default.bLength = i * 2 + 2;
}
// **************************************************************
// Descriptors List
// **************************************************************
// This table provides access to all the descriptor data above.
const usb_descriptor_list_t usb_descriptor_list[] = {
//wValue, wIndex, address, length
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config_descriptor, sizeof(config_descriptor)},
#ifdef SEREMU_INTERFACE
{0x2200, SEREMU_INTERFACE, seremu_report_desc, sizeof(seremu_report_desc)},
{0x2100, SEREMU_INTERFACE, config_descriptor+SEREMU_DESC_OFFSET, 9},
#endif
#ifdef KEYBOARD_INTERFACE
{0x2200, KEYBOARD_INTERFACE, keyboard_report_desc, sizeof(keyboard_report_desc)},
{0x2100, KEYBOARD_INTERFACE, config_descriptor+KEYBOARD_DESC_OFFSET, 9},
#endif
#ifdef MOUSE_INTERFACE
{0x2200, MOUSE_INTERFACE, mouse_report_desc, sizeof(mouse_report_desc)},
{0x2100, MOUSE_INTERFACE, config_descriptor+MOUSE_DESC_OFFSET, 9},
#endif
#ifdef JOYSTICK_INTERFACE
{0x2200, JOYSTICK_INTERFACE, joystick_report_desc, sizeof(joystick_report_desc)},
{0x2100, JOYSTICK_INTERFACE, config_descriptor+JOYSTICK_DESC_OFFSET, 9},
#endif
#ifdef RAWHID_INTERFACE
{0x2200, RAWHID_INTERFACE, rawhid_report_desc, sizeof(rawhid_report_desc)},
{0x2100, RAWHID_INTERFACE, config_descriptor+RAWHID_DESC_OFFSET, 9},
#endif
#ifdef FLIGHTSIM_INTERFACE
{0x2200, FLIGHTSIM_INTERFACE, flightsim_report_desc, sizeof(flightsim_report_desc)},
{0x2100, FLIGHTSIM_INTERFACE, config_descriptor+FLIGHTSIM_DESC_OFFSET, 9},
#endif
{0x0300, 0x0000, (const uint8_t *)&string0, 0},
{0x0301, 0x0409, (const uint8_t *)&usb_string_manufacturer_name, 0},
{0x0302, 0x0409, (const uint8_t *)&usb_string_product_name, 0},
{0x0303, 0x0409, (const uint8_t *)&usb_string_serial_number, 0},
//{0x0301, 0x0409, (const uint8_t *)&string1, 0},
//{0x0302, 0x0409, (const uint8_t *)&string2, 0},
//{0x0303, 0x0409, (const uint8_t *)&string3, 0},
{0, 0, NULL, 0}
};
// **************************************************************
// Endpoint Configuration
// **************************************************************
#if 0
// 0x00 = not used
// 0x19 = Recieve only
// 0x15 = Transmit only
// 0x1D = Transmit & Recieve
//
const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] =
{
0x00, 0x15, 0x19, 0x15, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif
const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] =
{
#if (defined(ENDPOINT1_CONFIG) && NUM_ENDPOINTS >= 1)
ENDPOINT1_CONFIG,
#elif (NUM_ENDPOINTS >= 1)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT2_CONFIG) && NUM_ENDPOINTS >= 2)
ENDPOINT2_CONFIG,
#elif (NUM_ENDPOINTS >= 2)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT3_CONFIG) && NUM_ENDPOINTS >= 3)
ENDPOINT3_CONFIG,
#elif (NUM_ENDPOINTS >= 3)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT4_CONFIG) && NUM_ENDPOINTS >= 4)
ENDPOINT4_CONFIG,
#elif (NUM_ENDPOINTS >= 4)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT5_CONFIG) && NUM_ENDPOINTS >= 5)
ENDPOINT5_CONFIG,
#elif (NUM_ENDPOINTS >= 5)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT6_CONFIG) && NUM_ENDPOINTS >= 6)
ENDPOINT6_CONFIG,
#elif (NUM_ENDPOINTS >= 6)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT7_CONFIG) && NUM_ENDPOINTS >= 7)
ENDPOINT7_CONFIG,
#elif (NUM_ENDPOINTS >= 7)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT8_CONFIG) && NUM_ENDPOINTS >= 8)
ENDPOINT8_CONFIG,
#elif (NUM_ENDPOINTS >= 8)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT9_CONFIG) && NUM_ENDPOINTS >= 9)
ENDPOINT9_CONFIG,
#elif (NUM_ENDPOINTS >= 9)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT10_CONFIG) && NUM_ENDPOINTS >= 10)
ENDPOINT10_CONFIG,
#elif (NUM_ENDPOINTS >= 10)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT11_CONFIG) && NUM_ENDPOINTS >= 11)
ENDPOINT11_CONFIG,
#elif (NUM_ENDPOINTS >= 11)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT12_CONFIG) && NUM_ENDPOINTS >= 12)
ENDPOINT12_CONFIG,
#elif (NUM_ENDPOINTS >= 12)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT13_CONFIG) && NUM_ENDPOINTS >= 13)
ENDPOINT13_CONFIG,
#elif (NUM_ENDPOINTS >= 13)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT14_CONFIG) && NUM_ENDPOINTS >= 14)
ENDPOINT14_CONFIG,
#elif (NUM_ENDPOINTS >= 14)
ENDPOINT_UNUSED,
#endif
#if (defined(ENDPOINT15_CONFIG) && NUM_ENDPOINTS >= 15)
ENDPOINT15_CONFIG,
#elif (NUM_ENDPOINTS >= 15)
ENDPOINT_UNUSED,
#endif
};
#endif // F_CPU >= 20 MHz

313
teensy/core/usb_desc.h Normal file
View File

@ -0,0 +1,313 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _usb_desc_h_
#define _usb_desc_h_
#if F_CPU >= 20000000
// This header is NOT meant to be included when compiling
// user sketches in Arduino. The low-level functions
// provided by usb_dev.c are meant to be called only by
// code which provides higher-level interfaces to the user.
#include <stdint.h>
#include <stddef.h>
#define ENDPOINT_UNUSED 0x00
#define ENDPOINT_TRANSIMIT_ONLY 0x15
#define ENDPOINT_RECEIVE_ONLY 0x19
#define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D
/*
To modify a USB Type to have different interfaces, start in this
file. Delete the XYZ_INTERFACE lines for any interfaces you
wish to remove, and copy them from another USB Type for any you
want to add.
Give each interface a unique number, and edit NUM_INTERFACE to
reflect the number of interfaces.
Within each interface, make sure it uses a unique set of endpoints.
Edit NUM_ENDPOINTS to be at least the largest endpoint number used.
Then edit the ENDPOINT*_CONFIG lines so each endpoint is configured
the proper way (transmit, receive, or both).
The CONFIG_DESC_SIZE and any XYZ_DESC_OFFSET numbers must be
edited to the correct sizes. See usb_desc.c for the giant array
of bytes. Someday these may be done automatically..... (but how?)
If you are using existing interfaces, the code in each file should
automatically adapt to the changes you specify. If you need to
create a new type of interface, you'll need to write the code which
sends and receives packets, and presents an API to the user.
Finally, edit usb_inst.cpp, which creats instances of the C++
objects for each combination.
Some operating systems, especially Windows, may cache USB device
info. Changes to the device name may not update on the same
computer unless the vendor or product ID numbers change, or the
"bcdDevice" revision code is increased.
If these instructions are missing steps or could be improved, please
let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
*/
#if defined(USB_SERIAL)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0483
#define DEVICE_CLASS 2 // 2 = Communication Class
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'U','S','B',' ','S','e','r','i','a','l'}
#define PRODUCT_NAME_LEN 10
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 12
#define NUM_INTERFACE 2
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1
#define CDC_ACM_ENDPOINT 2
#define CDC_RX_ENDPOINT 3
#define CDC_TX_ENDPOINT 4
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define CONFIG_DESC_SIZE (9+9+5+5+4+5+7+9+7+7)
#define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY
#elif defined(USB_HID)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0482
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}
#define PRODUCT_NAME_LEN 23
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 24
#define NUM_INTERFACE 4
#define SEREMU_INTERFACE 2 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define KEYBOARD_INTERFACE 0 // Keyboard
#define KEYBOARD_ENDPOINT 3
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define MOUSE_INTERFACE 1 // Mouse
#define MOUSE_ENDPOINT 5
#define MOUSE_SIZE 8
#define MOUSE_INTERVAL 1
#define JOYSTICK_INTERFACE 3 // Joystick
#define JOYSTICK_ENDPOINT 4
#define JOYSTICK_SIZE 16
#define JOYSTICK_INTERVAL 2
#define KEYBOARD_DESC_OFFSET (9 + 9)
#define MOUSE_DESC_OFFSET (9 + 9+9+7 + 9)
#define SEREMU_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 9)
#define JOYSTICK_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9)
#define CONFIG_DESC_SIZE (9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9+9+7)
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY
#elif defined(USB_SERIAL_HID)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0487
#define DEVICE_CLASS 0xEF
#define DEVICE_SUBCLASS 0x02
#define DEVICE_PROTOCOL 0x01
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'S','e','r','i','a','l','/','K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}
#define PRODUCT_NAME_LEN 30
#define EP0_SIZE 64
#define NUM_ENDPOINTS 6
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 5
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 2
#define CDC_RX_ENDPOINT 3
#define CDC_TX_ENDPOINT 4
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define KEYBOARD_INTERFACE 2 // Keyboard
#define KEYBOARD_ENDPOINT 1
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define MOUSE_INTERFACE 3 // Mouse
#define MOUSE_ENDPOINT 5
#define MOUSE_SIZE 8
#define MOUSE_INTERVAL 2
#define JOYSTICK_INTERFACE 4 // Joystick
#define JOYSTICK_ENDPOINT 6
#define JOYSTICK_SIZE 16
#define JOYSTICK_INTERVAL 1
#define KEYBOARD_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9)
#define MOUSE_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9)
#define JOYSTICK_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9)
#define CONFIG_DESC_SIZE (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9+9+7)
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY
#elif defined(USB_MIDI)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0485
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I'}
#define PRODUCT_NAME_LEN 11
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 2
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define MIDI_INTERFACE 0 // MIDI
#define MIDI_TX_ENDPOINT 3
#define MIDI_TX_SIZE 64
#define MIDI_RX_ENDPOINT 4
#define MIDI_RX_SIZE 64
#define SEREMU_DESC_OFFSET (9 + 9+7+6+6+9+9+9+5+9+5 + 9)
#define CONFIG_DESC_SIZE (9 + 9+7+6+6+9+9+9+5+9+5 + 9+9+7+7)
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_RAWHID)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0486
#define RAWHID_USAGE_PAGE 0xFFAB // recommended: 0xFF00 to 0xFFFF
#define RAWHID_USAGE 0x0200 // recommended: 0x0100 to 0xFFFF
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y','d','u','i','n','o',' ','R','a','w','H','I','D'}
#define PRODUCT_NAME_LEN 18
#define EP0_SIZE 64
#define NUM_ENDPOINTS 6
#define NUM_USB_BUFFERS 12
#define NUM_INTERFACE 2
#define RAWHID_INTERFACE 0 // RawHID
#define RAWHID_TX_ENDPOINT 3
#define RAWHID_TX_SIZE 64
#define RAWHID_TX_INTERVAL 1
#define RAWHID_RX_ENDPOINT 4
#define RAWHID_RX_SIZE 64
#define RAWHID_RX_INTERVAL 1
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define RAWHID_DESC_OFFSET (9 + 9)
#define SEREMU_DESC_OFFSET (9 + 9+9+7+7 + 9)
#define CONFIG_DESC_SIZE (9 + 9+9+7+7 + 9+9+7+7)
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#elif defined(USB_FLIGHTSIM)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0488
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','F','l','i','g','h','t',' ','S','i','m',' ','C','o','n','t','r','o','l','s'}
#define PRODUCT_NAME_LEN 26
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 20
#define NUM_INTERFACE 2
#define FLIGHTSIM_INTERFACE 0 // Flight Sim Control
#define FLIGHTSIM_TX_ENDPOINT 3
#define FLIGHTSIM_TX_SIZE 64
#define FLIGHTSIM_TX_INTERVAL 1
#define FLIGHTSIM_RX_ENDPOINT 4
#define FLIGHTSIM_RX_SIZE 64
#define FLIGHTSIM_RX_INTERVAL 1
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define FLIGHTSIM_DESC_OFFSET (9 + 9)
#define SEREMU_DESC_OFFSET (9 + 9+9+7+7 + 9)
#define CONFIG_DESC_SIZE (9 + 9+9+7+7 + 9+9+7+7)
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
#endif
// NUM_ENDPOINTS = number of non-zero endpoints (0 to 15)
extern const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS];
typedef struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint16_t length;
} usb_descriptor_list_t;
extern const usb_descriptor_list_t usb_descriptor_list[];
#endif // F_CPU >= 20 MHz
#endif

980
teensy/core/usb_dev.c Normal file
View File

@ -0,0 +1,980 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#if F_CPU >= 20000000
#include "mk20dx128.h"
//#include "HardwareSerial.h"
#include "usb_dev.h"
#include "usb_mem.h"
// buffer descriptor table
typedef struct {
uint32_t desc;
void * addr;
} bdt_t;
__attribute__ ((section(".usbdescriptortable"), used))
static bdt_t table[(NUM_ENDPOINTS+1)*4];
static usb_packet_t *rx_first[NUM_ENDPOINTS];
static usb_packet_t *rx_last[NUM_ENDPOINTS];
static usb_packet_t *tx_first[NUM_ENDPOINTS];
static usb_packet_t *tx_last[NUM_ENDPOINTS];
uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS];
static uint8_t tx_state[NUM_ENDPOINTS];
#define TX_STATE_BOTH_FREE_EVEN_FIRST 0
#define TX_STATE_BOTH_FREE_ODD_FIRST 1
#define TX_STATE_EVEN_FREE 2
#define TX_STATE_ODD_FREE 3
#define TX_STATE_NONE_FREE_EVEN_FIRST 4
#define TX_STATE_NONE_FREE_ODD_FIRST 5
#define BDT_OWN 0x80
#define BDT_DATA1 0x40
#define BDT_DATA0 0x00
#define BDT_DTS 0x08
#define BDT_STALL 0x04
#define BDT_PID(n) (((n) >> 2) & 15)
#define BDT_DESC(count, data) (BDT_OWN | BDT_DTS \
| ((data) ? BDT_DATA1 : BDT_DATA0) \
| ((count) << 16))
#define TX 1
#define RX 0
#define ODD 1
#define EVEN 0
#define DATA0 0
#define DATA1 1
#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd))
#define stat2bufferdescriptor(stat) (table + ((stat) >> 2))
static union {
struct {
union {
struct {
uint8_t bmRequestType;
uint8_t bRequest;
};
uint16_t wRequestAndType;
};
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
};
struct {
uint32_t word1;
uint32_t word2;
};
} setup;
#define GET_STATUS 0
#define CLEAR_FEATURE 1
#define SET_FEATURE 3
#define SET_ADDRESS 5
#define GET_DESCRIPTOR 6
#define SET_DESCRIPTOR 7
#define GET_CONFIGURATION 8
#define SET_CONFIGURATION 9
#define GET_INTERFACE 10
#define SET_INTERFACE 11
#define SYNCH_FRAME 12
// SETUP always uses a DATA0 PID for the data field of the SETUP transaction.
// transactions in the data phase start with DATA1 and toggle (figure 8-12, USB1.1)
// Status stage uses a DATA1 PID.
static uint8_t ep0_rx0_buf[EP0_SIZE] __attribute__ ((aligned (4)));
static uint8_t ep0_rx1_buf[EP0_SIZE] __attribute__ ((aligned (4)));
static const uint8_t *ep0_tx_ptr = NULL;
static uint16_t ep0_tx_len;
static uint8_t ep0_tx_bdt_bank = 0;
static uint8_t ep0_tx_data_toggle = 0;
uint8_t usb_rx_memory_needed = 0;
volatile uint8_t usb_configuration = 0;
volatile uint8_t usb_reboot_timer = 0;
static void endpoint0_stall(void)
{
USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK;
}
static void endpoint0_transmit(const void *data, uint32_t len)
{
#if 0
serial_print("tx0:");
serial_phex32((uint32_t)data);
serial_print(",");
serial_phex16(len);
serial_print(ep0_tx_bdt_bank ? ", odd" : ", even");
serial_print(ep0_tx_data_toggle ? ", d1\n" : ", d0\n");
#endif
table[index(0, TX, ep0_tx_bdt_bank)].addr = (void *)data;
table[index(0, TX, ep0_tx_bdt_bank)].desc = BDT_DESC(len, ep0_tx_data_toggle);
ep0_tx_data_toggle ^= 1;
ep0_tx_bdt_bank ^= 1;
}
static uint8_t reply_buffer[8];
static void usb_setup(void)
{
const uint8_t *data = NULL;
uint32_t datalen = 0;
const usb_descriptor_list_t *list;
uint32_t size;
volatile uint8_t *reg;
uint8_t epconf;
const uint8_t *cfg;
int i;
switch (setup.wRequestAndType) {
case 0x0500: // SET_ADDRESS
break;
case 0x0900: // SET_CONFIGURATION
//serial_print("configure\n");
usb_configuration = setup.wValue;
reg = &USB0_ENDPT1;
cfg = usb_endpoint_config_table;
// clear all BDT entries, free any allocated memory...
for (i=4; i < (NUM_ENDPOINTS+1)*4; i++) {
if (table[i].desc & BDT_OWN) {
usb_free((usb_packet_t *)((uint8_t *)(table[i].addr) - 8));
}
}
// free all queued packets
for (i=0; i < NUM_ENDPOINTS; i++) {
usb_packet_t *p, *n;
p = rx_first[i];
while (p) {
n = p->next;
usb_free(p);
p = n;
}
rx_first[i] = NULL;
rx_last[i] = NULL;
p = tx_first[i];
while (p) {
n = p->next;
usb_free(p);
p = n;
}
tx_first[i] = NULL;
tx_last[i] = NULL;
usb_rx_byte_count_data[i] = 0;
switch (tx_state[i]) {
case TX_STATE_EVEN_FREE:
case TX_STATE_NONE_FREE_EVEN_FIRST:
tx_state[i] = TX_STATE_BOTH_FREE_EVEN_FIRST;
break;
case TX_STATE_ODD_FREE:
case TX_STATE_NONE_FREE_ODD_FIRST:
tx_state[i] = TX_STATE_BOTH_FREE_ODD_FIRST;
break;
default:
break;
}
}
usb_rx_memory_needed = 0;
for (i=1; i <= NUM_ENDPOINTS; i++) {
epconf = *cfg++;
*reg = epconf;
reg += 4;
if (epconf & USB_ENDPT_EPRXEN) {
usb_packet_t *p;
p = usb_malloc();
if (p) {
table[index(i, RX, EVEN)].addr = p->buf;
table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0);
} else {
table[index(i, RX, EVEN)].desc = 0;
usb_rx_memory_needed++;
}
p = usb_malloc();
if (p) {
table[index(i, RX, ODD)].addr = p->buf;
table[index(i, RX, ODD)].desc = BDT_DESC(64, 1);
} else {
table[index(i, RX, ODD)].desc = 0;
usb_rx_memory_needed++;
}
}
table[index(i, TX, EVEN)].desc = 0;
table[index(i, TX, ODD)].desc = 0;
}
break;
case 0x0880: // GET_CONFIGURATION
reply_buffer[0] = usb_configuration;
datalen = 1;
data = reply_buffer;
break;
case 0x0080: // GET_STATUS (device)
reply_buffer[0] = 0;
reply_buffer[1] = 0;
datalen = 2;
data = reply_buffer;
break;
case 0x0082: // GET_STATUS (endpoint)
if (setup.wIndex > NUM_ENDPOINTS) {
// TODO: do we need to handle IN vs OUT here?
endpoint0_stall();
return;
}
reply_buffer[0] = 0;
reply_buffer[1] = 0;
if (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4) & 0x02) reply_buffer[0] = 1;
data = reply_buffer;
datalen = 2;
break;
case 0x0102: // CLEAR_FEATURE (endpoint)
i = setup.wIndex & 0x7F;
if (i > NUM_ENDPOINTS || setup.wValue != 0) {
// TODO: do we need to handle IN vs OUT here?
endpoint0_stall();
return;
}
(*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02;
// TODO: do we need to clear the data toggle here?
break;
case 0x0302: // SET_FEATURE (endpoint)
i = setup.wIndex & 0x7F;
if (i > NUM_ENDPOINTS || setup.wValue != 0) {
// TODO: do we need to handle IN vs OUT here?
endpoint0_stall();
return;
}
(*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) |= 0x02;
// TODO: do we need to clear the data toggle here?
break;
case 0x0680: // GET_DESCRIPTOR
case 0x0681:
//serial_print("desc:");
//serial_phex16(setup.wValue);
//serial_print("\n");
for (list = usb_descriptor_list; 1; list++) {
if (list->addr == NULL) break;
//if (setup.wValue == list->wValue &&
//(setup.wIndex == list->wIndex) || ((setup.wValue >> 8) == 3)) {
if (setup.wValue == list->wValue && setup.wIndex == list->wIndex) {
data = list->addr;
if ((setup.wValue >> 8) == 3) {
// for string descriptors, use the descriptor's
// length field, allowing runtime configured
// length.
datalen = *(list->addr);
} else {
datalen = list->length;
}
#if 0
serial_print("Desc found, ");
serial_phex32((uint32_t)data);
serial_print(",");
serial_phex16(datalen);
serial_print(",");
serial_phex(data[0]);
serial_phex(data[1]);
serial_phex(data[2]);
serial_phex(data[3]);
serial_phex(data[4]);
serial_phex(data[5]);
serial_print("\n");
#endif
goto send;
}
}
//serial_print("desc: not found\n");
endpoint0_stall();
return;
#if defined(CDC_STATUS_INTERFACE)
case 0x2221: // CDC_SET_CONTROL_LINE_STATE
usb_cdc_line_rtsdtr = setup.wValue;
//serial_print("set control line state\n");
break;
case 0x2321: // CDC_SEND_BREAK
break;
case 0x2021: // CDC_SET_LINE_CODING
//serial_print("set coding, waiting...\n");
return;
#endif
// TODO: this does not work... why?
#if defined(SEREMU_INTERFACE) || defined(KEYBOARD_INTERFACE)
case 0x0921: // HID SET_REPORT
//serial_print(":)\n");
return;
case 0x0A21: // HID SET_IDLE
break;
// case 0xC940:
#endif
default:
endpoint0_stall();
return;
}
send:
//serial_print("setup send ");
//serial_phex32(data);
//serial_print(",");
//serial_phex16(datalen);
//serial_print("\n");
if (datalen > setup.wLength) datalen = setup.wLength;
size = datalen;
if (size > EP0_SIZE) size = EP0_SIZE;
endpoint0_transmit(data, size);
data += size;
datalen -= size;
if (datalen == 0 && size < EP0_SIZE) return;
size = datalen;
if (size > EP0_SIZE) size = EP0_SIZE;
endpoint0_transmit(data, size);
data += size;
datalen -= size;
if (datalen == 0 && size < EP0_SIZE) return;
ep0_tx_ptr = data;
ep0_tx_len = datalen;
}
//A bulk endpoint's toggle sequence is initialized to DATA0 when the endpoint
//experiences any configuration event (configuration events are explained in
//Sections 9.1.1.5 and 9.4.5).
//Configuring a device or changing an alternate setting causes all of the status
//and configuration values associated with endpoints in the affected interfaces
//to be set to their default values. This includes setting the data toggle of
//any endpoint using data toggles to the value DATA0.
//For endpoints using data toggle, regardless of whether an endpoint has the
//Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the
//data toggle being reinitialized to DATA0.
// #define stat2bufferdescriptor(stat) (table + ((stat) >> 2))
static void usb_control(uint32_t stat)
{
bdt_t *b;
uint32_t pid, size;
uint8_t *buf;
const uint8_t *data;
b = stat2bufferdescriptor(stat);
pid = BDT_PID(b->desc);
//count = b->desc >> 16;
buf = b->addr;
//serial_print("pid:");
//serial_phex(pid);
//serial_print(", count:");
//serial_phex(count);
//serial_print("\n");
switch (pid) {
case 0x0D: // Setup received from host
//serial_print("PID=Setup\n");
//if (count != 8) ; // panic?
// grab the 8 byte setup info
setup.word1 = *(uint32_t *)(buf);
setup.word2 = *(uint32_t *)(buf + 4);
// give the buffer back
b->desc = BDT_DESC(EP0_SIZE, DATA1);
//table[index(0, RX, EVEN)].desc = BDT_DESC(EP0_SIZE, 1);
//table[index(0, RX, ODD)].desc = BDT_DESC(EP0_SIZE, 1);
// clear any leftover pending IN transactions
ep0_tx_ptr = NULL;
if (ep0_tx_data_toggle) {
}
//if (table[index(0, TX, EVEN)].desc & 0x80) {
//serial_print("leftover tx even\n");
//}
//if (table[index(0, TX, ODD)].desc & 0x80) {
//serial_print("leftover tx odd\n");
//}
table[index(0, TX, EVEN)].desc = 0;
table[index(0, TX, ODD)].desc = 0;
// first IN after Setup is always DATA1
ep0_tx_data_toggle = 1;
#if 0
serial_print("bmRequestType:");
serial_phex(setup.bmRequestType);
serial_print(", bRequest:");
serial_phex(setup.bRequest);
serial_print(", wValue:");
serial_phex16(setup.wValue);
serial_print(", wIndex:");
serial_phex16(setup.wIndex);
serial_print(", len:");
serial_phex16(setup.wLength);
serial_print("\n");
#endif
// actually "do" the setup request
usb_setup();
// unfreeze the USB, now that we're ready
USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit
break;
case 0x01: // OUT transaction received from host
case 0x02:
//serial_print("PID=OUT\n");
#ifdef CDC_STATUS_INTERFACE
if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) {
int i;
uint8_t *dst = (uint8_t *)usb_cdc_line_coding;
//serial_print("set line coding ");
for (i=0; i<7; i++) {
//serial_phex(*buf);
*dst++ = *buf++;
}
//serial_phex32(usb_cdc_line_coding[0]);
//serial_print("\n");
if (usb_cdc_line_coding[0] == 134) usb_reboot_timer = 15;
endpoint0_transmit(NULL, 0);
}
#endif
#ifdef KEYBOARD_INTERFACE
if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) {
keyboard_leds = buf[0];
endpoint0_transmit(NULL, 0);
}
#endif
#ifdef SEREMU_INTERFACE
if (setup.word1 == 0x03000921 && setup.word2 == ((4<<16)|SEREMU_INTERFACE)
&& buf[0] == 0xA9 && buf[1] == 0x45 && buf[2] == 0xC2 && buf[3] == 0x6B) {
usb_reboot_timer = 5;
endpoint0_transmit(NULL, 0);
}
#endif
// give the buffer back
b->desc = BDT_DESC(EP0_SIZE, DATA1);
break;
case 0x09: // IN transaction completed to host
//serial_print("PID=IN:");
//serial_phex(stat);
//serial_print("\n");
// send remaining data, if any...
data = ep0_tx_ptr;
if (data) {
size = ep0_tx_len;
if (size > EP0_SIZE) size = EP0_SIZE;
endpoint0_transmit(data, size);
data += size;
ep0_tx_len -= size;
ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL;
}
if (setup.bRequest == 5 && setup.bmRequestType == 0) {
setup.bRequest = 0;
//serial_print("set address: ");
//serial_phex16(setup.wValue);
//serial_print("\n");
USB0_ADDR = setup.wValue;
}
break;
//default:
//serial_print("PID=unknown:");
//serial_phex(pid);
//serial_print("\n");
}
USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit
}
usb_packet_t *usb_rx(uint32_t endpoint)
{
usb_packet_t *ret;
endpoint--;
if (endpoint >= NUM_ENDPOINTS) return NULL;
__disable_irq();
ret = rx_first[endpoint];
if (ret) {
rx_first[endpoint] = ret->next;
usb_rx_byte_count_data[endpoint] -= ret->len;
}
__enable_irq();
//serial_print("rx, epidx=");
//serial_phex(endpoint);
//serial_print(", packet=");
//serial_phex32(ret);
//serial_print("\n");
return ret;
}
static uint32_t usb_queue_byte_count(const usb_packet_t *p)
{
uint32_t count=0;
__disable_irq();
for ( ; p; p = p->next) {
count += p->len;
}
__enable_irq();
return count;
}
// TODO: make this an inline function...
/*
uint32_t usb_rx_byte_count(uint32_t endpoint)
{
endpoint--;
if (endpoint >= NUM_ENDPOINTS) return 0;
return usb_rx_byte_count_data[endpoint];
//return usb_queue_byte_count(rx_first[endpoint]);
}
*/
uint32_t usb_tx_byte_count(uint32_t endpoint)
{
endpoint--;
if (endpoint >= NUM_ENDPOINTS) return 0;
return usb_queue_byte_count(tx_first[endpoint]);
}
uint32_t usb_tx_packet_count(uint32_t endpoint)
{
const usb_packet_t *p;
uint32_t count=0;
endpoint--;
if (endpoint >= NUM_ENDPOINTS) return 0;
__disable_irq();
for (p = tx_first[endpoint]; p; p = p->next) count++;
__enable_irq();
return count;
}
// Called from usb_free, but only when usb_rx_memory_needed > 0, indicating
// receive endpoints are starving for memory. The intention is to give
// endpoints needing receive memory priority over the user's code, which is
// likely calling usb_malloc to obtain memory for transmitting. When the
// user is creating data very quickly, their consumption could starve reception
// without this prioritization. The packet buffer (input) is assigned to the
// first endpoint needing memory.
//
void usb_rx_memory(usb_packet_t *packet)
{
unsigned int i;
const uint8_t *cfg;
cfg = usb_endpoint_config_table;
//serial_print("rx_mem:");
__disable_irq();
for (i=1; i <= NUM_ENDPOINTS; i++) {
if (*cfg++ & USB_ENDPT_EPRXEN) {
if (table[index(i, RX, EVEN)].desc == 0) {
table[index(i, RX, EVEN)].addr = packet->buf;
table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0);
usb_rx_memory_needed--;
__enable_irq();
//serial_phex(i);
//serial_print(",even\n");
return;
}
if (table[index(i, RX, ODD)].desc == 0) {
table[index(i, RX, ODD)].addr = packet->buf;
table[index(i, RX, ODD)].desc = BDT_DESC(64, 1);
usb_rx_memory_needed--;
__enable_irq();
//serial_phex(i);
//serial_print(",odd\n");
return;
}
}
}
__enable_irq();
// we should never reach this point. If we get here, it means
// usb_rx_memory_needed was set greater than zero, but no memory
// was actually needed.
usb_rx_memory_needed = 0;
usb_free(packet);
return;
}
//#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd))
//#define stat2bufferdescriptor(stat) (table + ((stat) >> 2))
void usb_tx(uint32_t endpoint, usb_packet_t *packet)
{
bdt_t *b = &table[index(endpoint, TX, EVEN)];
uint8_t next;
endpoint--;
if (endpoint >= NUM_ENDPOINTS) return;
__disable_irq();
//serial_print("txstate=");
//serial_phex(tx_state[endpoint]);
//serial_print("\n");
switch (tx_state[endpoint]) {
case TX_STATE_BOTH_FREE_EVEN_FIRST:
next = TX_STATE_ODD_FREE;
break;
case TX_STATE_BOTH_FREE_ODD_FIRST:
b++;
next = TX_STATE_EVEN_FREE;
break;
case TX_STATE_EVEN_FREE:
next = TX_STATE_NONE_FREE_ODD_FIRST;
break;
case TX_STATE_ODD_FREE:
b++;
next = TX_STATE_NONE_FREE_EVEN_FIRST;
break;
default:
if (tx_first[endpoint] == NULL) {
tx_first[endpoint] = packet;
} else {
tx_last[endpoint]->next = packet;
}
tx_last[endpoint] = packet;
__enable_irq();
return;
}
tx_state[endpoint] = next;
b->addr = packet->buf;
b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0);
__enable_irq();
}
void _reboot_Teensyduino_(void)
{
// TODO: initialize R0 with a code....
__asm__ volatile("bkpt");
}
void usb_isr(void)
{
uint8_t status, stat, t;
//serial_print("isr");
//status = USB0_ISTAT;
//serial_phex(status);
//serial_print("\n");
restart:
status = USB0_ISTAT;
if ((status & USB_INTEN_SOFTOKEN /* 04 */ )) {
if (usb_configuration) {
t = usb_reboot_timer;
if (t) {
usb_reboot_timer = --t;
if (!t) _reboot_Teensyduino_();
}
#ifdef CDC_DATA_INTERFACE
t = usb_cdc_transmit_flush_timer;
if (t) {
usb_cdc_transmit_flush_timer = --t;
if (t == 0) usb_serial_flush_callback();
}
#endif
#ifdef SEREMU_INTERFACE
t = usb_seremu_transmit_flush_timer;
if (t) {
usb_seremu_transmit_flush_timer = --t;
if (t == 0) usb_seremu_flush_callback();
}
#endif
#ifdef MIDI_INTERFACE
usb_midi_flush_output();
#endif
#ifdef FLIGHTSIM_INTERFACE
usb_flightsim_flush_callback();
#endif
}
USB0_ISTAT = USB_INTEN_SOFTOKEN;
}
if ((status & USB_ISTAT_TOKDNE /* 08 */ )) {
uint8_t endpoint;
stat = USB0_STAT;
//serial_print("token: ep=");
//serial_phex(stat >> 4);
//serial_print(stat & 0x08 ? ",tx" : ",rx");
//serial_print(stat & 0x04 ? ",odd\n" : ",even\n");
endpoint = stat >> 4;
if (endpoint == 0) {
usb_control(stat);
} else {
bdt_t *b = stat2bufferdescriptor(stat);
usb_packet_t *packet = (usb_packet_t *)((uint8_t *)(b->addr) - 8);
#if 0
serial_print("ep:");
serial_phex(endpoint);
serial_print(", pid:");
serial_phex(BDT_PID(b->desc));
serial_print(((uint32_t)b & 8) ? ", odd" : ", even");
serial_print(", count:");
serial_phex(b->desc >> 16);
serial_print("\n");
#endif
endpoint--; // endpoint is index to zero-based arrays
if (stat & 0x08) { // transmit
usb_free(packet);
packet = tx_first[endpoint];
if (packet) {
//serial_print("tx packet\n");
tx_first[endpoint] = packet->next;
b->addr = packet->buf;
switch (tx_state[endpoint]) {
case TX_STATE_BOTH_FREE_EVEN_FIRST:
tx_state[endpoint] = TX_STATE_ODD_FREE;
break;
case TX_STATE_BOTH_FREE_ODD_FIRST:
tx_state[endpoint] = TX_STATE_EVEN_FREE;
break;
case TX_STATE_EVEN_FREE:
tx_state[endpoint] = TX_STATE_NONE_FREE_ODD_FIRST;
break;
case TX_STATE_ODD_FREE:
tx_state[endpoint] = TX_STATE_NONE_FREE_EVEN_FIRST;
break;
default:
break;
}
b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0);
} else {
//serial_print("tx no packet\n");
switch (tx_state[endpoint]) {
case TX_STATE_BOTH_FREE_EVEN_FIRST:
case TX_STATE_BOTH_FREE_ODD_FIRST:
break;
case TX_STATE_EVEN_FREE:
tx_state[endpoint] = TX_STATE_BOTH_FREE_EVEN_FIRST;
break;
case TX_STATE_ODD_FREE:
tx_state[endpoint] = TX_STATE_BOTH_FREE_ODD_FIRST;
break;
default:
tx_state[endpoint] = ((uint32_t)b & 8) ?
TX_STATE_ODD_FREE : TX_STATE_EVEN_FREE;
break;
}
}
} else { // receive
packet->len = b->desc >> 16;
if (packet->len > 0) {
packet->index = 0;
packet->next = NULL;
if (rx_first[endpoint] == NULL) {
//serial_print("rx 1st, epidx=");
//serial_phex(endpoint);
//serial_print(", packet=");
//serial_phex32((uint32_t)packet);
//serial_print("\n");
rx_first[endpoint] = packet;
} else {
//serial_print("rx Nth, epidx=");
//serial_phex(endpoint);
//serial_print(", packet=");
//serial_phex32((uint32_t)packet);
//serial_print("\n");
rx_last[endpoint]->next = packet;
}
rx_last[endpoint] = packet;
usb_rx_byte_count_data[endpoint] += packet->len;
// TODO: implement a per-endpoint maximum # of allocated packets
// so a flood of incoming data on 1 endpoint doesn't starve
// the others if the user isn't reading it regularly
packet = usb_malloc();
if (packet) {
b->addr = packet->buf;
b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0);
} else {
//serial_print("starving ");
//serial_phex(endpoint + 1);
//serial_print(((uint32_t)b & 8) ? ",odd\n" : ",even\n");
b->desc = 0;
usb_rx_memory_needed++;
}
} else {
b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0);
}
}
}
USB0_ISTAT = USB_ISTAT_TOKDNE;
goto restart;
}
if (status & USB_ISTAT_USBRST /* 01 */ ) {
//serial_print("reset\n");
// initialize BDT toggle bits
USB0_CTL = USB_CTL_ODDRST;
ep0_tx_bdt_bank = 0;
// set up buffers to receive Setup and OUT packets
table[index(0, RX, EVEN)].desc = BDT_DESC(EP0_SIZE, 0);
table[index(0, RX, EVEN)].addr = ep0_rx0_buf;
table[index(0, RX, ODD)].desc = BDT_DESC(EP0_SIZE, 0);
table[index(0, RX, ODD)].addr = ep0_rx1_buf;
table[index(0, TX, EVEN)].desc = 0;
table[index(0, TX, ODD)].desc = 0;
// activate endpoint 0
USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK;
// clear all ending interrupts
USB0_ERRSTAT = 0xFF;
USB0_ISTAT = 0xFF;
// set the address to zero during enumeration
USB0_ADDR = 0;
// enable other interrupts
USB0_ERREN = 0xFF;
USB0_INTEN = USB_INTEN_TOKDNEEN |
USB_INTEN_SOFTOKEN |
USB_INTEN_STALLEN |
USB_INTEN_ERROREN |
USB_INTEN_USBRSTEN |
USB_INTEN_SLEEPEN;
// is this necessary?
USB0_CTL = USB_CTL_USBENSOFEN;
return;
}
if ((status & USB_ISTAT_STALL /* 80 */ )) {
//serial_print("stall:\n");
USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK;
USB0_ISTAT = USB_ISTAT_STALL;
}
if ((status & USB_ISTAT_ERROR /* 02 */ )) {
uint8_t err = USB0_ERRSTAT;
USB0_ERRSTAT = err;
//serial_print("err:");
//serial_phex(err);
//serial_print("\n");
USB0_ISTAT = USB_ISTAT_ERROR;
}
if ((status & USB_ISTAT_SLEEP /* 10 */ )) {
//serial_print("sleep\n");
USB0_ISTAT = USB_ISTAT_SLEEP;
}
}
void usb_init(void)
{
int i;
//serial_begin(BAUD2DIV(115200));
//serial_print("usb_init\n");
usb_init_serialnumber();
for (i=0; i <= NUM_ENDPOINTS*4; i++) {
table[i].desc = 0;
table[i].addr = 0;
}
// this basically follows the flowchart in the Kinetis
// Quick Reference User Guide, Rev. 1, 03/2012, page 141
// assume 48 MHz clock already running
// SIM - enable clock
SIM_SCGC4 |= SIM_SCGC4_USBOTG;
// reset USB module
USB0_USBTRC0 = USB_USBTRC_USBRESET;
while ((USB0_USBTRC0 & USB_USBTRC_USBRESET) != 0) ; // wait for reset to end
// set desc table base addr
USB0_BDTPAGE1 = ((uint32_t)table) >> 8;
USB0_BDTPAGE2 = ((uint32_t)table) >> 16;
USB0_BDTPAGE3 = ((uint32_t)table) >> 24;
// clear all ISR flags
USB0_ISTAT = 0xFF;
USB0_ERRSTAT = 0xFF;
USB0_OTGISTAT = 0xFF;
USB0_USBTRC0 |= 0x40; // undocumented bit
// enable USB
USB0_CTL = USB_CTL_USBENSOFEN;
USB0_USBCTRL = 0;
// enable reset interrupt
USB0_INTEN = USB_INTEN_USBRSTEN;
// enable interrupt in NVIC...
NVIC_SET_PRIORITY(IRQ_USBOTG, 112);
NVIC_ENABLE_IRQ(IRQ_USBOTG);
// enable d+ pullup
USB0_CONTROL = USB_CONTROL_DPPULLUPNONOTG;
}
#else // F_CPU < 20 MHz
void usb_init(void)
{
}
#endif // F_CPU >= 20 MHz

108
teensy/core/usb_dev.h Normal file
View File

@ -0,0 +1,108 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _usb_dev_h_
#define _usb_dev_h_
#if F_CPU >= 20000000
// This header is NOT meant to be included when compiling
// user sketches in Arduino. The low-level functions
// provided by usb_dev.c are meant to be called only by
// code which provides higher-level interfaces to the user.
#include "usb_mem.h"
#include "usb_desc.h"
#ifdef __cplusplus
extern "C" {
#endif
void usb_init(void);
void usb_init_serialnumber(void);
void usb_isr(void);
usb_packet_t *usb_rx(uint32_t endpoint);
uint32_t usb_tx_byte_count(uint32_t endpoint);
uint32_t usb_tx_packet_count(uint32_t endpoint);
void usb_tx(uint32_t endpoint, usb_packet_t *packet);
void usb_tx_isr(uint32_t endpoint, usb_packet_t *packet);
extern volatile uint8_t usb_configuration;
extern uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS];
static inline uint32_t usb_rx_byte_count(uint32_t endpoint) __attribute__((always_inline));
static inline uint32_t usb_rx_byte_count(uint32_t endpoint)
{
endpoint--;
if (endpoint >= NUM_ENDPOINTS) return 0;
return usb_rx_byte_count_data[endpoint];
}
#ifdef CDC_DATA_INTERFACE
extern uint32_t usb_cdc_line_coding[2];
extern volatile uint8_t usb_cdc_line_rtsdtr;
extern volatile uint8_t usb_cdc_transmit_flush_timer;
extern void usb_serial_flush_callback(void);
#endif
#ifdef SEREMU_INTERFACE
extern volatile uint8_t usb_seremu_transmit_flush_timer;
extern void usb_seremu_flush_callback(void);
#endif
#ifdef KEYBOARD_INTERFACE
extern uint8_t keyboard_modifier_keys;
extern uint8_t keyboard_keys[6];
extern uint8_t keyboard_protocol;
extern uint8_t keyboard_idle_config;
extern uint8_t keyboard_idle_count;
extern volatile uint8_t keyboard_leds;
#endif
#ifdef MIDI_INTERFACE
extern void usb_midi_flush_output(void);
#endif
#ifdef FLIGHTSIM_INTERFACE
extern void usb_flightsim_flush_callback(void);
#endif
#ifdef __cplusplus
}
#endif
#endif // F_CPU >= 20 MHz
#endif

109
teensy/core/usb_mem.c Normal file
View File

@ -0,0 +1,109 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#if F_CPU >= 20000000
#include "mk20dx128.h"
//#include "HardwareSerial.h"
#include "usb_dev.h"
#include "usb_mem.h"
__attribute__ ((section(".usbbuffers"), used))
unsigned char usb_buffer_memory[NUM_USB_BUFFERS * sizeof(usb_packet_t)];
static uint32_t usb_buffer_available = 0xFFFFFFFF;
// use bitmask and CLZ instruction to implement fast free list
// http://www.archivum.info/gnu.gcc.help/2006-08/00148/Re-GCC-Inline-Assembly.html
// http://gcc.gnu.org/ml/gcc/2012-06/msg00015.html
// __builtin_clz()
usb_packet_t * usb_malloc(void)
{
unsigned int n, avail;
uint8_t *p;
__disable_irq();
avail = usb_buffer_available;
n = __builtin_clz(avail); // clz = count leading zeros
if (n >= NUM_USB_BUFFERS) {
__enable_irq();
return NULL;
}
//serial_print("malloc:");
//serial_phex(n);
//serial_print("\n");
usb_buffer_available = avail & ~(0x80000000 >> n);
__enable_irq();
p = usb_buffer_memory + (n * sizeof(usb_packet_t));
//serial_print("malloc:");
//serial_phex32((int)p);
//serial_print("\n");
*(uint32_t *)p = 0;
*(uint32_t *)(p + 4) = 0;
return (usb_packet_t *)p;
}
// for the receive endpoints to request memory
extern uint8_t usb_rx_memory_needed;
extern void usb_rx_memory(usb_packet_t *packet);
void usb_free(usb_packet_t *p)
{
unsigned int n, mask;
//serial_print("free:");
n = ((uint8_t *)p - usb_buffer_memory) / sizeof(usb_packet_t);
if (n >= NUM_USB_BUFFERS) return;
//serial_phex(n);
//serial_print("\n");
// if any endpoints are starving for memory to receive
// packets, give this memory to them immediately!
if (usb_rx_memory_needed && usb_configuration) {
//serial_print("give to rx:");
//serial_phex32((int)p);
//serial_print("\n");
usb_rx_memory(p);
return;
}
mask = (0x80000000 >> n);
__disable_irq();
usb_buffer_available |= mask;
__enable_irq();
//serial_print("free:");
//serial_phex32((int)p);
//serial_print("\n");
}
#endif // F_CPU >= 20 MHz

55
teensy/core/usb_mem.h Normal file
View File

@ -0,0 +1,55 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _usb_mem_h_
#define _usb_mem_h_
#include <stdint.h>
typedef struct usb_packet_struct {
uint16_t len;
uint16_t index;
struct usb_packet_struct *next;
uint8_t buf[64];
} usb_packet_t;
#ifdef __cplusplus
extern "C" {
#endif
usb_packet_t * usb_malloc(void);
void usb_free(usb_packet_t *p);
#ifdef __cplusplus
}
#endif
#endif

57
teensy/core/usb_names.h Normal file
View File

@ -0,0 +1,57 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _usb_names_h_
#define _usb_names_h_
// These definitions are intended to allow users to override the default
// USB manufacturer, product and serial number strings.
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct usb_string_descriptor_struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wString[];
};
extern struct usb_string_descriptor_struct usb_string_manufacturer_name;
extern struct usb_string_descriptor_struct usb_string_product_name;
extern struct usb_string_descriptor_struct usb_string_serial_number;
#ifdef __cplusplus
}
#endif
#endif

273
teensy/core/usb_serial.c Normal file
View File

@ -0,0 +1,273 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "usb_dev.h"
#include "usb_serial.h"
#include "core_pins.h" // for yield()
//#include "HardwareSerial.h"
#include <string.h> // for memcpy()
// defined by usb_dev.h -> usb_desc.h
#if defined(CDC_STATUS_INTERFACE) && defined(CDC_DATA_INTERFACE)
uint32_t usb_cdc_line_coding[2];
volatile uint8_t usb_cdc_line_rtsdtr=0;
volatile uint8_t usb_cdc_transmit_flush_timer=0;
static usb_packet_t *rx_packet=NULL;
static usb_packet_t *tx_packet=NULL;
static volatile uint8_t tx_noautoflush=0;
#define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */
// get the next character, or -1 if nothing received
int usb_serial_getchar(void)
{
unsigned int i;
int c;
if (!rx_packet) {
if (!usb_configuration) return -1;
rx_packet = usb_rx(CDC_RX_ENDPOINT);
if (!rx_packet) return -1;
}
i = rx_packet->index;
c = rx_packet->buf[i++];
if (i >= rx_packet->len) {
usb_free(rx_packet);
rx_packet = NULL;
} else {
rx_packet->index = i;
}
return c;
}
// peek at the next character, or -1 if nothing received
int usb_serial_peekchar(void)
{
if (!rx_packet) {
if (!usb_configuration) return -1;
rx_packet = usb_rx(CDC_RX_ENDPOINT);
if (!rx_packet) return -1;
}
if (!rx_packet) return -1;
return rx_packet->buf[rx_packet->index];
}
// number of bytes available in the receive buffer
int usb_serial_available(void)
{
int count;
count = usb_rx_byte_count(CDC_RX_ENDPOINT);
if (rx_packet) count += rx_packet->len - rx_packet->index;
return count;
}
// read a block of bytes to a buffer
int usb_serial_read(void *buffer, uint32_t size)
{
uint8_t *p = (uint8_t *)buffer;
uint32_t qty, count=0;
while (size) {
if (!usb_configuration) break;
if (!rx_packet) {
rx:
rx_packet = usb_rx(CDC_RX_ENDPOINT);
if (!rx_packet) break;
if (rx_packet->len == 0) {
usb_free(rx_packet);
goto rx;
}
}
qty = rx_packet->len - rx_packet->index;
if (qty > size) qty = size;
memcpy(p, rx_packet->buf + rx_packet->index, qty);
p += qty;
count += qty;
size -= qty;
rx_packet->index += qty;
if (rx_packet->index >= rx_packet->len) {
usb_free(rx_packet);
rx_packet = NULL;
}
}
return count;
}
// discard any buffered input
void usb_serial_flush_input(void)
{
usb_packet_t *rx;
if (!usb_configuration) return;
if (rx_packet) {
usb_free(rx_packet);
rx_packet = NULL;
}
while (1) {
rx = usb_rx(CDC_RX_ENDPOINT);
if (!rx) break;
usb_free(rx);
}
}
// Maximum number of transmit packets to queue so we don't starve other endpoints for memory
#define TX_PACKET_LIMIT 8
// When the PC isn't listening, how long do we wait before discarding data? If this is
// too short, we risk losing data during the stalls that are common with ordinary desktop
// software. If it's too long, we stall the user's program when no software is running.
#define TX_TIMEOUT_MSEC 70
#if F_CPU == 168000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100)
#elif F_CPU == 144000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932)
#elif F_CPU == 120000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764)
#elif F_CPU == 96000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596)
#elif F_CPU == 72000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512)
#elif F_CPU == 48000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428)
#elif F_CPU == 24000000
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262)
#endif
// When we've suffered the transmit timeout, don't wait again until the computer
// begins accepting data. If no software is running to receive, we'll just discard
// data as rapidly as Serial.print() can generate it, until there's something to
// actually receive it.
static uint8_t transmit_previous_timeout=0;
// transmit a character. 0 returned on success, -1 on error
int usb_serial_putchar(uint8_t c)
{
return usb_serial_write(&c, 1);
}
int usb_serial_write(const void *buffer, uint32_t size)
{
uint32_t len;
uint32_t wait_count;
const uint8_t *src = (const uint8_t *)buffer;
uint8_t *dest;
tx_noautoflush = 1;
while (size > 0) {
if (!tx_packet) {
wait_count = 0;
while (1) {
if (!usb_configuration) {
tx_noautoflush = 0;
return -1;
}
if (usb_tx_packet_count(CDC_TX_ENDPOINT) < TX_PACKET_LIMIT) {
tx_noautoflush = 1;
tx_packet = usb_malloc();
if (tx_packet) break;
tx_noautoflush = 0;
}
if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) {
transmit_previous_timeout = 1;
return -1;
}
yield();
}
}
transmit_previous_timeout = 0;
len = CDC_TX_SIZE - tx_packet->index;
if (len > size) len = size;
dest = tx_packet->buf + tx_packet->index;
tx_packet->index += len;
size -= len;
while (len-- > 0) *dest++ = *src++;
if (tx_packet->index >= CDC_TX_SIZE) {
tx_packet->len = CDC_TX_SIZE;
usb_tx(CDC_TX_ENDPOINT, tx_packet);
tx_packet = NULL;
}
usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
}
tx_noautoflush = 0;
return 0;
}
void usb_serial_flush_output(void)
{
if (!usb_configuration) return;
tx_noautoflush = 1;
if (tx_packet) {
usb_cdc_transmit_flush_timer = 0;
tx_packet->len = tx_packet->index;
usb_tx(CDC_TX_ENDPOINT, tx_packet);
tx_packet = NULL;
} else {
usb_packet_t *tx = usb_malloc();
if (tx) {
usb_cdc_transmit_flush_timer = 0;
usb_tx(CDC_TX_ENDPOINT, tx);
} else {
usb_cdc_transmit_flush_timer = 1;
}
}
tx_noautoflush = 0;
}
void usb_serial_flush_callback(void)
{
if (tx_noautoflush) return;
if (tx_packet) {
tx_packet->len = tx_packet->index;
usb_tx(CDC_TX_ENDPOINT, tx_packet);
tx_packet = NULL;
} else {
usb_packet_t *tx = usb_malloc();
if (tx) {
usb_tx(CDC_TX_ENDPOINT, tx);
} else {
usb_cdc_transmit_flush_timer = 1;
}
}
}
#endif // CDC_STATUS_INTERFACE && CDC_DATA_INTERFACE

144
teensy/core/usb_serial.h Normal file
View File

@ -0,0 +1,144 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef USBserial_h_
#define USBserial_h_
#if defined(USB_SERIAL) || defined(USB_SERIAL_HID)
#include <inttypes.h>
#if F_CPU >= 20000000
// C language implementation
#ifdef __cplusplus
extern "C" {
#endif
int usb_serial_getchar(void);
int usb_serial_peekchar(void);
int usb_serial_available(void);
int usb_serial_read(void *buffer, uint32_t size);
void usb_serial_flush_input(void);
int usb_serial_putchar(uint8_t c);
int usb_serial_write(const void *buffer, uint32_t size);
void usb_serial_flush_output(void);
extern uint32_t usb_cdc_line_coding[2];
extern volatile uint8_t usb_cdc_line_rtsdtr;
extern volatile uint8_t usb_cdc_transmit_flush_timer;
extern volatile uint8_t usb_configuration;
#ifdef __cplusplus
}
#endif
#define USB_SERIAL_DTR 0x01
#define USB_SERIAL_RTS 0x02
// C++ interface
#ifdef __cplusplus
#include "Stream.h"
class usb_serial_class : public Stream
{
public:
void begin(long) { /* TODO: call a function that tries to wait for enumeration */ };
void end() { /* TODO: flush output and shut down USB port */ };
virtual int available() { return usb_serial_available(); }
virtual int read() { return usb_serial_getchar(); }
virtual int peek() { return usb_serial_peekchar(); }
virtual void flush() { usb_serial_flush_output(); } // TODO: actually wait for data to leave USB...
virtual size_t write(uint8_t c) { return usb_serial_putchar(c); }
virtual size_t write(const uint8_t *buffer, size_t size) { return usb_serial_write(buffer, size); }
size_t write(unsigned long n) { return write((uint8_t)n); }
size_t write(long n) { return write((uint8_t)n); }
size_t write(unsigned int n) { return write((uint8_t)n); }
size_t write(int n) { return write((uint8_t)n); }
using Print::write;
void send_now(void) { usb_serial_flush_output(); }
uint32_t baud(void) { return usb_cdc_line_coding[0]; }
uint8_t stopbits(void) { uint8_t b = usb_cdc_line_coding[1]; if (!b) b = 1; return b; }
uint8_t paritytype(void) { return usb_cdc_line_coding[1] >> 8; } // 0=none, 1=odd, 2=even
uint8_t numbits(void) { return usb_cdc_line_coding[1] >> 16; }
uint8_t dtr(void) { return (usb_cdc_line_rtsdtr & USB_SERIAL_DTR) ? 1 : 0; }
uint8_t rts(void) { return (usb_cdc_line_rtsdtr & USB_SERIAL_RTS) ? 1 : 0; }
operator bool() { return usb_configuration && (usb_cdc_line_rtsdtr & (USB_SERIAL_DTR | USB_SERIAL_RTS)); }
size_t readBytes(char *buffer, size_t length) {
size_t count=0;
unsigned long startMillis = millis();
do {
count += usb_serial_read(buffer + count, length - count);
if (count >= length) return count;
} while(millis() - startMillis < _timeout);
setReadError();
return count;
}
};
extern usb_serial_class Serial;
#endif // __cplusplus
#else // F_CPU < 20 MHz
// Allow Arduino programs using Serial to compile, but Serial will do nothing.
#ifdef __cplusplus
#include "Stream.h"
class usb_serial_class : public Stream
{
public:
void begin(long) { };
void end() { };
virtual int available() { return 0; }
virtual int read() { return -1; }
virtual int peek() { return -1; }
virtual void flush() { }
virtual size_t write(uint8_t c) { return 1; }
virtual size_t write(const uint8_t *buffer, size_t size) { return size; }
size_t write(unsigned long n) { return 1; }
size_t write(long n) { return 1; }
size_t write(unsigned int n) { return 1; }
size_t write(int n) { return 1; }
using Print::write;
void send_now(void) { }
uint32_t baud(void) { return 0; }
uint8_t stopbits(void) { return 1; }
uint8_t paritytype(void) { return 0; }
uint8_t numbits(void) { return 8; }
uint8_t dtr(void) { return 1; }
uint8_t rts(void) { return 1; }
operator bool() { return true; }
};
extern usb_serial_class Serial;
#endif // __cplusplus
#endif // F_CPU
#endif // USB_SERIAL || USB_SERIAL_HID
#endif // USBserial_h_

32
teensy/core/yield.c Normal file
View File

@ -0,0 +1,32 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
void yield(void) __attribute__ ((weak));
void yield(void) {};

View File

@ -1,8 +1,8 @@
#include <stdio.h>
#include <stdint.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"

View File

@ -31,7 +31,7 @@ STATIC const pyb_led_obj_t pyb_led_obj[] = {
#endif
#endif
};
#define NUM_LEDS ARRAY_SIZE(pyb_led_obj)
#define NUM_LEDS MP_ARRAY_SIZE(pyb_led_obj)
void led_init(void) {
/* GPIO structure */

View File

@ -1,8 +1,8 @@
#include <stdint.h>
#include <stdlib.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "memzip.h"

View File

@ -3,8 +3,8 @@
#include <string.h>
#include <stdlib.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "nlr.h"
#include "lexer.h"
@ -39,7 +39,7 @@ void flash_error(int n) {
}
}
void __fatal_error(const char *msg) {
void NORETURN __fatal_error(const char *msg) {
for (volatile uint delay = 0; delay < 10000000; delay++) {
}
led_state(1, 1);

View File

@ -1,6 +1,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "mpconfigport.h"
#include "misc.h"
#include "memzip.h"

View File

@ -6,8 +6,8 @@
#include "teensy_hal.h"
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "pin.h"

View File

@ -29,8 +29,8 @@
#include <mk20dx128.h>
#include "Arduino.h"
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "teensy_hal.h"
@ -328,8 +328,8 @@ STATIC const mp_obj_dict_t pyb_module_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(pyb_module_globals_table),
.alloc = ARRAY_SIZE(pyb_module_globals_table),
.used = MP_ARRAY_SIZE(pyb_module_globals_table),
.alloc = MP_ARRAY_SIZE(pyb_module_globals_table),
.table = (mp_map_elem_t*)pyb_module_globals_table,
},
};

View File

@ -65,6 +65,7 @@ typedef const void *machine_const_ptr_t; // must be of pointer size
// The following would be from a board specific file, if one existed
#define MICROPY_HW_BOARD_NAME "Teensy-3.1"
#define MICROPY_HW_MCU_NAME "MK20DX256"
#define MICROPY_HW_HAS_SWITCH (0)
#define MICROPY_HW_HAS_SDCARD (0)

View File

@ -290,7 +290,7 @@ STATIC const mp_arg_t pyb_uart_init_args[] = {
{ MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
{ MP_QSTR_parity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
#define PYB_UART_INIT_NUM_ARGS ARRAY_SIZE(pyb_uart_init_args)
#define PYB_UART_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_init_args)
STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
// parse args
@ -419,7 +419,7 @@ STATIC const mp_arg_t pyb_uart_send_args[] = {
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
};
#define PYB_UART_SEND_NUM_ARGS ARRAY_SIZE(pyb_uart_send_args)
#define PYB_UART_SEND_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_send_args)
STATIC mp_obj_t pyb_uart_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
// TODO assumes transmission size is 8-bits wide
@ -465,7 +465,7 @@ STATIC const mp_arg_t pyb_uart_recv_args[] = {
{ MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
};
#define PYB_UART_RECV_NUM_ARGS ARRAY_SIZE(pyb_uart_recv_args)
#define PYB_UART_RECV_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_recv_args)
STATIC mp_obj_t pyb_uart_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
// TODO assumes transmission size is 8-bits wide

View File

@ -1,3 +1,5 @@
#include <string.h>
#include "Arduino.h"
#include "usb.h"

View File

@ -134,7 +134,7 @@ def main():
if args.test_dirs is None:
if pyb is None:
# run PC tests
test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc')
test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc', 'unicode')
else:
# run pyboard tests
test_dirs = ('basics', 'micropython', 'float', 'pyb', 'pybnative', 'inlineasm')

View File

@ -0,0 +1 @@
aαbβcγ

12
tests/unicode/file2.py Normal file
View File

@ -0,0 +1,12 @@
# test reading a given number of characters
def do(mode):
f = open('unicode/data/utf-8_2.txt', mode)
print(f.read(1))
print(f.read(1))
print(f.read(2))
print(f.read(4))
f.close()
do('rb')
do('rt')

View File

@ -39,6 +39,10 @@
#include "runtime.h"
#include "stream.h"
#ifdef _WIN32
#define fsync _commit
#endif
typedef struct _mp_obj_fdfile_t {
mp_obj_base_t base;
int fd;
@ -83,12 +87,9 @@ STATIC mp_int_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int
}
STATIC mp_obj_t fdfile_flush(mp_obj_t self_in) {
#ifndef _WIN32
mp_obj_fdfile_t *self = self_in;
check_fd_is_open(self);
fsync(self->fd);
#else
//TODO
#endif
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_flush_obj, fdfile_flush);

View File

@ -43,7 +43,7 @@
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_STREAMS_NON_BLOCK (1)
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_FROZENSET (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_PLATFORM "linux"