| @@ -255,6 +255,7 @@ public: | |||
| virtual void flush(void) { serial_flush(); } | |||
| virtual void clear(void) { serial_clear(); } | |||
| virtual int availableForWrite(void) { return serial_write_buffer_free(); } | |||
| using Print::write; | |||
| 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); } | |||
| @@ -290,6 +291,7 @@ public: | |||
| virtual void flush(void) { serial2_flush(); } | |||
| virtual void clear(void) { serial2_clear(); } | |||
| virtual int availableForWrite(void) { return serial2_write_buffer_free(); } | |||
| using Print::write; | |||
| 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); } | |||
| @@ -325,6 +327,7 @@ public: | |||
| virtual void flush(void) { serial3_flush(); } | |||
| virtual void clear(void) { serial3_clear(); } | |||
| virtual int availableForWrite(void) { return serial3_write_buffer_free(); } | |||
| using Print::write; | |||
| 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); } | |||
| @@ -360,6 +363,7 @@ public: | |||
| virtual void flush(void) { serial4_flush(); } | |||
| virtual void clear(void) { serial4_clear(); } | |||
| virtual int availableForWrite(void) { return serial4_write_buffer_free(); } | |||
| using Print::write; | |||
| virtual size_t write(uint8_t c) { serial4_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); } | |||
| @@ -395,6 +399,7 @@ public: | |||
| virtual void flush(void) { serial5_flush(); } | |||
| virtual void clear(void) { serial5_clear(); } | |||
| virtual int availableForWrite(void) { return serial5_write_buffer_free(); } | |||
| using Print::write; | |||
| virtual size_t write(uint8_t c) { serial5_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); } | |||
| @@ -437,6 +442,7 @@ public: | |||
| virtual void flush(void) { serial6_flush(); } | |||
| virtual void clear(void) { serial6_clear(); } | |||
| virtual int availableForWrite(void) { return serial6_write_buffer_free(); } | |||
| using Print::write; | |||
| virtual size_t write(uint8_t c) { serial6_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); } | |||
| @@ -909,6 +909,9 @@ enum IRQ_NUMBER_t { | |||
| #define PORTA_GPCLR (*(volatile uint32_t *)0x40049080) // Global Pin Control Low Register | |||
| #define PORTA_GPCHR (*(volatile uint32_t *)0x40049084) // Global Pin Control High Register | |||
| #define PORTA_ISFR (*(volatile uint32_t *)0x400490A0) // Interrupt Status Flag Register | |||
| #define PORTA_DFER (*(volatile uint32_t *)0x400490C0) // Digital Filter Enable | |||
| #define PORTA_DFCR (*(volatile uint32_t *)0x400490C4) // Digital Filter Clock | |||
| #define PORTA_DFWR (*(volatile uint32_t *)0x400490C8) // Digital Filter Width | |||
| #define PORTB_PCR0 (*(volatile uint32_t *)0x4004A000) // Pin Control Register n | |||
| #define PORTB_PCR1 (*(volatile uint32_t *)0x4004A004) // Pin Control Register n | |||
| #define PORTB_PCR2 (*(volatile uint32_t *)0x4004A008) // Pin Control Register n | |||
| @@ -944,6 +947,9 @@ enum IRQ_NUMBER_t { | |||
| #define PORTB_GPCLR (*(volatile uint32_t *)0x4004A080) // Global Pin Control Low Register | |||
| #define PORTB_GPCHR (*(volatile uint32_t *)0x4004A084) // Global Pin Control High Register | |||
| #define PORTB_ISFR (*(volatile uint32_t *)0x4004A0A0) // Interrupt Status Flag Register | |||
| #define PORTB_DFER (*(volatile uint32_t *)0x4004A0C0) // Digital Filter Enable | |||
| #define PORTB_DFCR (*(volatile uint32_t *)0x4004A0C4) // Digital Filter Clock | |||
| #define PORTB_DFWR (*(volatile uint32_t *)0x4004A0C8) // Digital Filter Width | |||
| #define PORTC_PCR0 (*(volatile uint32_t *)0x4004B000) // Pin Control Register n | |||
| #define PORTC_PCR1 (*(volatile uint32_t *)0x4004B004) // Pin Control Register n | |||
| #define PORTC_PCR2 (*(volatile uint32_t *)0x4004B008) // Pin Control Register n | |||
| @@ -979,6 +985,9 @@ enum IRQ_NUMBER_t { | |||
| #define PORTC_GPCLR (*(volatile uint32_t *)0x4004B080) // Global Pin Control Low Register | |||
| #define PORTC_GPCHR (*(volatile uint32_t *)0x4004B084) // Global Pin Control High Register | |||
| #define PORTC_ISFR (*(volatile uint32_t *)0x4004B0A0) // Interrupt Status Flag Register | |||
| #define PORTC_DFER (*(volatile uint32_t *)0x4004B0C0) // Digital Filter Enable | |||
| #define PORTC_DFCR (*(volatile uint32_t *)0x4004B0C4) // Digital Filter Clock | |||
| #define PORTC_DFWR (*(volatile uint32_t *)0x4004B0C8) // Digital Filter Width | |||
| #define PORTD_PCR0 (*(volatile uint32_t *)0x4004C000) // Pin Control Register n | |||
| #define PORTD_PCR1 (*(volatile uint32_t *)0x4004C004) // Pin Control Register n | |||
| #define PORTD_PCR2 (*(volatile uint32_t *)0x4004C008) // Pin Control Register n | |||
| @@ -1014,6 +1023,9 @@ enum IRQ_NUMBER_t { | |||
| #define PORTD_GPCLR (*(volatile uint32_t *)0x4004C080) // Global Pin Control Low Register | |||
| #define PORTD_GPCHR (*(volatile uint32_t *)0x4004C084) // Global Pin Control High Register | |||
| #define PORTD_ISFR (*(volatile uint32_t *)0x4004C0A0) // Interrupt Status Flag Register | |||
| #define PORTD_DFER (*(volatile uint32_t *)0x4004C0C0) // Digital Filter Enable | |||
| #define PORTD_DFCR (*(volatile uint32_t *)0x4004C0C4) // Digital Filter Clock | |||
| #define PORTD_DFWR (*(volatile uint32_t *)0x4004C0C8) // Digital Filter Width | |||
| #define PORTE_PCR0 (*(volatile uint32_t *)0x4004D000) // Pin Control Register n | |||
| #define PORTE_PCR1 (*(volatile uint32_t *)0x4004D004) // Pin Control Register n | |||
| #define PORTE_PCR2 (*(volatile uint32_t *)0x4004D008) // Pin Control Register n | |||
| @@ -1049,6 +1061,9 @@ enum IRQ_NUMBER_t { | |||
| #define PORTE_GPCLR (*(volatile uint32_t *)0x4004D080) // Global Pin Control Low Register | |||
| #define PORTE_GPCHR (*(volatile uint32_t *)0x4004D084) // Global Pin Control High Register | |||
| #define PORTE_ISFR (*(volatile uint32_t *)0x4004D0A0) // Interrupt Status Flag Register | |||
| #define PORTE_DFER (*(volatile uint32_t *)0x4004D0C0) // Digital Filter Enable | |||
| #define PORTE_DFCR (*(volatile uint32_t *)0x4004D0C4) // Digital Filter Clock | |||
| #define PORTE_DFWR (*(volatile uint32_t *)0x4004D0C8) // Digital Filter Width | |||
| // System Integration Module (SIM) | |||
| @@ -2878,6 +2893,9 @@ typedef struct { | |||
| #define DAC0_DAT14L (*(volatile uint8_t *)0x400CC01C) // DAC Data Low Register | |||
| #define DAC0_DAT15L (*(volatile uint8_t *)0x400CC01E) // DAC Data Low Register | |||
| #define DAC0_SR (*(volatile uint8_t *)0x400CC020) // DAC Status Register | |||
| #define DAC_SR_DACBFWMF 0x04 // Buffer Watermark Flag | |||
| #define DAC_SR_DACBFRTF 0x02 // Pointer Top Position Flag | |||
| #define DAC_SR_DACBFRBF 0x01 // Pointer Bottom Position Flag | |||
| #define DAC0_C0 (*(volatile uint8_t *)0x400CC021) // DAC Control Register | |||
| #define DAC_C0_DACEN 0x80 // DAC Enable | |||
| #define DAC_C0_DACRFS 0x40 // DAC Reference Select | |||
| @@ -3031,6 +3049,8 @@ typedef struct { | |||
| #define PDB0_CH1DLY0 (*(volatile uint32_t *)0x40036040) // Channel 1 Delay 0 Register | |||
| #define PDB0_CH1DLY1 (*(volatile uint32_t *)0x40036044) // Channel 1 Delay 1 Register | |||
| #define PDB0_DACINTC0 (*(volatile uint32_t *)0x40036150) // DAC Interval Trigger n Control Register | |||
| #define PDB_DACINTC_EXT 0x02 // External Trigger Input Enable | |||
| #define PDB_DACINTC_TOE 0x01 // Interval Trigger Enable | |||
| #define PDB0_DACINT0 (*(volatile uint32_t *)0x40036154) // DAC Interval n Register | |||
| #define PDB0_DACINTC1 (*(volatile uint32_t *)0x40036158) // DAC Interval Trigger n Control register | |||
| #define PDB0_DACINT1 (*(volatile uint32_t *)0x4003615C) // DAC Interval n register | |||
| @@ -28,7 +28,14 @@ | |||
| #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| #if defined (__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) | |||
| /* | |||
| * Let __ARM_FEATURE_UNALIGNED be set by the achitechture and the compiler flags: | |||
| * -munaligned-access | |||
| * -mno-unaligned-access | |||
| * instead of always setting it here. | |||
| * | |||
| #define __ARM_FEATURE_UNALIGNED 1 | |||
| */ | |||
| /* This memcpy routine is optimised for Cortex-M3/M4 cores with/without | |||
| unaligned access. | |||
| @@ -31,6 +31,7 @@ | |||
| #include "kinetis.h" | |||
| #include "core_pins.h" // testing only | |||
| #include "ser_print.h" // testing only | |||
| #include <errno.h> | |||
| // Flash Security Setting. On Teensy 3.2, you can lock the MK20 chip to prevent | |||
| @@ -1137,10 +1138,31 @@ void ResetHandler(void) | |||
| char *__brkval = (char *)&_ebss; | |||
| #ifndef STACK_MARGIN | |||
| #if defined(__MKL26Z64__) | |||
| #define STACK_MARGIN 512 | |||
| #elif defined(__MK20DX128__) | |||
| #define STACK_MARGIN 1024 | |||
| #elif defined(__MK20DX256__) | |||
| #define STACK_MARGIN 4096 | |||
| #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| #define STACK_MARGIN 8192 | |||
| #endif | |||
| #endif | |||
| void * _sbrk(int incr) | |||
| { | |||
| char *prev = __brkval; | |||
| __brkval += incr; | |||
| char *prev, *stack; | |||
| prev = __brkval; | |||
| if (incr != 0) { | |||
| __asm__ volatile("mov %0, sp" : "=r" (stack) ::); | |||
| if (prev + incr >= stack - STACK_MARGIN) { | |||
| errno = ENOMEM; | |||
| return (void *)-1; | |||
| } | |||
| __brkval = prev + incr; | |||
| } | |||
| return prev; | |||
| } | |||
| @@ -1275,7 +1297,7 @@ int kinetis_hsrun_enable(void) | |||
| if (SMC_PMSTAT == SMC_PMSTAT_RUN) { | |||
| // Turn HSRUN mode on | |||
| SMC_PMCTRL = SMC_PMCTRL_RUNM(3); | |||
| while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait | |||
| while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) {;} // wait | |||
| // Then configure clock for full speed | |||
| #if F_CPU == 240000000 && F_BUS == 60000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | |||
| @@ -126,15 +126,58 @@ char * dtostrf(float val, int width, unsigned int precision, char *buf) | |||
| } | |||
| s = fcvtf(val, precision, &decpt, &sign); | |||
| // if only 1 digit in output | |||
| if (precision == 0 && decpt == 0) { | |||
| // round and move decimal point | |||
| s = (*s < '5') ? "0" : "1"; | |||
| reqd = 1; | |||
| } else { | |||
| reqd = strlen(s); | |||
| if (reqd > decpt) reqd++; | |||
| if (decpt == 0) reqd++; | |||
| decpt++; | |||
| } | |||
| // if all zeros, limit to precision | |||
| if (-decpt > (int)precision) { | |||
| s = "0"; | |||
| decpt = -precision; | |||
| } | |||
| reqd = strlen(s); | |||
| // add 1 for decimal point | |||
| if (reqd > decpt) reqd++; | |||
| // add 1 for zero in front of decimal point | |||
| if (decpt == 0) reqd++; | |||
| // if leading zeros after decimal point | |||
| if (decpt < 0 && precision > 0) { | |||
| // ensure enough trailing zeros, add 2 for '0.' | |||
| reqd = precision + 2; | |||
| if (strlen(s) > precision + decpt) { | |||
| // bug in fcvtf. e.g. 0.012, precision 2 should return 1 instead of 12. | |||
| // However, 1.2, precision 0 returns correct value. So shift values so | |||
| // that decimal point is after the first digit, then convert again | |||
| int newPrecision = precision; | |||
| int newDecimalPoint; | |||
| // shift decimal point | |||
| while (newPrecision > 0) { | |||
| val *= 10.0; | |||
| newPrecision--; | |||
| } | |||
| // round after accounting for leading 0's | |||
| s = fcvtf(val, newPrecision, &newDecimalPoint, &sign); | |||
| // if rounded up to new digit (e.g. 0.09 to 0.1), move decimal point | |||
| if (newDecimalPoint - decpt == precision + 1) decpt++; | |||
| } | |||
| } | |||
| // add 1 for sign if negative | |||
| if (sign) reqd++; | |||
| p = buf; | |||
| e = p + reqd; | |||
| pad = width - reqd; | |||
| @@ -150,12 +193,13 @@ char * dtostrf(float val, int width, unsigned int precision, char *buf) | |||
| else if (decpt < 0 && precision > 0) { | |||
| *p++ = '0'; | |||
| *p++ = '.'; | |||
| e++; | |||
| // print leading zeros | |||
| while ( decpt < 0 ) { | |||
| decpt++; | |||
| *p++ = '0'; | |||
| } | |||
| } | |||
| // print digits | |||
| while (p < e) { | |||
| *p++ = *s++; | |||
| if (p == e) break; | |||
| @@ -583,8 +583,9 @@ void _init_Teensyduino_internal_(void) | |||
| // for background about this startup delay, please see these conversations | |||
| // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980 | |||
| // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273 | |||
| delay(400); | |||
| delay(50); | |||
| usb_init(); | |||
| delay(350); | |||
| } | |||
| @@ -926,6 +927,11 @@ void analogWriteFrequency(uint8_t pin, float frequency) | |||
| ftmClock = 16000000; | |||
| } else | |||
| #endif | |||
| #if defined(__MKL26Z64__) | |||
| // Teensy LC does not support slow clock source (ftmClockSource = 2) | |||
| ftmClockSource = 1; // Use default F_TIMER clock source | |||
| ftmClock = F_TIMER; // Set variable for the actual timer clock frequency | |||
| #else | |||
| if (frequency < (float)(F_TIMER >> 7) / 65536.0f) { | |||
| // frequency is too low for working with F_TIMER: | |||
| ftmClockSource = 2; // Use alternative 31250Hz clock source | |||
| @@ -934,6 +940,7 @@ void analogWriteFrequency(uint8_t pin, float frequency) | |||
| ftmClockSource = 1; // Use default F_TIMER clock source | |||
| ftmClock = F_TIMER; // Set variable for the actual timer clock frequency | |||
| } | |||
| #endif | |||
| for (prescale = 0; prescale < 7; prescale++) { | |||
| @@ -121,6 +121,7 @@ void serial_begin(uint32_t divisor) | |||
| case 21: CORE_PIN21_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||
| #if defined(KINETISL) | |||
| case 3: CORE_PIN3_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); break; | |||
| case 25: CORE_PIN25_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(4); break; | |||
| #endif | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| case 27: CORE_PIN27_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||
| @@ -131,6 +132,7 @@ void serial_begin(uint32_t divisor) | |||
| case 5: CORE_PIN5_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | |||
| #if defined(KINETISL) | |||
| case 4: CORE_PIN4_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2); break; | |||
| case 24: CORE_PIN24_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(4); break; | |||
| #endif | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| case 26: CORE_PIN26_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | |||
| @@ -196,8 +198,28 @@ void serial_end(void) | |||
| while (transmitting) yield(); // wait for buffered data to send | |||
| NVIC_DISABLE_IRQ(IRQ_UART0_STATUS); | |||
| UART0_C2 = 0; | |||
| CORE_PIN0_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| CORE_PIN1_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| switch (rx_pin_num) { | |||
| case 0: CORE_PIN0_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| case 21: CORE_PIN21_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| #if defined(KINETISL) | |||
| case 3: CORE_PIN3_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| case 25: CORE_PIN25_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| #endif | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| case 27: CORE_PIN27_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| #endif | |||
| } | |||
| switch (tx_pin_num & 127) { | |||
| case 1: CORE_PIN1_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| case 5: CORE_PIN5_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| #if defined(KINETISL) | |||
| case 4: CORE_PIN4_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| case 24: CORE_PIN24_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| #endif | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| #endif | |||
| } | |||
| rx_buffer_head = 0; | |||
| rx_buffer_tail = 0; | |||
| if (rts_pin) rts_deassert(); | |||
| @@ -553,8 +575,11 @@ void uart0_status_isr(void) | |||
| } | |||
| #else | |||
| if (UART0_S1 & UART_S1_RDRF) { | |||
| n = UART0_D; | |||
| if (use9Bits && (UART0_C3 & 0x80)) n |= 0x100; | |||
| if (use9Bits && (UART0_C3 & 0x80)) { | |||
| n = UART0_D | 0x100; | |||
| } else { | |||
| n = UART0_D; | |||
| } | |||
| head = rx_buffer_head + 1; | |||
| if (head >= SERIAL1_RX_BUFFER_SIZE) head = 0; | |||
| if (head != rx_buffer_tail) { | |||
| @@ -565,8 +565,11 @@ void uart1_status_isr(void) | |||
| } | |||
| #else | |||
| if (UART1_S1 & UART_S1_RDRF) { | |||
| n = UART1_D; | |||
| if (use9Bits && (UART1_C3 & 0x80)) n |= 0x100; | |||
| if (use9Bits && (UART1_C3 & 0x80)) { | |||
| n = UART1_D | 0x100; | |||
| } else { | |||
| n = UART1_D; | |||
| } | |||
| head = rx_buffer_head + 1; | |||
| if (head >= SERIAL2_RX_BUFFER_SIZE) head = 0; | |||
| if (head != rx_buffer_tail) { | |||
| @@ -181,8 +181,19 @@ void serial3_end(void) | |||
| while (transmitting) yield(); // wait for buffered data to send | |||
| NVIC_DISABLE_IRQ(IRQ_UART2_STATUS); | |||
| UART2_C2 = 0; | |||
| #if defined(KINETISK) | |||
| CORE_PIN7_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| CORE_PIN8_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| #elif defined(KINETISL) | |||
| switch (rx_pin_num) { | |||
| case 7: CORE_PIN7_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| case 6: CORE_PIN6_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| } | |||
| switch (tx_pin_num & 127) { | |||
| case 8: CORE_PIN8_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| case 20: CORE_PIN20_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| } | |||
| #endif | |||
| rx_buffer_head = 0; | |||
| rx_buffer_tail = 0; | |||
| if (rts_pin) rts_deassert(); | |||
| @@ -159,8 +159,6 @@ void serial4_end(void) | |||
| while (transmitting) yield(); // wait for buffered data to send | |||
| NVIC_DISABLE_IRQ(IRQ_UART3_STATUS); | |||
| UART3_C2 = 0; | |||
| CORE_PIN31_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| CORE_PIN32_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| switch (rx_pin_num) { | |||
| case 31: CORE_PIN31_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC3 | |||
| case 63: CORE_PIN63_CONFIG = 0; break; | |||
| @@ -49,7 +49,7 @@ audio_block_t * AudioInputUSB::ready_right; | |||
| uint16_t AudioInputUSB::incoming_count; | |||
| uint8_t AudioInputUSB::receive_flag; | |||
| struct usb_audio_features_struct AudioInputUSB::features = {0,0,FEATURE_MAX_VOLUME}; | |||
| struct usb_audio_features_struct AudioInputUSB::features = {0,0,FEATURE_MAX_VOLUME/2}; | |||
| #define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4))) | |||
| uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR; | |||
| @@ -350,6 +350,31 @@ unsigned int usb_audio_transmit_callback(void) | |||
| return target * 4; | |||
| } | |||
| struct setup_struct { | |||
| union { | |||
| struct { | |||
| uint8_t bmRequestType; | |||
| uint8_t bRequest; | |||
| union { | |||
| struct { | |||
| uint8_t bChannel; // 0=main, 1=left, 2=right | |||
| uint8_t bCS; // Control Selector | |||
| }; | |||
| uint16_t wValue; | |||
| }; | |||
| union { | |||
| struct { | |||
| uint8_t bIfEp; // type of entity | |||
| uint8_t bEntityId; // UnitID, TerminalID, etc. | |||
| }; | |||
| uint16_t wIndex; | |||
| }; | |||
| uint16_t wLength; | |||
| }; | |||
| }; | |||
| }; | |||
| int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen) | |||
| { | |||
| struct setup_struct setup = *((struct setup_struct *)stp); | |||
| @@ -22,32 +22,6 @@ extern uint8_t usb_audio_transmit_setting; | |||
| #ifdef __cplusplus | |||
| } | |||
| // setup struct definition could be moved from usb_dev.c to usb_dev.h so we can reuse | |||
| // it instead of redefining it here | |||
| struct setup_struct { | |||
| union { | |||
| struct { | |||
| uint8_t bmRequestType; | |||
| uint8_t bRequest; | |||
| union { | |||
| struct { | |||
| uint8_t bChannel; // 0=main, 1=left, 2=right | |||
| uint8_t bCS; // Control Selector | |||
| }; | |||
| uint16_t wValue; | |||
| }; | |||
| union { | |||
| struct { | |||
| uint8_t bIfEp; // type of entity | |||
| uint8_t bEntityId; // UnitID, TerminalID, etc. | |||
| }; | |||
| uint16_t wIndex; | |||
| }; | |||
| uint16_t wLength; | |||
| }; | |||
| }; | |||
| }; | |||
| // audio features supported | |||
| struct usb_audio_features_struct { | |||
| int change; // set to 1 when any value is changed | |||
| @@ -66,9 +40,11 @@ public: | |||
| friend void usb_audio_receive_callback(unsigned int len); | |||
| friend int usb_audio_set_feature(void *stp, uint8_t *buf); | |||
| friend int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen); | |||
| static struct usb_audio_features_struct features; | |||
| float volume(void) { | |||
| if (features.mute) return 0.0; | |||
| return (float)(features.volume) * (1.0 / (float)FEATURE_MAX_VOLUME); | |||
| } | |||
| private: | |||
| static bool update_responsibility; | |||
| static audio_block_t *incoming_left; | |||
| @@ -1131,7 +1131,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
| 9, // bLength | |||
| 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | |||
| AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress | |||
| 0x05, // bmAttributes = isochronous, asynchronous | |||
| 0x09, // bmAttributes = isochronous, adaptive | |||
| LSB(AUDIO_TX_SIZE), MSB(AUDIO_TX_SIZE), // wMaxPacketSize | |||
| 1, // bInterval, 1 = every frame | |||
| 0, // bRefresh | |||
| @@ -71,7 +71,13 @@ extern volatile uint8_t usb_configuration; | |||
| class usb_serial_class : public Stream | |||
| { | |||
| public: | |||
| void begin(long) { /* TODO: call a function that tries to wait for enumeration */ }; | |||
| void begin(long) { | |||
| uint32_t millis_begin = systick_millis_count; | |||
| while (!(*this)) { | |||
| // wait up to 1 second for Arduino Serial Monitor | |||
| if ((uint32_t)(systick_millis_count - millis_begin) > 1000) break; | |||
| } | |||
| } | |||
| void end() { /* TODO: flush output and shut down USB port */ }; | |||
| virtual int available() { return usb_serial_available(); } | |||
| virtual int read() { return usb_serial_getchar(); } | |||