2015-01-26 01:53:48 +00:00
/* Copyright (C) 2014-2015 by Jacob Alexander
2014-06-27 07:53:20 +00:00
*
* 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 .
*/
2015-01-11 03:55:28 +00:00
// ----- Includes -----
// Compiler Includes
# include <string.h> // For memcpy
// Project Includes
2014-06-27 07:53:20 +00:00
# include <Lib/OutputLib.h>
# include <Lib/Interrupts.h>
2015-08-22 02:43:45 +00:00
# include <print.h>
# include <kll_defs.h>
2015-01-11 03:55:28 +00:00
// Local Includes
# include "uart_serial.h"
// ----- Defines -----
// UART Configuration
# if defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) // UART0 Debug
# define UART_BDH UART0_BDH
# define UART_BDL UART0_BDL
# define UART_C1 UART0_C1
# define UART_C2 UART0_C2
# define UART_C3 UART0_C3
# define UART_C4 UART0_C4
# define UART_CFIFO UART0_CFIFO
# define UART_D UART0_D
# define UART_PFIFO UART0_PFIFO
# define UART_RCFIFO UART0_RCFIFO
# define UART_RWFIFO UART0_RWFIFO
# define UART_S1 UART0_S1
# define UART_S2 UART0_S2
# define UART_SFIFO UART0_SFIFO
# define UART_TWFIFO UART0_TWFIFO
# define SIM_SCGC4_UART SIM_SCGC4_UART0
# define IRQ_UART_STATUS IRQ_UART0_STATUS
# elif defined(_mk20dx256vlh7_) // UART2 Debug
# define UART_BDH UART2_BDH
# define UART_BDL UART2_BDL
# define UART_C1 UART2_C1
# define UART_C2 UART2_C2
# define UART_C3 UART2_C3
# define UART_C4 UART2_C4
# define UART_CFIFO UART2_CFIFO
# define UART_D UART2_D
# define UART_PFIFO UART2_PFIFO
# define UART_RCFIFO UART2_RCFIFO
# define UART_RWFIFO UART2_RWFIFO
# define UART_S1 UART2_S1
# define UART_S2 UART2_S2
# define UART_SFIFO UART2_SFIFO
# define UART_TWFIFO UART2_TWFIFO
# define SIM_SCGC4_UART SIM_SCGC4_UART2
# define IRQ_UART_STATUS IRQ_UART2_STATUS
# endif
2014-06-27 07:53:20 +00:00
// ----- Variables -----
2015-01-11 03:55:28 +00:00
# define uart_buffer_size 128 // 128 byte buffer
volatile uint8_t uart_buffer_head = 0 ;
volatile uint8_t uart_buffer_tail = 0 ;
volatile uint8_t uart_buffer_items = 0 ;
volatile uint8_t uart_buffer [ uart_buffer_size ] ;
2014-06-27 07:53:20 +00:00
2014-06-28 21:12:56 +00:00
volatile uint8_t uart_configured = 0 ;
2014-06-27 07:53:20 +00:00
// ----- Interrupt Functions -----
2015-01-11 03:55:28 +00:00
# if defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) // UART0 Debug
2014-06-27 07:53:20 +00:00
void uart0_status_isr ( )
2015-01-11 03:55:28 +00:00
# elif defined(_mk20dx256vlh7_) // UART2 Debug
void uart2_status_isr ( )
# endif
2014-06-27 07:53:20 +00:00
{
cli ( ) ; // Disable Interrupts
// UART0_S1 must be read for the interrupt to be cleared
2015-01-11 03:55:28 +00:00
if ( UART_S1 & ( UART_S1_RDRF | UART_S1_IDLE ) )
2014-06-27 07:53:20 +00:00
{
2015-01-11 03:55:28 +00:00
uint8_t available = UART_RCFIFO ;
2014-06-28 17:35:54 +00:00
// If there was actually nothing
if ( available = = 0 )
{
// Cleanup
2015-01-11 03:55:28 +00:00
available = UART_D ;
UART_CFIFO = UART_CFIFO_RXFLUSH ;
2015-06-14 03:42:12 +00:00
goto done ;
2014-06-28 17:35:54 +00:00
}
2014-06-27 07:53:20 +00:00
// Read UART0 into buffer until FIFO is empty
2014-06-28 17:35:54 +00:00
while ( available - - > 0 )
2014-06-27 07:53:20 +00:00
{
2015-01-11 03:55:28 +00:00
uart_buffer [ uart_buffer_tail + + ] = UART_D ;
uart_buffer_items + + ;
2014-06-27 07:53:20 +00:00
// Wrap-around of tail pointer
2015-01-11 03:55:28 +00:00
if ( uart_buffer_tail > = uart_buffer_size )
2014-06-27 07:53:20 +00:00
{
2015-01-11 03:55:28 +00:00
uart_buffer_tail = 0 ;
2014-06-27 07:53:20 +00:00
}
// Make sure the head pointer also moves if circular buffer is overwritten
2015-01-11 03:55:28 +00:00
if ( uart_buffer_head = = uart_buffer_tail )
2014-06-27 07:53:20 +00:00
{
2015-01-11 03:55:28 +00:00
uart_buffer_head + + ;
2014-06-27 07:53:20 +00:00
}
// Wrap-around of head pointer
2015-01-11 03:55:28 +00:00
if ( uart_buffer_head > = uart_buffer_size )
2014-06-27 07:53:20 +00:00
{
2015-01-11 03:55:28 +00:00
uart_buffer_head = 0 ;
2014-06-27 07:53:20 +00:00
}
}
}
2015-06-14 03:42:12 +00:00
done :
2014-06-27 07:53:20 +00:00
sei ( ) ; // Re-enable Interrupts
}
2014-06-28 21:12:56 +00:00
2014-06-27 07:53:20 +00:00
// ----- Functions -----
void uart_serial_setup ( )
{
2014-06-28 21:12:56 +00:00
// Indication that the UART is not ready yet
uart_configured = 0 ;
2014-06-27 07:53:20 +00:00
// Setup the the UART interface for keyboard data input
2015-01-11 03:55:28 +00:00
SIM_SCGC4 | = SIM_SCGC4_UART ; // Disable clock gating
2014-06-27 07:53:20 +00:00
2015-01-11 03:55:28 +00:00
// MCHCK / Kiibohd-dfu
2014-07-01 06:52:24 +00:00
# if defined(_mk20dx128vlf5_)
// Pin Setup for UART0
PORTA_PCR1 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX ( 2 ) ; // RX Pin
PORTA_PCR2 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX ( 2 ) ; // TX Pin
2015-01-11 03:55:28 +00:00
// Kiibohd-dfu
# elif defined(_mk20dx256vlh7_)
// Pin Setup for UART2
PORTD_PCR2 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX ( 3 ) ; // RX Pin
PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX ( 3 ) ; // TX Pin
2014-07-01 06:52:24 +00:00
// Teensy
# else
2014-06-27 07:53:20 +00:00
// Pin Setup for UART0
PORTB_PCR16 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX ( 3 ) ; // RX Pin
PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX ( 3 ) ; // TX Pin
2014-07-01 06:52:24 +00:00
# endif
2014-06-27 07:53:20 +00:00
2015-01-11 03:55:28 +00:00
# if defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) // UART0 Debug
2014-06-28 17:35:54 +00:00
// Setup baud rate - 115200 Baud
2014-06-27 07:53:20 +00:00
// 48 MHz / ( 16 * Baud ) = BDH/L
2014-06-28 17:35:54 +00:00
// Baud: 115200 -> 48 MHz / ( 16 * 115200 ) = 26.0416667
// Thus baud setting = 26
2014-06-27 07:53:20 +00:00
// NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
2014-06-28 17:35:54 +00:00
uint16_t baud = 26 ; // Max setting of 8191
2015-01-11 03:55:28 +00:00
UART_BDH = ( uint8_t ) ( baud > > 8 ) ;
UART_BDL = ( uint8_t ) baud ;
UART_C4 = 0x02 ;
# elif defined(_mk20dx256vlh7_) // UART2 Debug
// Setup baud rate - 115200 Baud
// Uses Bus Clock
2015-04-27 07:57:34 +00:00
// 36 MHz / ( 16 * Baud ) = BDH/L
// Baud: 115200 -> 36 MHz / ( 16 * 115200 ) = 19.53125
// Thus baud setting = 19
2015-01-11 03:55:28 +00:00
// NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
2015-04-27 07:57:34 +00:00
uint16_t baud = 19 ; // Max setting of 8191
2015-01-11 03:55:28 +00:00
UART_BDH = ( uint8_t ) ( baud > > 8 ) ;
UART_BDL = ( uint8_t ) baud ;
2015-04-27 07:57:34 +00:00
UART_C4 = 0x11 ;
2015-01-11 03:55:28 +00:00
# endif
2014-06-27 07:53:20 +00:00
// 8 bit, No Parity, Idle Character bit after stop
2015-01-11 03:55:28 +00:00
UART_C1 = UART_C1_ILT ;
2014-06-27 07:53:20 +00:00
2014-07-01 06:52:24 +00:00
// Interrupt notification watermarks
2015-01-11 03:55:28 +00:00
# if defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) // UART0 Debug
UART_TWFIFO = 2 ;
UART_RWFIFO = 4 ;
# elif defined(_mk20dx256vlh7_) // UART2 Debug
// UART2 has a single byte FIFO
UART_TWFIFO = 1 ;
UART_RWFIFO = 1 ;
# endif
2014-06-28 17:35:54 +00:00
2015-01-11 03:55:28 +00:00
// TX FIFO Enabled, TX FIFO Size 1 (Max 8 datawords), RX FIFO Enabled, RX FIFO Size 1 (Max 8 datawords)
2014-06-27 07:53:20 +00:00
// TX/RX FIFO Size:
// 0x0 - 1 dataword
// 0x1 - 4 dataword
// 0x2 - 8 dataword
2015-01-11 03:55:28 +00:00
UART_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE ;
2014-06-27 07:53:20 +00:00
// Reciever Inversion Disabled, LSBF
// UART_S2_RXINV UART_S2_MSBF
2015-01-11 03:55:28 +00:00
UART_S2 | = 0x00 ;
2014-06-27 07:53:20 +00:00
// Transmit Inversion Disabled
// UART_C3_TXINV
2015-01-11 03:55:28 +00:00
UART_C3 | = 0x00 ;
2014-06-27 07:53:20 +00:00
2014-06-28 17:35:54 +00:00
// TX Enabled, RX Enabled, RX Interrupt Enabled, Generate idles
// UART_C2_TE UART_C2_RE UART_C2_RIE UART_C2_ILIE
2015-01-11 03:55:28 +00:00
UART_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE | UART_C2_ILIE ;
2014-06-27 07:53:20 +00:00
// Add interrupt to the vector table
2015-01-11 03:55:28 +00:00
NVIC_ENABLE_IRQ ( IRQ_UART_STATUS ) ;
2014-06-28 21:12:56 +00:00
// UART is now ready to use
uart_configured = 1 ;
2014-06-27 07:53:20 +00:00
}
// Get the next character, or -1 if nothing received
int uart_serial_getchar ( )
{
2014-06-28 21:12:56 +00:00
if ( ! uart_configured )
return - 1 ;
2014-06-27 07:53:20 +00:00
unsigned int value = - 1 ;
// Check to see if the FIFO has characters
2015-01-11 03:55:28 +00:00
if ( uart_buffer_items > 0 )
2014-06-27 07:53:20 +00:00
{
2015-01-11 03:55:28 +00:00
value = uart_buffer [ uart_buffer_head + + ] ;
uart_buffer_items - - ;
2014-06-27 07:53:20 +00:00
// Wrap-around of head pointer
2015-01-11 03:55:28 +00:00
if ( uart_buffer_head > = uart_buffer_size )
2014-06-27 07:53:20 +00:00
{
2015-01-11 03:55:28 +00:00
uart_buffer_head = 0 ;
2014-06-27 07:53:20 +00:00
}
}
return value ;
}
// Number of bytes available in the receive buffer
int uart_serial_available ( )
{
2015-01-11 03:55:28 +00:00
return uart_buffer_items ;
2014-06-27 07:53:20 +00:00
}
// Discard any buffered input
void uart_serial_flush_input ( )
{
2015-01-11 03:55:28 +00:00
uart_buffer_head = 0 ;
uart_buffer_tail = 0 ;
uart_buffer_items = 0 ;
2014-06-27 07:53:20 +00:00
}
// Transmit a character. 0 returned on success, -1 on error
int uart_serial_putchar ( uint8_t c )
{
2014-06-28 21:12:56 +00:00
if ( ! uart_configured )
return - 1 ;
2015-01-11 03:55:28 +00:00
while ( ! ( UART_SFIFO & UART_SFIFO_TXEMPT ) ) ; // Wait till there is room to send
UART_D = c ;
2014-06-28 17:35:54 +00:00
return 0 ;
2014-06-27 07:53:20 +00:00
}
int uart_serial_write ( const void * buffer , uint32_t size )
{
2014-06-28 21:12:56 +00:00
if ( ! uart_configured )
return - 1 ;
2014-06-27 07:53:20 +00:00
const uint8_t * data = ( const uint8_t * ) buffer ;
uint32_t position = 0 ;
// While buffer is not empty and transmit buffer is
while ( position < size )
{
2015-01-11 03:55:28 +00:00
while ( ! ( UART_SFIFO & UART_SFIFO_TXEMPT ) ) ; // Wait till there is room to send
UART_D = data [ position + + ] ;
2014-06-27 07:53:20 +00:00
}
return 0 ;
}
void uart_serial_flush_output ( )
{
// Delay until buffer has been sent
2015-01-11 03:55:28 +00:00
while ( ! ( UART_SFIFO & UART_SFIFO_TXEMPT ) ) ; // Wait till there is room to send
2014-06-27 07:53:20 +00:00
}
void uart_device_reload ( )
{
2015-08-22 02:43:45 +00:00
if ( flashModeEnabled_define = = 0 )
{
print ( NL ) ;
warn_print ( " flashModeEnabled not set, cancelling firmware reload... " ) ;
info_msg ( " Set flashModeEnabled to 1 in your kll configuration. " ) ;
return ;
}
// MCHCK
# if defined(_mk20dx128vlf5_)
// MCHCK Kiibohd Variant
// Check to see if PTA3 (has a pull-up) is connected to GND (usually via jumper)
// Only allow reload if the jumper is present (security)
GPIOA_PDDR & = ~ ( 1 < < 3 ) ; // Input
PORTA_PCR3 = PORT_PCR_PFE | PORT_PCR_MUX ( 1 ) ; // Internal pull-up
// Check for jumper
if ( GPIOA_PDIR & ( 1 < < 3 ) & & flashModeEnabled_define ! = 0 )
{
print ( NL ) ;
warn_print ( " Security jumper not present, cancelling firmware reload... " ) ;
info_msg ( " Replace jumper on middle 2 pins, or manually press the firmware reload button. " ) ;
}
else
{
// Copies variable into the VBAT register, must be identical to the variable in the bootloader to jump to the bootloader flash mode
for ( int pos = 0 ; pos < sizeof ( sys_reset_to_loader_magic ) ; pos + + )
( & VBAT ) [ pos ] = sys_reset_to_loader_magic [ pos ] ;
SOFTWARE_RESET ( ) ;
}
// Kiibohd mk20dx256vlh7
# elif defined(_mk20dx256vlh7_)
// Copies variable into the VBAT register, must be identical to the variable in the bootloader to jump to the bootloader flash mode
for ( int pos = 0 ; pos < sizeof ( sys_reset_to_loader_magic ) ; pos + + )
( & VBAT ) [ pos ] = sys_reset_to_loader_magic [ pos ] ;
SOFTWARE_RESET ( ) ;
// Teensy 3.0 and 3.1
# else
2014-06-27 07:53:20 +00:00
asm volatile ( " bkpt " ) ;
2015-08-22 02:43:45 +00:00
# endif
2014-06-27 07:53:20 +00:00
}