move to targets dir
This commit is contained in:
580
targets/efm8/src/InitDevice.c
Normal file
580
targets/efm8/src/InitDevice.c
Normal file
@@ -0,0 +1,580 @@
|
||||
//=========================================================
|
||||
// src/InitDevice.c: generated by Hardware Configurator
|
||||
//
|
||||
// This file will be regenerated when saving a document.
|
||||
// leave the sections inside the "$[...]" comment tags alone
|
||||
// or they will be overwritten!
|
||||
//=========================================================
|
||||
|
||||
// USER INCLUDES
|
||||
#include <SI_EFM8UB1_Register_Enums.h>
|
||||
#include "InitDevice.h"
|
||||
|
||||
// USER PROTOTYPES
|
||||
// USER FUNCTIONS
|
||||
|
||||
// $[Library Includes]
|
||||
#include "efm8_usb.h"
|
||||
#include "descriptors.h"
|
||||
#include "usb_0.h"
|
||||
// [Library Includes]$
|
||||
|
||||
//==============================================================================
|
||||
// enter_DefaultMode_from_RESET
|
||||
//==============================================================================
|
||||
extern void enter_DefaultMode_from_RESET(void) {
|
||||
// $[Config Calls]
|
||||
// Save the SFRPAGE
|
||||
uint8_t SFRPAGE_save = SFRPAGE;
|
||||
WDT_0_enter_DefaultMode_from_RESET();
|
||||
PORTS_0_enter_DefaultMode_from_RESET();
|
||||
PORTS_1_enter_DefaultMode_from_RESET();
|
||||
PBCFG_0_enter_DefaultMode_from_RESET();
|
||||
LFOSC_0_enter_DefaultMode_from_RESET();
|
||||
CIP51_0_enter_DefaultMode_from_RESET();
|
||||
CLOCK_0_enter_DefaultMode_from_RESET();
|
||||
TIMER01_0_enter_DefaultMode_from_RESET();
|
||||
TIMER16_2_enter_DefaultMode_from_RESET();
|
||||
TIMER16_3_enter_DefaultMode_from_RESET();
|
||||
TIMER_SETUP_0_enter_DefaultMode_from_RESET();
|
||||
SPI_0_enter_DefaultMode_from_RESET();
|
||||
UART_0_enter_DefaultMode_from_RESET();
|
||||
INTERRUPT_0_enter_DefaultMode_from_RESET();
|
||||
USBLIB_0_enter_DefaultMode_from_RESET();
|
||||
// Restore the SFRPAGE
|
||||
SFRPAGE = SFRPAGE_save;
|
||||
// [Config Calls]$
|
||||
|
||||
}
|
||||
|
||||
extern void INTERRUPT_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[EIE1 - Extended Interrupt Enable 1]
|
||||
// [EIE1 - Extended Interrupt Enable 1]$
|
||||
|
||||
// $[EIE2 - Extended Interrupt Enable 2]
|
||||
// [EIE2 - Extended Interrupt Enable 2]$
|
||||
|
||||
// $[EIP1H - Extended Interrupt Priority 1 High]
|
||||
// [EIP1H - Extended Interrupt Priority 1 High]$
|
||||
|
||||
// $[EIP1 - Extended Interrupt Priority 1 Low]
|
||||
// [EIP1 - Extended Interrupt Priority 1 Low]$
|
||||
|
||||
// $[EIP2 - Extended Interrupt Priority 2]
|
||||
// [EIP2 - Extended Interrupt Priority 2]$
|
||||
|
||||
// $[EIP2H - Extended Interrupt Priority 2 High]
|
||||
// [EIP2H - Extended Interrupt Priority 2 High]$
|
||||
|
||||
// $[IE - Interrupt Enable]
|
||||
/***********************************************************************
|
||||
- Enable each interrupt according to its individual mask setting
|
||||
- Disable external interrupt 0
|
||||
- Disable external interrupt 1
|
||||
- Disable all SPI0 interrupts
|
||||
- Disable all Timer 0 interrupt
|
||||
- Disable all Timer 1 interrupt
|
||||
- Disable Timer 2 interrupt
|
||||
- Disable UART0 interrupt
|
||||
***********************************************************************/
|
||||
IE = IE_EA__ENABLED | IE_EX0__DISABLED | IE_EX1__DISABLED
|
||||
| IE_ESPI0__DISABLED | IE_ET0__DISABLED | IE_ET1__DISABLED
|
||||
| IE_ET2__DISABLED | IE_ES0__DISABLED;
|
||||
// [IE - Interrupt Enable]$
|
||||
|
||||
// $[IP - Interrupt Priority]
|
||||
// [IP - Interrupt Priority]$
|
||||
|
||||
// $[IPH - Interrupt Priority High]
|
||||
// [IPH - Interrupt Priority High]$
|
||||
|
||||
}
|
||||
|
||||
extern void USBLIB_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[USBD Init]
|
||||
USBD_Init (&initstruct);
|
||||
// [USBD Init]$
|
||||
|
||||
}
|
||||
|
||||
extern void CLOCK_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[HFOSC1 Setup]
|
||||
// Ensure SYSCLK is > 24 MHz before switching to HFOSC1
|
||||
SFRPAGE = 0x00;
|
||||
CLKSEL = CLKSEL_CLKSL__HFOSC0 | CLKSEL_CLKDIV__SYSCLK_DIV_1;
|
||||
while ((CLKSEL & CLKSEL_DIVRDY__BMASK) == CLKSEL_DIVRDY__NOT_READY)
|
||||
;
|
||||
// [HFOSC1 Setup]$
|
||||
|
||||
// $[CLKSEL - Clock Select]
|
||||
/***********************************************************************
|
||||
- Clock derived from the Internal High Frequency Oscillator 1
|
||||
- SYSCLK is equal to selected clock source divided by 1
|
||||
***********************************************************************/
|
||||
CLKSEL = CLKSEL_CLKSL__HFOSC1 | CLKSEL_CLKDIV__SYSCLK_DIV_1;
|
||||
while ((CLKSEL & CLKSEL_DIVRDY__BMASK) == CLKSEL_DIVRDY__NOT_READY)
|
||||
;
|
||||
// [CLKSEL - Clock Select]$
|
||||
|
||||
}
|
||||
|
||||
extern void WDT_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[WDTCN - Watchdog Timer Control]
|
||||
SFRPAGE = 0x00;
|
||||
//Disable Watchdog with key sequence
|
||||
WDTCN = 0xDE; //First key
|
||||
WDTCN = 0xAD; //Second key
|
||||
// [WDTCN - Watchdog Timer Control]$
|
||||
|
||||
}
|
||||
|
||||
extern void CIP51_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[PFE0CN - Prefetch Engine Control]
|
||||
/***********************************************************************
|
||||
- Enable the prefetch engine
|
||||
- SYSCLK < 50 MHz
|
||||
***********************************************************************/
|
||||
SFRPAGE = 0x10;
|
||||
PFE0CN = PFE0CN_PFEN__ENABLED | PFE0CN_FLRT__SYSCLK_BELOW_50_MHZ;
|
||||
// [PFE0CN - Prefetch Engine Control]$
|
||||
|
||||
}
|
||||
|
||||
extern void PBCFG_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[XBR2 - Port I/O Crossbar 2]
|
||||
/***********************************************************************
|
||||
- Weak Pullups enabled
|
||||
- Crossbar enabled
|
||||
- UART1 I/O unavailable at Port pin
|
||||
- UART1 RTS1 unavailable at Port pin
|
||||
- UART1 CTS1 unavailable at Port pin
|
||||
***********************************************************************/
|
||||
XBR2 = XBR2_WEAKPUD__PULL_UPS_ENABLED | XBR2_XBARE__ENABLED
|
||||
| XBR2_URT1E__DISABLED | XBR2_URT1RTSE__DISABLED
|
||||
| XBR2_URT1CTSE__DISABLED;
|
||||
// [XBR2 - Port I/O Crossbar 2]$
|
||||
|
||||
// $[PRTDRV - Port Drive Strength]
|
||||
// [PRTDRV - Port Drive Strength]$
|
||||
|
||||
// $[XBR0 - Port I/O Crossbar 0]
|
||||
/***********************************************************************
|
||||
- UART0 TX0, RX0 routed to Port pins P0.4 and P0.5
|
||||
- SPI I/O routed to Port pins
|
||||
- SMBus 0 I/O unavailable at Port pins
|
||||
- CP0 unavailable at Port pin
|
||||
- Asynchronous CP0 unavailable at Port pin
|
||||
- CP1 unavailable at Port pin
|
||||
- Asynchronous CP1 unavailable at Port pin
|
||||
- SYSCLK unavailable at Port pin
|
||||
***********************************************************************/
|
||||
XBR0 = XBR0_URT0E__ENABLED | XBR0_SPI0E__ENABLED | XBR0_SMB0E__DISABLED
|
||||
| XBR0_CP0E__DISABLED | XBR0_CP0AE__DISABLED | XBR0_CP1E__DISABLED
|
||||
| XBR0_CP1AE__DISABLED | XBR0_SYSCKE__DISABLED;
|
||||
// [XBR0 - Port I/O Crossbar 0]$
|
||||
|
||||
// $[XBR1 - Port I/O Crossbar 1]
|
||||
// [XBR1 - Port I/O Crossbar 1]$
|
||||
|
||||
}
|
||||
|
||||
extern void TIMER_SETUP_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[CKCON0 - Clock Control 0]
|
||||
/***********************************************************************
|
||||
- System clock divided by 4
|
||||
- Counter/Timer 0 uses the clock defined by the prescale field, SCA
|
||||
- Timer 2 high byte uses the clock defined by T2XCLK in TMR2CN0
|
||||
- Timer 2 low byte uses the clock defined by T2XCLK in TMR2CN0
|
||||
- Timer 3 high byte uses the clock defined by T3XCLK in TMR3CN0
|
||||
- Timer 3 low byte uses the clock defined by T3XCLK in TMR3CN0
|
||||
- Timer 1 uses the system clock
|
||||
***********************************************************************/
|
||||
CKCON0 = CKCON0_SCA__SYSCLK_DIV_4 | CKCON0_T0M__PRESCALE
|
||||
| CKCON0_T2MH__EXTERNAL_CLOCK | CKCON0_T2ML__EXTERNAL_CLOCK
|
||||
| CKCON0_T3MH__EXTERNAL_CLOCK | CKCON0_T3ML__EXTERNAL_CLOCK
|
||||
| CKCON0_T1M__SYSCLK;
|
||||
// [CKCON0 - Clock Control 0]$
|
||||
|
||||
// $[CKCON1 - Clock Control 1]
|
||||
// [CKCON1 - Clock Control 1]$
|
||||
|
||||
// $[TMOD - Timer 0/1 Mode]
|
||||
/***********************************************************************
|
||||
- Mode 0, 13-bit Counter/Timer
|
||||
- Mode 2, 8-bit Counter/Timer with Auto-Reload
|
||||
- Timer Mode
|
||||
- Timer 0 enabled when TR0 = 1 irrespective of INT0 logic level
|
||||
- Timer Mode
|
||||
- Timer 1 enabled when TR1 = 1 irrespective of INT1 logic level
|
||||
***********************************************************************/
|
||||
TMOD = TMOD_T0M__MODE0 | TMOD_T1M__MODE2 | TMOD_CT0__TIMER
|
||||
| TMOD_GATE0__DISABLED | TMOD_CT1__TIMER | TMOD_GATE1__DISABLED;
|
||||
// [TMOD - Timer 0/1 Mode]$
|
||||
|
||||
// $[TCON - Timer 0/1 Control]
|
||||
/***********************************************************************
|
||||
- Start Timer 1 running
|
||||
***********************************************************************/
|
||||
TCON |= TCON_TR1__RUN;
|
||||
// [TCON - Timer 0/1 Control]$
|
||||
|
||||
}
|
||||
|
||||
extern void UARTE_1_enter_DefaultMode_from_RESET(void) {
|
||||
// $[SBCON1 - UART1 Baud Rate Generator Control]
|
||||
/***********************************************************************
|
||||
- Enable the baud rate generator
|
||||
- Prescaler = 8
|
||||
***********************************************************************/
|
||||
SFRPAGE = 0x20;
|
||||
SBCON1 = SBCON1_BREN__ENABLED | SBCON1_BPS__DIV_BY_8;
|
||||
// [SBCON1 - UART1 Baud Rate Generator Control]$
|
||||
|
||||
// $[SMOD1 - UART1 Mode]
|
||||
// [SMOD1 - UART1 Mode]$
|
||||
|
||||
// $[UART1FCN0 - UART1 FIFO Control 0]
|
||||
// [UART1FCN0 - UART1 FIFO Control 0]$
|
||||
|
||||
// $[SBRLH1 - UART1 Baud Rate Generator High Byte]
|
||||
/***********************************************************************
|
||||
- UART1 Baud Rate Reload High = 0xFF
|
||||
***********************************************************************/
|
||||
SBRLH1 = (0xFF << SBRLH1_BRH__SHIFT);
|
||||
// [SBRLH1 - UART1 Baud Rate Generator High Byte]$
|
||||
|
||||
// $[SBRLL1 - UART1 Baud Rate Generator Low Byte]
|
||||
/***********************************************************************
|
||||
- UART1 Baud Rate Reload Low = 0xE6
|
||||
***********************************************************************/
|
||||
SBRLL1 = (0xE6 << SBRLL1_BRL__SHIFT);
|
||||
// [SBRLL1 - UART1 Baud Rate Generator Low Byte]$
|
||||
|
||||
// $[UART1LIN - UART1 LIN Configuration]
|
||||
// [UART1LIN - UART1 LIN Configuration]$
|
||||
|
||||
// $[SCON1 - UART1 Serial Port Control]
|
||||
/***********************************************************************
|
||||
- UART1 reception enabled
|
||||
***********************************************************************/
|
||||
SCON1 |= SCON1_REN__RECEIVE_ENABLED;
|
||||
// [SCON1 - UART1 Serial Port Control]$
|
||||
|
||||
// $[UART1FCN1 - UART1 FIFO Control 1]
|
||||
// [UART1FCN1 - UART1 FIFO Control 1]$
|
||||
|
||||
}
|
||||
|
||||
extern void TIMER16_2_enter_DefaultMode_from_RESET(void) {
|
||||
// $[Timer Initialization]
|
||||
// Save Timer Configuration
|
||||
uint8_t TMR2CN0_TR2_save;
|
||||
TMR2CN0_TR2_save = TMR2CN0 & TMR2CN0_TR2__BMASK;
|
||||
// Stop Timer
|
||||
TMR2CN0 &= ~(TMR2CN0_TR2__BMASK);
|
||||
// [Timer Initialization]$
|
||||
|
||||
// $[TMR2CN1 - Timer 2 Control 1]
|
||||
// [TMR2CN1 - Timer 2 Control 1]$
|
||||
|
||||
// $[TMR2CN0 - Timer 2 Control]
|
||||
// [TMR2CN0 - Timer 2 Control]$
|
||||
|
||||
// $[TMR2H - Timer 2 High Byte]
|
||||
// [TMR2H - Timer 2 High Byte]$
|
||||
|
||||
// $[TMR2L - Timer 2 Low Byte]
|
||||
// [TMR2L - Timer 2 Low Byte]$
|
||||
|
||||
// $[TMR2RLH - Timer 2 Reload High Byte]
|
||||
/***********************************************************************
|
||||
- Timer 2 Reload High Byte = 0x63
|
||||
***********************************************************************/
|
||||
TMR2RLH = (0x63 << TMR2RLH_TMR2RLH__SHIFT);
|
||||
// [TMR2RLH - Timer 2 Reload High Byte]$
|
||||
|
||||
// $[TMR2RLL - Timer 2 Reload Low Byte]
|
||||
/***********************************************************************
|
||||
- Timer 2 Reload Low Byte = 0xC0
|
||||
***********************************************************************/
|
||||
TMR2RLL = (0xC0 << TMR2RLL_TMR2RLL__SHIFT);
|
||||
// [TMR2RLL - Timer 2 Reload Low Byte]$
|
||||
|
||||
// $[TMR2CN0]
|
||||
// [TMR2CN0]$
|
||||
|
||||
// $[Timer Restoration]
|
||||
// Restore Timer Configuration
|
||||
TMR2CN0 |= TMR2CN0_TR2_save;
|
||||
// [Timer Restoration]$
|
||||
|
||||
}
|
||||
|
||||
extern void TIMER16_3_enter_DefaultMode_from_RESET(void) {
|
||||
// $[Timer Initialization]
|
||||
// Save Timer Configuration
|
||||
uint8_t TMR3CN0_TR3_save;
|
||||
TMR3CN0_TR3_save = TMR3CN0 & TMR3CN0_TR3__BMASK;
|
||||
// Stop Timer
|
||||
TMR3CN0 &= ~(TMR3CN0_TR3__BMASK);
|
||||
// [Timer Initialization]$
|
||||
|
||||
// $[TMR3CN1 - Timer 3 Control 1]
|
||||
// [TMR3CN1 - Timer 3 Control 1]$
|
||||
|
||||
// $[TMR3CN0 - Timer 3 Control]
|
||||
/***********************************************************************
|
||||
- Timer 3 clock is the low-frequency oscillator divided by 8
|
||||
***********************************************************************/
|
||||
TMR3CN0 |= TMR3CN0_T3XCLK__LFOSC_DIV_8;
|
||||
// [TMR3CN0 - Timer 3 Control]$
|
||||
|
||||
// $[TMR3H - Timer 3 High Byte]
|
||||
// [TMR3H - Timer 3 High Byte]$
|
||||
|
||||
// $[TMR3L - Timer 3 Low Byte]
|
||||
// [TMR3L - Timer 3 Low Byte]$
|
||||
|
||||
// $[TMR3RLH - Timer 3 Reload High Byte]
|
||||
// [TMR3RLH - Timer 3 Reload High Byte]$
|
||||
|
||||
// $[TMR3RLL - Timer 3 Reload Low Byte]
|
||||
// [TMR3RLL - Timer 3 Reload Low Byte]$
|
||||
|
||||
// $[TMR3CN0]
|
||||
/***********************************************************************
|
||||
- Start Timer 3 running
|
||||
***********************************************************************/
|
||||
TMR3CN0 |= TMR3CN0_TR3__RUN;
|
||||
// [TMR3CN0]$
|
||||
|
||||
// $[Timer Restoration]
|
||||
// Restore Timer Configuration
|
||||
TMR3CN0 |= TMR3CN0_TR3_save;
|
||||
// [Timer Restoration]$
|
||||
|
||||
}
|
||||
|
||||
extern void PORTS_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[P0 - Port 0 Pin Latch]
|
||||
// [P0 - Port 0 Pin Latch]$
|
||||
|
||||
// $[P0MDOUT - Port 0 Output Mode]
|
||||
/***********************************************************************
|
||||
- P0.0 output is open-drain
|
||||
- P0.1 output is open-drain
|
||||
- P0.2 output is open-drain
|
||||
- P0.3 output is open-drain
|
||||
- P0.4 output is push-pull
|
||||
- P0.5 output is open-drain
|
||||
- P0.6 output is open-drain
|
||||
- P0.7 output is push-pull
|
||||
***********************************************************************/
|
||||
P0MDOUT = P0MDOUT_B0__OPEN_DRAIN | P0MDOUT_B1__OPEN_DRAIN
|
||||
| P0MDOUT_B2__OPEN_DRAIN | P0MDOUT_B3__OPEN_DRAIN
|
||||
| P0MDOUT_B4__PUSH_PULL | P0MDOUT_B5__OPEN_DRAIN
|
||||
| P0MDOUT_B6__OPEN_DRAIN | P0MDOUT_B7__PUSH_PULL;
|
||||
// [P0MDOUT - Port 0 Output Mode]$
|
||||
|
||||
// $[P0MDIN - Port 0 Input Mode]
|
||||
// [P0MDIN - Port 0 Input Mode]$
|
||||
|
||||
// $[P0SKIP - Port 0 Skip]
|
||||
/***********************************************************************
|
||||
- P0.0 pin is skipped by the crossbar
|
||||
- P0.1 pin is skipped by the crossbar
|
||||
- P0.2 pin is skipped by the crossbar
|
||||
- P0.3 pin is skipped by the crossbar
|
||||
- P0.4 pin is not skipped by the crossbar
|
||||
- P0.5 pin is not skipped by the crossbar
|
||||
- P0.6 pin is not skipped by the crossbar
|
||||
- P0.7 pin is not skipped by the crossbar
|
||||
***********************************************************************/
|
||||
P0SKIP = P0SKIP_B0__SKIPPED | P0SKIP_B1__SKIPPED | P0SKIP_B2__SKIPPED
|
||||
| P0SKIP_B3__SKIPPED | P0SKIP_B4__NOT_SKIPPED
|
||||
| P0SKIP_B5__NOT_SKIPPED | P0SKIP_B6__NOT_SKIPPED
|
||||
| P0SKIP_B7__NOT_SKIPPED;
|
||||
// [P0SKIP - Port 0 Skip]$
|
||||
|
||||
// $[P0MASK - Port 0 Mask]
|
||||
// [P0MASK - Port 0 Mask]$
|
||||
|
||||
// $[P0MAT - Port 0 Match]
|
||||
// [P0MAT - Port 0 Match]$
|
||||
|
||||
}
|
||||
|
||||
extern void PORTS_1_enter_DefaultMode_from_RESET(void) {
|
||||
|
||||
// $[P1 - Port 1 Pin Latch]
|
||||
/***********************************************************************
|
||||
- P1.0 is high. Set P1.0 to drive or float high
|
||||
- P1.1 is high. Set P1.1 to drive or float high
|
||||
- P1.2 is low. Set P1.2 to drive low
|
||||
- P1.3 is high. Set P1.3 to drive or float high
|
||||
- P1.4 is high. Set P1.4 to drive or float high
|
||||
- P1.5 is high. Set P1.5 to drive or float high
|
||||
- P1.6 is high. Set P1.6 to drive or float high
|
||||
- P1.7 is high. Set P1.7 to drive or float high
|
||||
***********************************************************************/
|
||||
P1 = P1_B0__HIGH | P1_B1__HIGH | P1_B2__LOW | P1_B3__HIGH | P1_B4__HIGH
|
||||
| P1_B5__HIGH | P1_B6__HIGH | P1_B7__HIGH;
|
||||
// [P1 - Port 1 Pin Latch]$
|
||||
|
||||
// $[P1MDOUT - Port 1 Output Mode]
|
||||
/***********************************************************************
|
||||
- P1.0 output is open-drain
|
||||
- P1.1 output is push-pull
|
||||
- P1.2 output is open-drain
|
||||
- P1.3 output is open-drain
|
||||
- P1.4 output is push-pull
|
||||
- P1.5 output is push-pull
|
||||
- P1.6 output is push-pull
|
||||
- P1.7 output is open-drain
|
||||
***********************************************************************/
|
||||
P1MDOUT = P1MDOUT_B0__OPEN_DRAIN | P1MDOUT_B1__PUSH_PULL
|
||||
| P1MDOUT_B2__OPEN_DRAIN | P1MDOUT_B3__OPEN_DRAIN
|
||||
| P1MDOUT_B4__PUSH_PULL | P1MDOUT_B5__PUSH_PULL
|
||||
| P1MDOUT_B6__PUSH_PULL | P1MDOUT_B7__OPEN_DRAIN;
|
||||
// [P1MDOUT - Port 1 Output Mode]$
|
||||
|
||||
// $[P1MDIN - Port 1 Input Mode]
|
||||
// [P1MDIN - Port 1 Input Mode]$
|
||||
|
||||
// $[P1SKIP - Port 1 Skip]
|
||||
// [P1SKIP - Port 1 Skip]$
|
||||
|
||||
// $[P1MASK - Port 1 Mask]
|
||||
// [P1MASK - Port 1 Mask]$
|
||||
|
||||
// $[P1MAT - Port 1 Match]
|
||||
// [P1MAT - Port 1 Match]$
|
||||
|
||||
}
|
||||
|
||||
extern void PORTS_2_enter_DefaultMode_from_RESET(void) {
|
||||
|
||||
// $[P2 - Port 2 Pin Latch]
|
||||
/***********************************************************************
|
||||
- P2.0 is low. Set P2.0 to drive low
|
||||
- P2.1 is high. Set P2.1 to drive or float high
|
||||
- P2.2 is high. Set P2.2 to drive or float high
|
||||
- P2.3 is high. Set P2.3 to drive or float high
|
||||
***********************************************************************/
|
||||
P2 = P2_B0__LOW | P2_B1__HIGH | P2_B2__HIGH | P2_B3__HIGH;
|
||||
// [P2 - Port 2 Pin Latch]$
|
||||
|
||||
// $[P2MDOUT - Port 2 Output Mode]
|
||||
/***********************************************************************
|
||||
- P2.0 output is push-pull
|
||||
- P2.1 output is open-drain
|
||||
- P2.2 output is open-drain
|
||||
- P2.3 output is open-drain
|
||||
***********************************************************************/
|
||||
P2MDOUT = P2MDOUT_B0__PUSH_PULL | P2MDOUT_B1__OPEN_DRAIN
|
||||
| P2MDOUT_B2__OPEN_DRAIN | P2MDOUT_B3__OPEN_DRAIN;
|
||||
// [P2MDOUT - Port 2 Output Mode]$
|
||||
|
||||
// $[P2MDIN - Port 2 Input Mode]
|
||||
// [P2MDIN - Port 2 Input Mode]$
|
||||
|
||||
// $[P2SKIP - Port 2 Skip]
|
||||
// [P2SKIP - Port 2 Skip]$
|
||||
|
||||
// $[P2MASK - Port 2 Mask]
|
||||
// [P2MASK - Port 2 Mask]$
|
||||
|
||||
// $[P2MAT - Port 2 Match]
|
||||
// [P2MAT - Port 2 Match]$
|
||||
|
||||
}
|
||||
|
||||
extern void TIMER01_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[Timer Initialization]
|
||||
//Save Timer Configuration
|
||||
uint8_t TCON_save;
|
||||
TCON_save = TCON;
|
||||
//Stop Timers
|
||||
TCON &= ~TCON_TR0__BMASK & ~TCON_TR1__BMASK;
|
||||
|
||||
// [Timer Initialization]$
|
||||
|
||||
// $[TH0 - Timer 0 High Byte]
|
||||
// [TH0 - Timer 0 High Byte]$
|
||||
|
||||
// $[TL0 - Timer 0 Low Byte]
|
||||
// [TL0 - Timer 0 Low Byte]$
|
||||
|
||||
// $[TH1 - Timer 1 High Byte]
|
||||
/***********************************************************************
|
||||
- Timer 1 High Byte = 0x30
|
||||
***********************************************************************/
|
||||
TH1 = (0x30 << TH1_TH1__SHIFT);
|
||||
// [TH1 - Timer 1 High Byte]$
|
||||
|
||||
// $[TL1 - Timer 1 Low Byte]
|
||||
// [TL1 - Timer 1 Low Byte]$
|
||||
|
||||
// $[Timer Restoration]
|
||||
//Restore Timer Configuration
|
||||
TCON |= (TCON_save & TCON_TR0__BMASK) | (TCON_save & TCON_TR1__BMASK);
|
||||
|
||||
// [Timer Restoration]$
|
||||
|
||||
}
|
||||
|
||||
extern void UART_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[SCON0 - UART0 Serial Port Control]
|
||||
/***********************************************************************
|
||||
- UART0 reception enabled
|
||||
***********************************************************************/
|
||||
SCON0 |= SCON0_REN__RECEIVE_ENABLED;
|
||||
// [SCON0 - UART0 Serial Port Control]$
|
||||
|
||||
}
|
||||
|
||||
extern void SPI_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[SPI0CKR - SPI0 Clock Rate]
|
||||
/***********************************************************************
|
||||
- SPI0 Clock Rate = 0x0B
|
||||
***********************************************************************/
|
||||
SPI0CKR = (0x0B << SPI0CKR_SPI0CKR__SHIFT);
|
||||
// [SPI0CKR - SPI0 Clock Rate]$
|
||||
|
||||
// $[SPI0FCN0 - SPI0 FIFO Control 0]
|
||||
// [SPI0FCN0 - SPI0 FIFO Control 0]$
|
||||
|
||||
// $[SPI0FCN1 - SPI0 FIFO Control 1]
|
||||
// [SPI0FCN1 - SPI0 FIFO Control 1]$
|
||||
|
||||
// $[SPI0CFG - SPI0 Configuration]
|
||||
// [SPI0CFG - SPI0 Configuration]$
|
||||
|
||||
// $[SPI0CN0 - SPI0 Control]
|
||||
/***********************************************************************
|
||||
- Enable the SPI module
|
||||
- 3-Wire Slave or 3-Wire Master Mode
|
||||
***********************************************************************/
|
||||
SPI0CN0 &= ~SPI0CN0_NSSMD__FMASK;
|
||||
SPI0CN0 |= SPI0CN0_SPIEN__ENABLED;
|
||||
// [SPI0CN0 - SPI0 Control]$
|
||||
|
||||
}
|
||||
|
||||
extern void LFOSC_0_enter_DefaultMode_from_RESET(void) {
|
||||
// $[LFO0CN - Low Frequency Oscillator Control]
|
||||
/***********************************************************************
|
||||
- Internal L-F Oscillator Enabled
|
||||
- Divide by 8 selected
|
||||
***********************************************************************/
|
||||
LFO0CN &= ~LFO0CN_OSCLD__FMASK;
|
||||
LFO0CN |= LFO0CN_OSCLEN__ENABLED;
|
||||
// [LFO0CN - Low Frequency Oscillator Control]$
|
||||
|
||||
// $[Wait for LFOSC Ready]
|
||||
while ((LFO0CN & LFO0CN_OSCLRDY__BMASK) != LFO0CN_OSCLRDY__SET)
|
||||
;
|
||||
// [Wait for LFOSC Ready]$
|
||||
|
||||
}
|
||||
|
203
targets/efm8/src/SILABS_STARTUP.A51
Normal file
203
targets/efm8/src/SILABS_STARTUP.A51
Normal file
@@ -0,0 +1,203 @@
|
||||
$NOMOD51
|
||||
;------------------------------------------------------------------------------
|
||||
; This file is part of the C51 Compiler package
|
||||
; Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc.
|
||||
; Version 8.01
|
||||
;
|
||||
; *** <<< Use Configuration Wizard in Context Menu >>> ***
|
||||
;------------------------------------------------------------------------------
|
||||
; STARTUP.A51: This code is executed after processor reset.
|
||||
;
|
||||
; To translate this file use A51 with the following invocation:
|
||||
;
|
||||
; A51 STARTUP.A51
|
||||
;
|
||||
; To link the modified STARTUP.OBJ file to your application use the following
|
||||
; Lx51 invocation:
|
||||
;
|
||||
; Lx51 your object file list, STARTUP.OBJ controls
|
||||
;
|
||||
;------------------------------------------------------------------------------
|
||||
;
|
||||
; User-defined <h> Power-On Initialization of Memory
|
||||
;
|
||||
; With the following EQU statements the initialization of memory
|
||||
; at processor reset can be defined:
|
||||
;
|
||||
; <o> IDATALEN: IDATA memory size <0x0-0x100>
|
||||
; <i> Note: The absolute start-address of IDATA memory is always 0
|
||||
; <i> The IDATA space overlaps physically the DATA and BIT areas.
|
||||
IDATALEN EQU 80H
|
||||
;
|
||||
; <o> XDATASTART: XDATA memory start address <0x0-0xFFFF>
|
||||
; <i> The absolute start address of XDATA memory
|
||||
XDATASTART EQU 0
|
||||
;
|
||||
; <o> XDATALEN: XDATA memory size <0x0-0xFFFF>
|
||||
; <i> The length of XDATA memory in bytes.
|
||||
XDATALEN EQU 0
|
||||
;
|
||||
; <o> PDATASTART: PDATA memory start address <0x0-0xFFFF>
|
||||
; <i> The absolute start address of PDATA memory
|
||||
PDATASTART EQU 0H
|
||||
;
|
||||
; <o> PDATALEN: PDATA memory size <0x0-0xFF>
|
||||
; <i> The length of PDATA memory in bytes.
|
||||
PDATALEN EQU 0H
|
||||
;
|
||||
;</h>
|
||||
;------------------------------------------------------------------------------
|
||||
;
|
||||
;<h> Reentrant Stack Initialization
|
||||
;
|
||||
; The following EQU statements define the stack pointer for reentrant
|
||||
; functions and initialized it:
|
||||
;
|
||||
; <h> Stack Space for reentrant functions in the SMALL model.
|
||||
; <q> IBPSTACK: Enable SMALL model reentrant stack
|
||||
; <i> Stack space for reentrant functions in the SMALL model.
|
||||
IBPSTACK EQU 0 ; set to 1 if small reentrant is used.
|
||||
; <o> IBPSTACKTOP: End address of SMALL model stack <0x0-0xFF>
|
||||
; <i> Set the top of the stack to the highest location.
|
||||
IBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1
|
||||
; </h>
|
||||
;
|
||||
; <h> Stack Space for reentrant functions in the LARGE model.
|
||||
; <q> XBPSTACK: Enable LARGE model reentrant stack
|
||||
; <i> Stack space for reentrant functions in the LARGE model.
|
||||
XBPSTACK EQU 0 ; set to 1 if large reentrant is used.
|
||||
; <o> XBPSTACKTOP: End address of LARGE model stack <0x0-0xFFFF>
|
||||
; <i> Set the top of the stack to the highest location.
|
||||
XBPSTACKTOP EQU 0xFFFF +1 ; default 0FFFFH+1
|
||||
; </h>
|
||||
;
|
||||
; <h> Stack Space for reentrant functions in the COMPACT model.
|
||||
; <q> PBPSTACK: Enable COMPACT model reentrant stack
|
||||
; <i> Stack space for reentrant functions in the COMPACT model.
|
||||
PBPSTACK EQU 0 ; set to 1 if compact reentrant is used.
|
||||
;
|
||||
; <o> PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF>
|
||||
; <i> Set the top of the stack to the highest location.
|
||||
PBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1
|
||||
; </h>
|
||||
;</h>
|
||||
;------------------------------------------------------------------------------
|
||||
;
|
||||
; Memory Page for Using the Compact Model with 64 KByte xdata RAM
|
||||
; <e>Compact Model Page Definition
|
||||
;
|
||||
; <i>Define the XDATA page used for PDATA variables.
|
||||
; <i>PPAGE must conform with the PPAGE set in the linker invocation.
|
||||
;
|
||||
; Enable pdata memory page initalization
|
||||
PPAGEENABLE EQU 0 ; set to 1 if pdata object are used.
|
||||
;
|
||||
; <o> PPAGE number <0x0-0xFF>
|
||||
; <i> uppermost 256-byte address of the page used for PDATA variables.
|
||||
PPAGE EQU 0
|
||||
;
|
||||
; <o> SFR address which supplies uppermost address byte <0x0-0xFF>
|
||||
; <i> most 8051 variants use P2 as uppermost address byte
|
||||
PPAGE_SFR DATA 0A0H
|
||||
;
|
||||
; </e>
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
; Standard SFR Symbols
|
||||
ACC DATA 0E0H
|
||||
B DATA 0F0H
|
||||
SP DATA 81H
|
||||
DPL DATA 82H
|
||||
DPH DATA 83H
|
||||
|
||||
NAME ?C_STARTUP
|
||||
|
||||
|
||||
?C_C51STARTUP SEGMENT CODE
|
||||
?STACK SEGMENT IDATA
|
||||
|
||||
RSEG ?STACK
|
||||
DS 1
|
||||
|
||||
EXTRN CODE (?C_START)
|
||||
PUBLIC ?C_STARTUP
|
||||
|
||||
CSEG AT 0
|
||||
?C_STARTUP: LJMP STARTUP1
|
||||
|
||||
RSEG ?C_C51STARTUP
|
||||
|
||||
STARTUP1:
|
||||
|
||||
$IF (SILABS_STARTUP = 1)
|
||||
EXTRN CODE (SiLabs_Startup)
|
||||
LCALL SiLabs_Startup
|
||||
$ENDIF
|
||||
|
||||
IF IDATALEN <> 0
|
||||
MOV R0,#IDATALEN - 1
|
||||
CLR A
|
||||
IDATALOOP: MOV @R0,A
|
||||
DJNZ R0,IDATALOOP
|
||||
ENDIF
|
||||
|
||||
IF XDATALEN <> 0
|
||||
MOV DPTR,#XDATASTART
|
||||
MOV R7,#LOW (XDATALEN)
|
||||
IF (LOW (XDATALEN)) <> 0
|
||||
MOV R6,#(HIGH (XDATALEN)) +1
|
||||
ELSE
|
||||
MOV R6,#HIGH (XDATALEN)
|
||||
ENDIF
|
||||
CLR A
|
||||
XDATALOOP: MOVX @DPTR,A
|
||||
INC DPTR
|
||||
DJNZ R7,XDATALOOP
|
||||
DJNZ R6,XDATALOOP
|
||||
ENDIF
|
||||
|
||||
IF PPAGEENABLE <> 0
|
||||
MOV PPAGE_SFR,#PPAGE
|
||||
ENDIF
|
||||
|
||||
IF PDATALEN <> 0
|
||||
MOV R0,#LOW (PDATASTART)
|
||||
MOV R7,#LOW (PDATALEN)
|
||||
CLR A
|
||||
PDATALOOP: MOVX @R0,A
|
||||
INC R0
|
||||
DJNZ R7,PDATALOOP
|
||||
ENDIF
|
||||
|
||||
IF IBPSTACK <> 0
|
||||
EXTRN DATA (?C_IBP)
|
||||
|
||||
MOV ?C_IBP,#LOW IBPSTACKTOP
|
||||
ENDIF
|
||||
|
||||
IF XBPSTACK <> 0
|
||||
EXTRN DATA (?C_XBP)
|
||||
|
||||
MOV ?C_XBP,#HIGH XBPSTACKTOP
|
||||
MOV ?C_XBP+1,#LOW XBPSTACKTOP
|
||||
ENDIF
|
||||
|
||||
IF PBPSTACK <> 0
|
||||
EXTRN DATA (?C_PBP)
|
||||
MOV ?C_PBP,#LOW PBPSTACKTOP
|
||||
ENDIF
|
||||
|
||||
MOV SP,#?STACK-1
|
||||
|
||||
; This code is required if you use L51_BANK.A51 with Banking Mode 4
|
||||
;<h> Code Banking
|
||||
; <q> Select Bank 0 for L51_BANK.A51 Mode 4
|
||||
$IF (USE_BANKING = 1)
|
||||
; <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.
|
||||
EXTRN CODE (?B_SWITCH0)
|
||||
CALL ?B_SWITCH0 ; init bank mechanism to code bank 0
|
||||
$ENDIF
|
||||
;</h>
|
||||
LJMP ?C_START
|
||||
|
||||
END
|
152
targets/efm8/src/callback.c
Normal file
152
targets/efm8/src/callback.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Conor Patrick
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#include <SI_EFM8UB1_Register_Enums.h>
|
||||
#include <efm8_usb.h>
|
||||
#include <stdio.h>
|
||||
#include "printing.h"
|
||||
#include "descriptors.h"
|
||||
#include "app.h"
|
||||
|
||||
#define UNUSED(expr) do { (void)(expr); } while (0)
|
||||
|
||||
#define HID_INTERFACE_INDEX 0
|
||||
|
||||
uint8_t tmpBuffer;
|
||||
|
||||
|
||||
|
||||
void USBD_ResetCb(void) {
|
||||
// cprints("USBD_ResetCb\r\n");
|
||||
// u2f_print_ev("USBD_ResetCb\r\n");
|
||||
}
|
||||
|
||||
|
||||
void USBD_DeviceStateChangeCb(USBD_State_TypeDef oldState,
|
||||
USBD_State_TypeDef newState) {
|
||||
|
||||
// cprints("USBD_DeviceStateChangeCb\r\n");
|
||||
UNUSED(oldState);
|
||||
UNUSED(newState);
|
||||
|
||||
// u2f_print_ev("USBD_DeviceStateChangeCb\r\n");
|
||||
}
|
||||
|
||||
bool USBD_IsSelfPoweredCb(void) {
|
||||
// cprints("USBD_IsSelfPoweredCb\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Necessary routine for USB HID
|
||||
USB_Status_TypeDef USBD_SetupCmdCb(
|
||||
SI_VARIABLE_SEGMENT_POINTER(setup, USB_Setup_TypeDef, MEM_MODEL_SEG)) {
|
||||
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_UNHANDLED;
|
||||
|
||||
|
||||
if ((setup->bmRequestType.Type == USB_SETUP_TYPE_STANDARD)
|
||||
&& (setup->bmRequestType.Direction == USB_SETUP_DIR_IN)
|
||||
&& (setup->bmRequestType.Recipient == USB_SETUP_RECIPIENT_INTERFACE)) {
|
||||
// A HID device must extend the standard GET_DESCRIPTOR command
|
||||
// with support for HID descriptors.
|
||||
|
||||
switch (setup->bRequest) {
|
||||
case GET_DESCRIPTOR:
|
||||
if (setup->wIndex == 0)
|
||||
{
|
||||
if ((setup->wValue >> 8) == USB_HID_REPORT_DESCRIPTOR) {
|
||||
|
||||
USBD_Write(EP0, ReportDescriptor0,
|
||||
EFM8_MIN(sizeof(ReportDescriptor0), setup->wLength),
|
||||
false);
|
||||
retVal = USB_STATUS_OK;
|
||||
|
||||
} else if ((setup->wValue >> 8) == USB_HID_DESCRIPTOR) {
|
||||
|
||||
USBD_Write(EP0, (&configDesc[18]),
|
||||
EFM8_MIN(USB_HID_DESCSIZE, setup->wLength), false);
|
||||
retVal = USB_STATUS_OK;
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((setup->bmRequestType.Type == USB_SETUP_TYPE_CLASS)
|
||||
&& (setup->bmRequestType.Recipient == USB_SETUP_RECIPIENT_INTERFACE)
|
||||
&& (setup->wIndex == HID_INTERFACE_INDEX))
|
||||
{
|
||||
// Implement the necessary HID class specific commands.
|
||||
switch (setup->bRequest)
|
||||
{
|
||||
case USB_HID_SET_IDLE:
|
||||
if (((setup->wValue & 0xFF) == 0) // Report ID
|
||||
&& (setup->wLength == 0)
|
||||
&& (setup->bmRequestType.Direction != USB_SETUP_DIR_IN))
|
||||
{
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_HID_GET_IDLE:
|
||||
if ((setup->wValue == 0) // Report ID
|
||||
&& (setup->wLength == 1)
|
||||
&& (setup->bmRequestType.Direction == USB_SETUP_DIR_IN))
|
||||
{
|
||||
tmpBuffer = 24;
|
||||
USBD_Write(EP0, &tmpBuffer, 1, false);
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
uint16_t USBD_XferCompleteCb(uint8_t epAddr, USB_Status_TypeDef status,
|
||||
uint16_t xferred, uint16_t remaining ) {
|
||||
|
||||
UNUSED(status);
|
||||
UNUSED(xferred);
|
||||
UNUSED(remaining);
|
||||
|
||||
if (epAddr == INPUT_ENDPOINT)
|
||||
{
|
||||
usb_transfer_complete();
|
||||
}
|
||||
else if (epAddr == OUTPUT_ENDPOINT)
|
||||
{
|
||||
usb_writeback_complete();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
183
targets/efm8/src/descriptors.c
Normal file
183
targets/efm8/src/descriptors.c
Normal file
@@ -0,0 +1,183 @@
|
||||
//=============================================================================
|
||||
// src/descriptors.c: generated by Hardware Configurator
|
||||
//
|
||||
// This file is only generated if it does not exist. Modifications in this file
|
||||
// will persist even if Configurator generates code. To refresh this file,
|
||||
// you must first delete it and then regenerate code.
|
||||
//=============================================================================
|
||||
//-----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <si_toolchain.h>
|
||||
#include <endian.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <efm8_usb.h>
|
||||
#include "descriptors.h"
|
||||
#include "app.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// HID Report Descriptor for Interface 0
|
||||
SI_SEGMENT_VARIABLE(ReportDescriptor0[34],
|
||||
const uint8_t,
|
||||
SI_SEG_CODE) =
|
||||
{
|
||||
|
||||
0x06, 0xd0, 0xf1,// USAGE_PAGE (FIDO Alliance)
|
||||
0x09, 0x01,// USAGE (Keyboard)
|
||||
0xa1, 0x01,// COLLECTION (Application)
|
||||
|
||||
0x09, 0x20, // USAGE (Input Report Data)
|
||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
|
||||
0x75, 0x08, // REPORT_SIZE (8)
|
||||
0x95, HID_PACKET_SIZE, // REPORT_COUNT (64)
|
||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||||
0x09, 0x21, // USAGE(Output Report Data)
|
||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
|
||||
0x75, 0x08, // REPORT_SIZE (8)
|
||||
0x95, HID_PACKET_SIZE, // REPORT_COUNT (64)
|
||||
0x91, 0x02, // OUTPUT (Data,Var,Abs)
|
||||
|
||||
|
||||
0xc0,// END_COLLECTION
|
||||
|
||||
};
|
||||
SI_SEGMENT_VARIABLE(deviceDesc[],
|
||||
const USB_DeviceDescriptor_TypeDef,
|
||||
SI_SEG_CODE) =
|
||||
{
|
||||
USB_DEVICE_DESCSIZE, // bLength
|
||||
USB_DEVICE_DESCRIPTOR,// bLength
|
||||
htole16(0x0200),// bcdUSB
|
||||
0,// bDeviceClass
|
||||
0,// bDeviceSubClass
|
||||
0,// bDeviceProtocol
|
||||
64,// bMaxPacketSize
|
||||
USB_VENDOR_ID,// idVendor
|
||||
USB_PRODUCT_ID,// idProduct
|
||||
htole16(0x0100),// bcdDevice
|
||||
1,// iManufacturer
|
||||
2,// iProduct
|
||||
3,// iSerialNumber
|
||||
1,// bNumConfigurations
|
||||
};
|
||||
|
||||
SI_SEGMENT_VARIABLE(configDesc[],
|
||||
const uint8_t,
|
||||
SI_SEG_CODE) =
|
||||
{
|
||||
USB_CONFIG_DESCSIZE, // bLength
|
||||
USB_CONFIG_DESCRIPTOR,// bLength
|
||||
0x29,// wTotalLength(LSB)
|
||||
0x00,// wTotalLength(MSB)
|
||||
1,// bNumInterfaces
|
||||
1,// bConfigurationValue
|
||||
0,// iConfiguration
|
||||
|
||||
CONFIG_DESC_BM_RESERVED_D7,// bmAttrib: Bus powered
|
||||
|
||||
CONFIG_DESC_MAXPOWER_mA(100),// bMaxPower: 100 mA
|
||||
|
||||
//Interface 0 Descriptor
|
||||
USB_INTERFACE_DESCSIZE,// bLength
|
||||
USB_INTERFACE_DESCRIPTOR,// bDescriptorType
|
||||
0,// bInterfaceNumber
|
||||
0,// bAlternateSetting
|
||||
2,// bNumEndpoints
|
||||
3,// bInterfaceClass: HID (Human Interface Device)
|
||||
0,// bInterfaceSubClass
|
||||
0,// bInterfaceProtocol
|
||||
4,// iInterface
|
||||
|
||||
//HID Descriptor
|
||||
USB_HID_DESCSIZE,// bLength
|
||||
USB_HID_DESCRIPTOR,// bLength
|
||||
0x11,// bcdHID (LSB)
|
||||
0x01,// bcdHID (MSB)
|
||||
0,// bCountryCode
|
||||
1,// bNumDescriptors
|
||||
USB_HID_REPORT_DESCRIPTOR,// bDescriptorType
|
||||
sizeof( ReportDescriptor0 ),// wDescriptorLength(LSB)
|
||||
sizeof( ReportDescriptor0 )>>8,// wDescriptorLength(MSB)
|
||||
|
||||
//Endpoint 2 IN Descriptor
|
||||
USB_ENDPOINT_DESCSIZE,// bLength
|
||||
USB_ENDPOINT_DESCRIPTOR,// bDescriptorType
|
||||
OUTPUT_ENDPOINT_NUM,// bEndpointAddress
|
||||
USB_EPTYPE_INTR,// bAttrib
|
||||
HID_PACKET_SIZE,// wMaxPacketSize (LSB)
|
||||
0x00,// wMaxPacketSize (MSB)
|
||||
5,// bInterval
|
||||
|
||||
//Endpoint 3 OUT Descriptor
|
||||
USB_ENDPOINT_DESCSIZE,// bLength
|
||||
USB_ENDPOINT_DESCRIPTOR,// bDescriptorType
|
||||
INPUT_ENDPOINT_NUM,// bEndpointAddress
|
||||
USB_EPTYPE_INTR,// bAttrib
|
||||
HID_PACKET_SIZE,// wMaxPacketSize (LSB)
|
||||
0x00,// wMaxPacketSize (MSB)
|
||||
5,// bInterval
|
||||
};
|
||||
|
||||
#define LANG_STRING htole16( SLAB_USB_LANGUAGE )
|
||||
#define MFR_STRING 'S','i','l','i','c','o','n',' ','L','a','b','s','\0'
|
||||
#define MFR_SIZE 13
|
||||
|
||||
#define SER_STRING '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','\0'
|
||||
#define SER_SIZE 17
|
||||
#define CFG_STRING 'C','o','n','f','i','g',' ','#','1','\0'
|
||||
#define CFG_SIZE 10
|
||||
#ifdef BRIDGE_TO_WALLET
|
||||
#define INT0_STRING 'E','O','S',' ','W','a','l','l','e','t','\0'
|
||||
#define INT0_SIZE 11
|
||||
#define PROD_STRING 'E','O','S',' ','W','a','l','l','e','t','\0'
|
||||
#define PROD_SIZE 11
|
||||
#else
|
||||
#define INT0_STRING 'S','o','l','o',' ','K','e','y','\0'
|
||||
#define INT0_SIZE 9
|
||||
#define PROD_STRING 'S','o','l','o',' ','K','e','y','\0'
|
||||
#define PROD_SIZE 9
|
||||
#endif
|
||||
|
||||
LANGID_STATIC_CONST_STRING_DESC( langDesc[], LANG_STRING );
|
||||
UTF16LE_PACKED_STATIC_CONST_STRING_DESC( mfrDesc[], MFR_STRING, MFR_SIZE);
|
||||
UTF16LE_PACKED_STATIC_CONST_STRING_DESC( prodDesc[], PROD_STRING, PROD_SIZE);
|
||||
UTF16LE_PACKED_STATIC_CONST_STRING_DESC( serDesc[], SER_STRING, SER_SIZE);
|
||||
//UTF16LE_PACKED_STATIC_CONST_STRING_DESC( cfgDesc[], CFG_STRING, CFG_SIZE);
|
||||
UTF16LE_PACKED_STATIC_CONST_STRING_DESC( int0Desc[], INT0_STRING, INT0_SIZE);
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
SI_SEGMENT_POINTER(myUsbStringTable_USEnglish[],
|
||||
static const USB_StringDescriptor_TypeDef,
|
||||
const SI_SEG_CODE) =
|
||||
{
|
||||
langDesc,
|
||||
mfrDesc,
|
||||
prodDesc,
|
||||
serDesc,
|
||||
int0Desc,
|
||||
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
SI_SEGMENT_VARIABLE(initstruct,
|
||||
const USBD_Init_TypeDef,
|
||||
SI_SEG_CODE) =
|
||||
{
|
||||
deviceDesc, // deviceDescriptor
|
||||
configDesc,// configDescriptor
|
||||
myUsbStringTable_USEnglish,// stringDescriptors
|
||||
5// numberOfStrings
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
79
targets/efm8/src/eeprom.c
Normal file
79
targets/efm8/src/eeprom.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <SI_EFM8UB1_Register_Enums.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "eeprom.h"
|
||||
#include "printing.h"
|
||||
|
||||
char __erase_mem[3];
|
||||
|
||||
static void erase_ram()
|
||||
{
|
||||
data uint16_t i;
|
||||
data uint8_t xdata * clear = 0;
|
||||
for (i=0; i<0x400;i++)
|
||||
{
|
||||
*(clear++) = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void eeprom_init()
|
||||
{
|
||||
uint8_t secbyte;
|
||||
eeprom_read(0xFBFF,&secbyte,1);
|
||||
if (secbyte == 0xff)
|
||||
{
|
||||
eeprom_erase(0xFBC0);
|
||||
secbyte = -32;
|
||||
eeprom_write(0xFBFF, &secbyte, 1);
|
||||
erase_ram();
|
||||
// Reboot
|
||||
cprints("rebooting\r\n");
|
||||
RSTSRC = (1<<4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cprints("no reboot\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void eeprom_read(uint16_t addr, uint8_t * buf, uint8_t len)
|
||||
{
|
||||
uint8_t code * eepaddr = (uint8_t code *) addr;
|
||||
bit old_int;
|
||||
|
||||
while(len--)
|
||||
{
|
||||
old_int = IE_EA;
|
||||
IE_EA = 0;
|
||||
*buf++ = *eepaddr++;
|
||||
IE_EA = old_int;
|
||||
}
|
||||
}
|
||||
|
||||
void _eeprom_write(uint16_t addr, uint8_t * buf, uint8_t len, uint8_t flags)
|
||||
{
|
||||
uint8_t xdata * data eepaddr = (uint8_t xdata *) addr;
|
||||
bit old_int;
|
||||
|
||||
while(len--)
|
||||
{
|
||||
old_int = IE_EA;
|
||||
IE_EA = 0;
|
||||
// Enable VDD monitor
|
||||
VDM0CN = 0x80;
|
||||
RSTSRC = 0x02;
|
||||
|
||||
// unlock key
|
||||
FLKEY = 0xA5;
|
||||
FLKEY = 0xF1;
|
||||
PSCTL |= flags;
|
||||
|
||||
*eepaddr = *buf;
|
||||
PSCTL &= ~flags;
|
||||
IE_EA = old_int;
|
||||
|
||||
eepaddr++;
|
||||
buf++;
|
||||
}
|
||||
}
|
261
targets/efm8/src/main.c
Normal file
261
targets/efm8/src/main.c
Normal file
@@ -0,0 +1,261 @@
|
||||
#include <SI_EFM8UB1_Register_Enums.h>
|
||||
#include "InitDevice.h"
|
||||
#include "efm8_usb.h"
|
||||
#include "uart_1.h"
|
||||
#include "printing.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
#define BUFFER_SIZE 12
|
||||
|
||||
#ifdef USING_DEVELOPMENT_BOARD
|
||||
#define RW_PIN P2_B3
|
||||
#define BUSY_PIN P1_B2
|
||||
#define MSG_RDY_PIN P1_B1
|
||||
#else
|
||||
#define RW_PIN P0_B1
|
||||
#define BUSY_PIN P0_B2
|
||||
#define MSG_RDY_PIN P0_B3
|
||||
#endif
|
||||
|
||||
#define SIGNAL_WRITE_BSY() BUSY_PIN = 0 // Set P1 low
|
||||
#define SIGNAL_WRITE_RDY() BUSY_PIN = 1 // Set P1 high
|
||||
|
||||
|
||||
|
||||
data uint8_t write_ptr = 0;
|
||||
data uint8_t read_ptr = 0;
|
||||
data uint8_t i_ptr = 0;
|
||||
data uint8_t count = 0;
|
||||
data uint8_t writebackbuf_count = 0;
|
||||
|
||||
uint8_t hidmsgbuf[64*BUFFER_SIZE];
|
||||
//uint8_t debugR[64];
|
||||
//uint8_t debugRi;
|
||||
//uint8_t debugW[64];
|
||||
//uint8_t debugW2[64];
|
||||
//uint8_t debugWi;
|
||||
data uint8_t writebackbuf[64];
|
||||
|
||||
void usb_transfer_complete()
|
||||
{
|
||||
count++;
|
||||
// memmove(debugR, hidmsgbuf + write_ptr*64, 64);
|
||||
// debugRi = write_ptr;
|
||||
write_ptr++;
|
||||
|
||||
if (write_ptr == BUFFER_SIZE)
|
||||
{
|
||||
write_ptr = 0;
|
||||
}
|
||||
|
||||
|
||||
// MSG_RDY_INT_PIN = 0;
|
||||
// MSG_RDY_INT_PIN = 1;
|
||||
|
||||
}
|
||||
|
||||
uint16_t USB_TX_COUNT = 0;
|
||||
|
||||
void usb_writeback_complete()
|
||||
{
|
||||
// if (USB_TX_COUNT >= 511/2)
|
||||
// {
|
||||
// USB_TX_COUNT -= 64;
|
||||
// if (USB_TX_COUNT < 511)
|
||||
// {
|
||||
// SIGNAL_WRITE_RDY();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// USB_TX_COUNT -= 64;
|
||||
// }
|
||||
USB_TX_COUNT -= 64;
|
||||
}
|
||||
|
||||
void spi_transfer_complete()
|
||||
{
|
||||
|
||||
if (count > 0) count--;
|
||||
i_ptr = 0;
|
||||
read_ptr++;
|
||||
if (read_ptr == BUFFER_SIZE)
|
||||
{
|
||||
read_ptr = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void usb_write()
|
||||
{
|
||||
data uint8_t errors = 0;
|
||||
USB_TX_COUNT += 64;
|
||||
while (USB_STATUS_OK != (USBD_Write(OUTPUT_ENDPOINT, writebackbuf, 64, true)))
|
||||
{
|
||||
delay(2);
|
||||
if (errors++ > 30)
|
||||
{
|
||||
cprints("ERROR USB WRITE\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
extern USBD_Device_TypeDef myUsbDevice;
|
||||
|
||||
int main(void) {
|
||||
data uint8_t k;
|
||||
data uint16_t last_efm32_pin = 0;
|
||||
uint16_t t1 = 0;
|
||||
uint8_t lastcount = count;
|
||||
|
||||
int reset;
|
||||
data int lastwritecount = writebackbuf_count;
|
||||
|
||||
enter_DefaultMode_from_RESET();
|
||||
|
||||
|
||||
eeprom_init();
|
||||
|
||||
|
||||
SCON0_TI = 1;
|
||||
// P2_B0 = 1;
|
||||
|
||||
MSG_RDY_PIN = 1;
|
||||
|
||||
// enable SPI interrupts
|
||||
// SPI0FCN1 = SPI0FCN1 | (1<<4);
|
||||
IE_EA = 1;
|
||||
// IE_ESPI0 = 1;
|
||||
|
||||
SPI0FCN0 = SPI0FCN0 | (1<<2); // flush RX fifo
|
||||
SPI0FCN0 = SPI0FCN0 | (1<<6); // flush TX fifo
|
||||
// SPI0FCN0 &= ~3; // FIFO threshold 0x0
|
||||
SPI0FCN1 |= (1); // Enable RX fifo
|
||||
|
||||
// cprints("hello,world\r\n");
|
||||
|
||||
|
||||
reset = RSTSRC;
|
||||
cprintx("reset source: ", 1, reset);
|
||||
if (reset != 0x10)
|
||||
{
|
||||
RSTSRC = (1<<4);
|
||||
}
|
||||
|
||||
MSG_RDY_PIN = 1;
|
||||
SIGNAL_WRITE_BSY();
|
||||
|
||||
while (1) {
|
||||
|
||||
if (RW_PIN == 0)
|
||||
{
|
||||
i_ptr = 0;
|
||||
SPI0FCN0 |= (1<<6); // Flush TX fifo buffer
|
||||
|
||||
while (SPI0CN0 & (1 << 1)) // While TX FIFO has room
|
||||
SPI0DAT = (hidmsgbuf+read_ptr*64)[i_ptr++];
|
||||
|
||||
SIGNAL_WRITE_RDY();
|
||||
while (i_ptr<64)
|
||||
{
|
||||
while(! (SPI0CN0 & (1 << 1)))
|
||||
;
|
||||
SPI0DAT = (hidmsgbuf+read_ptr*64)[i_ptr++];
|
||||
}
|
||||
|
||||
while(RW_PIN == 0)
|
||||
{
|
||||
}
|
||||
|
||||
// cprints(">> ");
|
||||
// dump_hex(hidmsgbuf+read_ptr*64,64);
|
||||
spi_transfer_complete();
|
||||
if (count == 0)
|
||||
{
|
||||
MSG_RDY_PIN = 1;
|
||||
}
|
||||
|
||||
SPI0FCN0 = SPI0FCN0 | (1<<2); // flush RX fifo
|
||||
|
||||
while ((SPI0CFG & (0x1)) == 0)
|
||||
{
|
||||
k = SPI0DAT;
|
||||
}
|
||||
|
||||
SIGNAL_WRITE_BSY();
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Did we RX data and have room?
|
||||
if ((SPI0CFG & (0x1)) == 0 && USB_TX_COUNT < 511/2)
|
||||
{
|
||||
|
||||
writebackbuf[writebackbuf_count++] = SPI0DAT;
|
||||
SIGNAL_WRITE_RDY();
|
||||
|
||||
while(writebackbuf_count < 64)
|
||||
{
|
||||
while((SPI0CFG & (0x1)) == 1)
|
||||
;
|
||||
writebackbuf[writebackbuf_count++] = SPI0DAT;
|
||||
}
|
||||
|
||||
// cprints("<< ");
|
||||
// dump_hex(writebackbuf,64);
|
||||
|
||||
usb_write();
|
||||
writebackbuf_count = 0;
|
||||
SPI0FCN0 = SPI0FCN0 | (1<<2); // flush RX fifo
|
||||
|
||||
SIGNAL_WRITE_BSY();
|
||||
}
|
||||
}
|
||||
|
||||
if (millis() - t1 > 1500)
|
||||
{
|
||||
#ifdef USING_DEVELOPMENT_BOARD
|
||||
P1_B5 = k++&1;
|
||||
#endif
|
||||
t1 = millis();
|
||||
}
|
||||
// if (!USBD_EpIsBusy(EP2OUT) && !USBD_EpIsBusy(EP3IN) && lastcount==count)
|
||||
if (!USBD_EpIsBusy(INPUT_ENDPOINT) && lastcount==count)
|
||||
// if (lastcount==count)
|
||||
{
|
||||
// cprintd("sched read to ",1,(int)(hidmsgbuf + write_ptr*64));
|
||||
if (count == BUFFER_SIZE)
|
||||
{
|
||||
// cprints("Warning, USB buffer full\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// cprints("sched read\r\n");
|
||||
USBD_Read(INPUT_ENDPOINT, hidmsgbuf + write_ptr*64, 64, true);
|
||||
}
|
||||
}
|
||||
|
||||
// cprints("it\r\n");
|
||||
|
||||
if (lastcount != count)
|
||||
{
|
||||
if (count > lastcount)
|
||||
{
|
||||
// cputd(debugRi); cprints(">> ");
|
||||
// dump_hex(debugR,64);
|
||||
MSG_RDY_PIN = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// cputd(debugWi); cprints(">>>> ");
|
||||
// dump_hex(debugW,64);
|
||||
// dump_hex(debugW2,64);
|
||||
}
|
||||
lastcount = count;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
186
targets/efm8/src/printing.c
Normal file
186
targets/efm8/src/printing.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* printing.c
|
||||
*
|
||||
* Created on: Jun 25, 2018
|
||||
* Author: conor
|
||||
*/
|
||||
|
||||
#include <SI_EFM8UB1_Register_Enums.h>
|
||||
#include <efm8_usb.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "printing.h"
|
||||
|
||||
void delay(uint16_t ms)
|
||||
{
|
||||
uint16_t m1 = millis();
|
||||
while (millis() - m1 < ms)
|
||||
;
|
||||
}
|
||||
#ifdef USE_PRINTING
|
||||
void putf(char c)
|
||||
{
|
||||
uint8_t i;
|
||||
SBUF0 = c;
|
||||
// Blocking delay that works for 115200 baud on this device (<1ms)
|
||||
for (i=0; i<200; i++){}
|
||||
for (i=0; i<200; i++){}
|
||||
for (i=0; i<190; i++){}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void dump_hex(uint8_t* hex, uint8_t len)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t b;
|
||||
const char lut[] = "0123456789abcdef";
|
||||
for (i=0 ; i < len ; i++)
|
||||
{
|
||||
b = ((*hex) & 0xf0)>>4;
|
||||
putf(lut[b]);
|
||||
b = ((*hex) & 0x0f);
|
||||
putf(lut[b]);
|
||||
putf(' ');
|
||||
hex++;
|
||||
}
|
||||
cprints("\r\n");
|
||||
}
|
||||
|
||||
|
||||
void cprints(char* d)
|
||||
{
|
||||
while(*d)
|
||||
{
|
||||
// UART0 output queue
|
||||
putf(*d++);
|
||||
}
|
||||
}
|
||||
|
||||
static void int2str_reduce_n(char ** snum, uint32_t copy, uint8_t n)
|
||||
{
|
||||
do
|
||||
{
|
||||
copy /= n;
|
||||
++*snum;
|
||||
}while(copy);
|
||||
}
|
||||
|
||||
|
||||
static const char * __digits = "0123456789abcdef";
|
||||
static char xdata __int2str_buf[9];
|
||||
|
||||
static void int2str_map_n(char ** snum, uint32_t i, uint8_t n)
|
||||
{
|
||||
int c = 0;
|
||||
do
|
||||
{
|
||||
if (*snum <__int2str_buf) break;
|
||||
*--*snum = __digits[i % n];
|
||||
i /= n;
|
||||
}while(i);
|
||||
}
|
||||
|
||||
#define dint2str(i) __int2strn(i,10)
|
||||
#define xint2str(i) __int2strn(i,16)
|
||||
|
||||
char * __int2strn(int32_t i, uint8_t n)
|
||||
{
|
||||
char * snum = __int2str_buf;
|
||||
if (i<0) *snum++ = '-';
|
||||
int2str_reduce_n(&snum, i, n);
|
||||
*snum = '\0';
|
||||
int2str_map_n(&snum, i, n);
|
||||
return snum;
|
||||
}
|
||||
|
||||
void cputd(int32_t i)
|
||||
{
|
||||
cprints(dint2str((int32_t)i));
|
||||
}
|
||||
|
||||
void cputx(int32_t i)
|
||||
{
|
||||
cprints(xint2str(i));
|
||||
}
|
||||
|
||||
static void put_space()
|
||||
{
|
||||
cprints(" ");
|
||||
}
|
||||
static void put_line()
|
||||
{
|
||||
cprints("\r\n");
|
||||
}
|
||||
|
||||
void cprintd(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
cprints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
cputd((int32_t)va_arg(args, int16_t));
|
||||
|
||||
}
|
||||
put_line();
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void cprintl(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
cprints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
cputl(va_arg(args, int32_t));
|
||||
cprints(" ");
|
||||
}
|
||||
put_line();
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void cprintx(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
cprints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
cputx((int32_t)va_arg(args, uint16_t));
|
||||
cprints(" ");
|
||||
}
|
||||
put_line();
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void cprintb(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
cprints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
cputb(va_arg(args, uint8_t));
|
||||
put_space();
|
||||
}
|
||||
put_line();
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void cprintlx(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
cprints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
cputlx(va_arg(args, int32_t));
|
||||
put_space();
|
||||
}
|
||||
put_line();
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user