forked from auracaster/openocd
contrib/firmware: add new adapter ANGIE's firmware/bitstream code
This is ANGIE's firmware and bitstream code. The 'Embeded C' code is based on the openULINK project. The hdl bitstream source code is for the spartan-6 FPGA included in ANGIE. Since ANGIE has a different microcontroller (EZ-USB FX2) than openULINK (EZ-USB AN2131), the registers file (reg_ezusb.h) has been changed completely, so are the descriptors, interruptions and the endpoints configuration. Change-Id: I70590c7c58bac6f1939c5ffba57e87d86850664d Signed-off-by: Ahmed BOUDJELIDA <aboudjelida@nanoxplore.com> Reviewed-on: https://review.openocd.org/c/openocd/+/7701 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
committed by
Antonio Borneo
parent
3b78b5c1db
commit
9c91ce8d24
125
contrib/firmware/angie/c/src/USBJmpTb.a51
Normal file
125
contrib/firmware/angie/c/src/USBJmpTb.a51
Normal file
@@ -0,0 +1,125 @@
|
||||
; SPDX-License-Identifier: GPL-2.0-or-later
|
||||
;****************************************************************************
|
||||
; File : USBJmpTb.a51 *
|
||||
; Contents : Interruptions vector configuration. *
|
||||
; Based on openULINK project code by: Martin Schmoelzer. *
|
||||
; Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
|
||||
; <aboudjelida@nanoxplore.com> *
|
||||
; <ahmederrachedbjld@gmail.com> *
|
||||
;****************************************************************************
|
||||
.module JUMPTABLE
|
||||
|
||||
.globl USB_AutoVector
|
||||
.globl USB_Jump_Table
|
||||
|
||||
.globl _sudav_isr, _sof_isr, _sutok_isr, _suspend_isr, _usbreset_isr, _highspeed_isr, _ep0ack_isr, _stub_isr, _ep0in_isr, _ep0out_isr, _ep1in_isr, _ep1out_isr, _ep2_isr, _ep4_isr, _ep6_isr, _ep8_isr, _ibn_isr
|
||||
.globl _ep0pingnak_isr, _ep1pingnak_isr, _ep2pingnak_isr, _ep4pingnak_isr, _ep6pingnak_isr, _ep8pingnak_isr, _errorlimit_isr, _stub_isr, _stub_isr, _stub_isr, _ep2piderror_isr, _ep4piderror_isr, _ep6piderror_isr, _ep8piderror_isr
|
||||
.globl _ep2pflag_isr, _ep4pflag_isr, _ep6pflag_isr, _ep8pflag_isr, _ep2eflag_isr, _ep4eflag_isr, _ep6eflag_isr, _ep8eflag_isr, _ep2fflag_isr, _ep4fflag_isr, _ep6fflag_isr, _ep8fflag_isr, _gpifcomplete_isr, _gpifwaveform_isr
|
||||
|
||||
;--------------------------------------------------------------------------;
|
||||
; Interrupt Vectors ;
|
||||
;--------------------------------------------------------------------------;
|
||||
.area USB_JV (ABS,OVR) ; Absolute, Overlay
|
||||
.org 0x43 ; USB interrupt (INT2) jumps here
|
||||
USB_AutoVector = #. + 2
|
||||
ljmp USB_Jump_Table ; Autovector will replace byte 45
|
||||
|
||||
;--------------------------------------------------------------------------;
|
||||
; USB Jump Table ;
|
||||
;--------------------------------------------------------------------------;
|
||||
.area USB_JT (ABS) ; Absolute placement
|
||||
.org 0x0200 ; Place jump table at 0x0200
|
||||
|
||||
USB_Jump_Table: ; autovector jump table
|
||||
ljmp _sudav_isr ; (00) Setup Data Available
|
||||
.db 0
|
||||
ljmp _sof_isr ; (04) Start of Frame
|
||||
.db 0
|
||||
ljmp _sutok_isr ; (08) Setup Data Loading
|
||||
.db 0
|
||||
ljmp _suspend_isr ; (0C) Global Suspend
|
||||
.db 0
|
||||
ljmp _usbreset_isr ; (10) USB Reset
|
||||
.db 0
|
||||
ljmp _highspeed_isr ; (14) Entered High Speed
|
||||
.db 0
|
||||
ljmp _ep0ack_isr ; (18) EP0ACK
|
||||
.db 0
|
||||
ljmp _stub_isr ; (1C) Reserved
|
||||
.db 0
|
||||
ljmp _ep0in_isr ; (20) EP0 In
|
||||
.db 0
|
||||
ljmp _ep0out_isr ; (24) EP0 Out
|
||||
.db 0
|
||||
ljmp _ep1in_isr ; (28) EP1 In
|
||||
.db 0
|
||||
ljmp _ep1out_isr ; (2C) EP1 Out
|
||||
.db 0
|
||||
ljmp _ep2_isr ; (30) EP2 In/Out
|
||||
.db 0
|
||||
ljmp _ep4_isr ; (34) EP4 In/Out
|
||||
.db 0
|
||||
ljmp _ep6_isr ; (38) EP6 In/Out
|
||||
.db 0
|
||||
ljmp _ep8_isr ; (3C) EP8 In/Out
|
||||
.db 0
|
||||
ljmp _ibn_isr ; (40) IBN
|
||||
.db 0
|
||||
ljmp _stub_isr ; (44) Reserved
|
||||
.db 0
|
||||
ljmp _ep0pingnak_isr ; (48) EP0 PING NAK
|
||||
.db 0
|
||||
ljmp _ep1pingnak_isr ; (4C) EP1 PING NAK
|
||||
.db 0
|
||||
ljmp _ep2pingnak_isr ; (50) EP2 PING NAK
|
||||
.db 0
|
||||
ljmp _ep4pingnak_isr ; (54) EP4 PING NAK
|
||||
.db 0
|
||||
ljmp _ep6pingnak_isr ; (58) EP6 PING NAK
|
||||
.db 0
|
||||
ljmp _ep8pingnak_isr ; (5C) EP8 PING NAK
|
||||
.db 0
|
||||
ljmp _errorlimit_isr ; (60) Error Limit
|
||||
.db 0
|
||||
ljmp _stub_isr ; (64) Reserved
|
||||
.db 0
|
||||
ljmp _stub_isr ; (68) Reserved
|
||||
.db 0
|
||||
ljmp _stub_isr ; (6C) Reserved
|
||||
.db 0
|
||||
ljmp _ep2piderror_isr ; (70) EP2 ISO Pid Sequence Error
|
||||
.db 0
|
||||
ljmp _ep4piderror_isr ; (74) EP4 ISO Pid Sequence Error
|
||||
.db 0
|
||||
ljmp _ep6piderror_isr ; (78) EP6 ISO Pid Sequence Error
|
||||
.db 0
|
||||
ljmp _ep8piderror_isr ; (7C) EP8 ISO Pid Sequence Error
|
||||
.db 0
|
||||
ljmp _ep2pflag_isr ; (80) EP2 Programmable Flag
|
||||
.db 0
|
||||
ljmp _ep4pflag_isr ; (84) EP4 Programmable Flag
|
||||
.db 0
|
||||
ljmp _ep6pflag_isr ; (88) EP6 Programmable Flag
|
||||
.db 0
|
||||
ljmp _ep8pflag_isr ; (8C) EP8 Programmable Flag
|
||||
.db 0
|
||||
ljmp _ep2eflag_isr ; (90) EP2 Empty Flag
|
||||
.db 0
|
||||
ljmp _ep4eflag_isr ; (94) EP4 Empty Flag
|
||||
.db 0
|
||||
ljmp _ep6eflag_isr ; (98) EP6 Empty Flag
|
||||
.db 0
|
||||
ljmp _ep8eflag_isr ; (9C) EP8 Empty Flag
|
||||
.db 0
|
||||
ljmp _ep2fflag_isr ; (A0) EP2 Full Flag
|
||||
.db 0
|
||||
ljmp _ep4fflag_isr ; (A4) EP4 Full Flag
|
||||
.db 0
|
||||
ljmp _ep6fflag_isr ; (A8) EP6 Full Flag
|
||||
.db 0
|
||||
ljmp _ep8fflag_isr ; (AC) EP8 Full Flag
|
||||
.db 0
|
||||
ljmp _gpifcomplete_isr ; (B0) GPIF Operation Complete
|
||||
.db 0
|
||||
ljmp _gpifwaveform_isr ; (B4) GPIF Waveform
|
||||
.db 0
|
||||
49
contrib/firmware/angie/c/src/delay.c
Normal file
49
contrib/firmware/angie/c/src/delay.c
Normal file
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/****************************************************************************
|
||||
File : delay.c *
|
||||
Contents : Delays handling fucntions code for NanoXplore *
|
||||
USB-JTAG ANGIE adapter hardware. *
|
||||
Based on openULINK project code by: Martin Schmoelzer. *
|
||||
Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
|
||||
<aboudjelida@nanoxplore.com> *
|
||||
<ahmederrachedbjld@gmail.com> *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "delay.h"
|
||||
#include <mcs51/compiler.h>
|
||||
|
||||
void syncdelay(uint8_t count)
|
||||
{
|
||||
for (uint8_t i = 0; i < count; i++)
|
||||
NOP();
|
||||
}
|
||||
|
||||
void delay_5us(void)
|
||||
{
|
||||
NOP();
|
||||
}
|
||||
|
||||
void delay_1ms(void)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < 598; i++)
|
||||
;
|
||||
}
|
||||
|
||||
void delay_us(uint16_t delay)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t maxcount = (delay / 5);
|
||||
|
||||
for (i = 0; i < maxcount; i++)
|
||||
delay_5us();
|
||||
}
|
||||
|
||||
void delay_ms(uint16_t delay)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < delay; i++)
|
||||
delay_1ms();
|
||||
}
|
||||
98
contrib/firmware/angie/c/src/gpif.c
Normal file
98
contrib/firmware/angie/c/src/gpif.c
Normal file
@@ -0,0 +1,98 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/*
|
||||
This program configures the General Programmable Interface (GPIF) for FX2.
|
||||
Please do not modify sections of text which are marked as "DO NOT EDIT ...".
|
||||
*/
|
||||
|
||||
/* GPIF Program Code */
|
||||
|
||||
#include "reg_ezusb.h"
|
||||
#include "delay.h"
|
||||
|
||||
/****************************** GPIF PROGRAM CODE ********************************/
|
||||
/* DO NOT EDIT ... */
|
||||
const char wavedata[128] = {
|
||||
/* Wave 0 */
|
||||
/* LenBr */ 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07,
|
||||
/* Opcode*/ 0x02, 0x07, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00,
|
||||
/* Output*/ 0x04, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
/* LFun */ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
/* Wave 1 */
|
||||
/* LenBr */ 0x88, 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x07,
|
||||
/* Opcode*/ 0x01, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* Output*/ 0x07, 0x05, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
/* LFun */ 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
/* Wave 2 */
|
||||
/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07,
|
||||
/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* Output*/ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
/* Wave 3 */
|
||||
/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07,
|
||||
/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* Output*/ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
};
|
||||
/* END DO NOT EDIT */
|
||||
|
||||
/* DO NOT EDIT ... */
|
||||
const char flowstates[36] = {
|
||||
/* Wave 0 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* Wave 1 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* Wave 2 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* Wave 3 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
/* END DO NOT EDIT */
|
||||
|
||||
/* DO NOT EDIT ... */
|
||||
const char initdata[7] = {
|
||||
/* Regs */ 0xE0, 0x00, 0x00, 0x07, 0xEE, 0xF2, 0x00
|
||||
};
|
||||
/* END DO NOT EDIT */
|
||||
|
||||
void gpif_init(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
IFCONFIG = 0xEE;
|
||||
|
||||
GPIFABORT = 0xFF; /* abort any waveforms pending */
|
||||
GPIFREADYCFG = initdata[0];
|
||||
GPIFCTLCFG = initdata[1];
|
||||
GPIFIDLECS = initdata[2];
|
||||
GPIFIDLECTL = initdata[3];
|
||||
GPIFWFSELECT = initdata[5];
|
||||
GPIFREADYSTAT = initdata[6];
|
||||
|
||||
/* use dual autopointer feature... */
|
||||
AUTOPTRSETUP = 0x07;
|
||||
|
||||
/* source */
|
||||
AUTOPTRH1 = (uint8_t)(((uint16_t)(&wavedata) >> 8) & 0xff);
|
||||
AUTOPTRL1 = (uint8_t)((uint16_t)(&wavedata) & 0xff);
|
||||
|
||||
/* destination */
|
||||
AUTOPTRH2 = 0xE4;
|
||||
AUTOPTRL2 = 0x00;
|
||||
|
||||
/* transfer */
|
||||
for (i = 0x00; i < 128; i++)
|
||||
EXTAUTODAT2 = EXTAUTODAT1;
|
||||
|
||||
/* GPIF address pins update when GPIFADRH/L written */
|
||||
syncdelay(3);
|
||||
GPIFADRH = 0x00; /* bits[7:1] always 0 */
|
||||
syncdelay(3);
|
||||
GPIFADRL = 0x00; /* point to PERIPHERAL address 0x0000 */
|
||||
|
||||
/* Configure GPIF flowstates registers for Wave 0 of wavedata */
|
||||
FLOWSTATE = flowstates[0];
|
||||
FLOWLOGIC = flowstates[1];
|
||||
FLOWEQ0CTL = flowstates[2];
|
||||
FLOWEQ1CTL = flowstates[3];
|
||||
FLOWHOLDOFF = flowstates[4];
|
||||
FLOWSTB = flowstates[5];
|
||||
FLOWSTBEDGE = flowstates[6];
|
||||
FLOWSTBHPERIOD = flowstates[7];
|
||||
}
|
||||
674
contrib/firmware/angie/c/src/jtag.c
Normal file
674
contrib/firmware/angie/c/src/jtag.c
Normal file
@@ -0,0 +1,674 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/****************************************************************************
|
||||
File : jtag.c *
|
||||
Contents : Jtag handling functions code for NanoXplore *
|
||||
USB-JTAG ANGIE adapter hardware. *
|
||||
Based on openULINK project code by: Martin Schmoelzer. *
|
||||
Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
|
||||
<aboudjelida@nanoxplore.com> *
|
||||
<ahmederrachedbjld@gmail.com> *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "jtag.h"
|
||||
#include "io.h"
|
||||
#include "msgtypes.h"
|
||||
#include "reg_ezusb.h"
|
||||
#include <stdbool.h>
|
||||
#include <serial.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/** Delay value for SCAN_IN operations with less than maximum TCK frequency */
|
||||
uint8_t delay_scan_in;
|
||||
|
||||
/** Delay value for SCAN_OUT operations with less than maximum TCK frequency */
|
||||
uint8_t delay_scan_out;
|
||||
|
||||
/** Delay value for SCAN_IO operations with less than maximum TCK frequency */
|
||||
uint8_t delay_scan_io;
|
||||
|
||||
/** Delay value for CLOCK_TCK operations with less than maximum frequency */
|
||||
uint8_t delay_tck;
|
||||
|
||||
/** Delay value for CLOCK_TMS operations with less than maximum frequency */
|
||||
uint8_t delay_tms;
|
||||
|
||||
/**
|
||||
* Perform JTAG SCAN-IN operation at maximum TCK frequency.
|
||||
*
|
||||
* Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and
|
||||
* stored in the EP2 IN buffer.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 182 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param out_offset offset in EP1OUTBUF where payload data starts
|
||||
* @param in_offset
|
||||
*/
|
||||
void jtag_scan_in(uint8_t out_offset, uint8_t in_offset)
|
||||
{
|
||||
uint8_t scan_size_bytes, bits_last_byte;
|
||||
uint8_t tms_count_start, tms_count_end;
|
||||
uint8_t tms_sequence_start, tms_sequence_end;
|
||||
uint8_t tdo_data, i, j;
|
||||
|
||||
uint8_t outb_buffer;
|
||||
|
||||
/* Get parameters from EP1OUTBUF */
|
||||
scan_size_bytes = EP1OUTBUF[out_offset];
|
||||
bits_last_byte = EP1OUTBUF[out_offset + 1];
|
||||
tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
|
||||
tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
|
||||
tms_sequence_start = EP1OUTBUF[out_offset + 3];
|
||||
tms_sequence_end = EP1OUTBUF[out_offset + 4];
|
||||
|
||||
if (tms_count_start > 0)
|
||||
jtag_clock_tms(tms_count_start, tms_sequence_start);
|
||||
|
||||
outb_buffer = IOB & ~(bmbit1 | bmbit2 | bmbit3);
|
||||
|
||||
/* Shift all bytes except the last byte */
|
||||
for (i = 0; i < scan_size_bytes - 1; i++) {
|
||||
tdo_data = 0;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
IOB = outb_buffer; /* TCK changes here */
|
||||
tdo_data = tdo_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
|
||||
if (PIN_TDO)
|
||||
tdo_data |= 0x80;
|
||||
}
|
||||
|
||||
/* Copy TDO data to EP1INBUF */
|
||||
EP1INBUF[i + in_offset] = tdo_data;
|
||||
}
|
||||
tdo_data = 0;
|
||||
|
||||
/* Shift the last byte */
|
||||
for (j = 0; j < bits_last_byte; j++) {
|
||||
/* Assert TMS signal if requested and this is the last bit */
|
||||
if (j == (bits_last_byte - 1) && tms_count_end > 0) {
|
||||
outb_buffer |= bmbit1;
|
||||
tms_count_end--;
|
||||
tms_sequence_end = tms_sequence_end >> 1;
|
||||
}
|
||||
|
||||
IOB = outb_buffer; /* TCK changes here */
|
||||
tdo_data = tdo_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
|
||||
if (PIN_TDO)
|
||||
tdo_data |= 0x80;
|
||||
}
|
||||
tdo_data = tdo_data >> (8 - bits_last_byte);
|
||||
|
||||
/* Copy TDO data to EP1INBUF */
|
||||
EP1INBUF[i + in_offset] = tdo_data;
|
||||
|
||||
/* Move to correct end state */
|
||||
if (tms_count_end > 0)
|
||||
jtag_clock_tms(tms_count_end, tms_sequence_end);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform JTAG SCAN-IN operation at variable TCK frequency.
|
||||
*
|
||||
* Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and
|
||||
* stored in the EP2 IN buffer.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 113 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param out_offset offset in EP1OUTBUF where payload data starts
|
||||
* @param in_offset
|
||||
*/
|
||||
void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset)
|
||||
{
|
||||
uint8_t scan_size_bytes, bits_last_byte;
|
||||
uint8_t tms_count_start, tms_count_end;
|
||||
uint8_t tms_sequence_start, tms_sequence_end;
|
||||
uint8_t tdo_data, i, j, k;
|
||||
uint8_t outb_buffer;
|
||||
|
||||
/* Get parameters from EP1OUTBUF */
|
||||
scan_size_bytes = EP1OUTBUF[out_offset];
|
||||
bits_last_byte = EP1OUTBUF[out_offset + 1];
|
||||
tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
|
||||
tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
|
||||
tms_sequence_start = EP1OUTBUF[out_offset + 3];
|
||||
tms_sequence_end = EP1OUTBUF[out_offset + 4];
|
||||
|
||||
if (tms_count_start > 0)
|
||||
jtag_slow_clock_tms(tms_count_start, tms_sequence_start);
|
||||
|
||||
outb_buffer = IOB & ~(bmbit3 | bmbit2 | bmbit1);
|
||||
|
||||
/* Shift all bytes except the last byte */
|
||||
for (i = 0; i < scan_size_bytes - 1; i++) {
|
||||
tdo_data = 0;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
IOB = outb_buffer; /* TCK changes here */
|
||||
for (k = 0; k < delay_scan_in; k++)
|
||||
;
|
||||
tdo_data = tdo_data >> 1;
|
||||
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
for (k = 0; k < delay_scan_in; k++)
|
||||
;
|
||||
|
||||
if (PIN_TDO)
|
||||
tdo_data |= 0x80;
|
||||
}
|
||||
|
||||
/* Copy TDO data to EP1INBUF */
|
||||
EP1INBUF[i + in_offset] = tdo_data;
|
||||
}
|
||||
|
||||
tdo_data = 0;
|
||||
|
||||
/* Shift the last byte */
|
||||
for (j = 0; j < bits_last_byte; j++) {
|
||||
/* Assert TMS signal if requested and this is the last bit */
|
||||
if (j == (bits_last_byte - 1) && tms_count_end > 0) {
|
||||
outb_buffer |= bmbit1;
|
||||
tms_count_end--;
|
||||
tms_sequence_end = tms_sequence_end >> 1;
|
||||
}
|
||||
|
||||
IOB = outb_buffer; /* TCK changes here */
|
||||
for (k = 0; k < delay_scan_in; k++)
|
||||
;
|
||||
tdo_data = tdo_data >> 1;
|
||||
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
for (k = 0; k < delay_scan_in; k++)
|
||||
;
|
||||
|
||||
if (PIN_TDO)
|
||||
tdo_data |= 0x80;
|
||||
}
|
||||
tdo_data = tdo_data >> (8 - bits_last_byte);
|
||||
|
||||
/* Copy TDO data to EP1INBUF */
|
||||
EP1INBUF[i + in_offset] = tdo_data;
|
||||
|
||||
/* Move to correct end state */
|
||||
if (tms_count_end > 0)
|
||||
jtag_slow_clock_tms(tms_count_end, tms_sequence_end);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform JTAG SCAN-OUT operation at maximum TCK frequency.
|
||||
*
|
||||
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
|
||||
* data is not sampled.
|
||||
* The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 142 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param out_offset offset in EP1OUTBUF where payload data starts
|
||||
*/
|
||||
void jtag_scan_out(uint8_t out_offset)
|
||||
{
|
||||
uint8_t scan_size_bytes, bits_last_byte;
|
||||
uint8_t tms_count_start, tms_count_end;
|
||||
uint8_t tms_sequence_start, tms_sequence_end;
|
||||
uint8_t tdi_data, i, j;
|
||||
uint8_t outb_buffer;
|
||||
|
||||
/* Get parameters from EP1OUTBUF */
|
||||
scan_size_bytes = EP1OUTBUF[out_offset];
|
||||
bits_last_byte = EP1OUTBUF[out_offset + 1];
|
||||
tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
|
||||
tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
|
||||
tms_sequence_start = EP1OUTBUF[out_offset + 3];
|
||||
tms_sequence_end = EP1OUTBUF[out_offset + 4];
|
||||
|
||||
if (tms_count_start > 0)
|
||||
jtag_clock_tms(tms_count_start, tms_sequence_start);
|
||||
outb_buffer = IOB & ~(bmbit2 | bmbit1);
|
||||
|
||||
/* Shift all bytes except the last byte */
|
||||
for (i = 0; i < scan_size_bytes - 1; i++) {
|
||||
tdi_data = EP1OUTBUF[i + out_offset + 5];
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (tdi_data & 0x01)
|
||||
outb_buffer |= bmbit3;
|
||||
else
|
||||
outb_buffer &= ~bmbit3;
|
||||
|
||||
IOB = outb_buffer; /* TDI and TCK change here */
|
||||
tdi_data = tdi_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
}
|
||||
}
|
||||
tdi_data = EP1OUTBUF[i + out_offset + 5];
|
||||
|
||||
/* Shift the last byte */
|
||||
for (j = 0; j < bits_last_byte; j++) {
|
||||
if (tdi_data & 0x01)
|
||||
outb_buffer |= bmbit3;
|
||||
else
|
||||
outb_buffer &= ~bmbit3;
|
||||
|
||||
/* Assert TMS signal if requested and this is the last bit */
|
||||
if (j == (bits_last_byte - 1) && tms_count_end > 0) {
|
||||
outb_buffer |= bmbit1;
|
||||
tms_count_end--;
|
||||
tms_sequence_end = tms_sequence_end >> 1;
|
||||
}
|
||||
IOB = outb_buffer; /* TDI and TCK change here */
|
||||
tdi_data = tdi_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
}
|
||||
|
||||
/* Move to correct end state */
|
||||
if (tms_count_end > 0)
|
||||
jtag_clock_tms(tms_count_end, tms_sequence_end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform JTAG SCAN-OUT operation at maximum TCK frequency.
|
||||
*
|
||||
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
|
||||
* data is not sampled.
|
||||
* The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 97 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param out_offset offset in EP1OUTBUF where payload data starts
|
||||
*/
|
||||
void jtag_slow_scan_out(uint8_t out_offset)
|
||||
{
|
||||
uint8_t scan_size_bytes, bits_last_byte;
|
||||
uint8_t tms_count_start, tms_count_end;
|
||||
uint8_t tms_sequence_start, tms_sequence_end;
|
||||
uint8_t tdi_data, i, j, k;
|
||||
uint8_t outb_buffer;
|
||||
|
||||
/* Get parameters from EP1OUTBUF */
|
||||
scan_size_bytes = EP1OUTBUF[out_offset];
|
||||
bits_last_byte = EP1OUTBUF[out_offset + 1];
|
||||
tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
|
||||
tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
|
||||
tms_sequence_start = EP1OUTBUF[out_offset + 3];
|
||||
tms_sequence_end = EP1OUTBUF[out_offset + 4];
|
||||
|
||||
if (tms_count_start > 0)
|
||||
jtag_slow_clock_tms(tms_count_start, tms_sequence_start);
|
||||
outb_buffer = IOB & ~(bmbit2 | bmbit1);
|
||||
|
||||
/* Shift all bytes except the last byte */
|
||||
for (i = 0; i < scan_size_bytes - 1; i++) {
|
||||
tdi_data = EP1OUTBUF[i + out_offset + 5];
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (tdi_data & 0x01)
|
||||
outb_buffer |= bmbit3;
|
||||
else
|
||||
outb_buffer &= ~bmbit3;
|
||||
IOB = outb_buffer; /* TDI and TCK change here */
|
||||
for (k = 0; k < delay_scan_out; k++)
|
||||
;
|
||||
tdi_data = tdi_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
for (k = 0; k < delay_scan_out; k++)
|
||||
;
|
||||
}
|
||||
}
|
||||
tdi_data = EP1OUTBUF[i + out_offset + 5];
|
||||
|
||||
/* Shift the last byte */
|
||||
for (j = 0; j < bits_last_byte; j++) {
|
||||
if (tdi_data & 0x01)
|
||||
outb_buffer |= bmbit3;
|
||||
else
|
||||
outb_buffer &= ~bmbit3;
|
||||
|
||||
/* Assert TMS signal if requested and this is the last bit */
|
||||
if (j == (bits_last_byte - 1) && tms_count_end > 0) {
|
||||
outb_buffer |= bmbit1;
|
||||
tms_count_end--;
|
||||
tms_sequence_end = tms_sequence_end >> 1;
|
||||
}
|
||||
IOB = outb_buffer; /* TDI and TCK change here */
|
||||
for (k = 0; k < delay_scan_out; k++)
|
||||
;
|
||||
tdi_data = tdi_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
for (k = 0; k < delay_scan_out; k++)
|
||||
;
|
||||
}
|
||||
|
||||
/* Move to correct end state */
|
||||
if (tms_count_end > 0)
|
||||
jtag_slow_clock_tms(tms_count_end, tms_sequence_end);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform bidirectional JTAG SCAN operation at maximum TCK frequency.
|
||||
*
|
||||
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
|
||||
* data is sampled and stored in the EP2 IN buffer.
|
||||
* The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 100 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param out_offset offset in EP1OUTBUF where payload data starts
|
||||
* @param in_offset
|
||||
*/
|
||||
int it;
|
||||
void jtag_scan_io(uint8_t out_offset, uint8_t in_offset)
|
||||
{
|
||||
uint8_t scan_size_bytes, bits_last_byte;
|
||||
uint8_t tms_count_start, tms_count_end;
|
||||
uint8_t tms_sequence_start, tms_sequence_end;
|
||||
uint8_t tdi_data, tdo_data, i, j;
|
||||
uint8_t outb_buffer;
|
||||
|
||||
it++;
|
||||
/* Get parameters from EP1OUTBUF */
|
||||
scan_size_bytes = EP1OUTBUF[out_offset];
|
||||
bits_last_byte = EP1OUTBUF[out_offset + 1];
|
||||
tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
|
||||
tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
|
||||
tms_sequence_start = EP1OUTBUF[out_offset + 3];
|
||||
tms_sequence_end = EP1OUTBUF[out_offset + 4];
|
||||
|
||||
if (tms_count_start > 0)
|
||||
jtag_clock_tms(tms_count_start, tms_sequence_start);
|
||||
outb_buffer = IOB & ~(bmbit2 | bmbit1);
|
||||
|
||||
/* Shift all bytes except the last byte */
|
||||
for (i = 0; i < scan_size_bytes - 1; i++) {
|
||||
tdi_data = EP1OUTBUF[i + out_offset + 5];
|
||||
tdo_data = 0;
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (tdi_data & 0x01)
|
||||
outb_buffer |= bmbit3;
|
||||
else
|
||||
outb_buffer &= ~bmbit3;
|
||||
IOB = outb_buffer; /* TDI and TCK change here */
|
||||
tdi_data = tdi_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
tdo_data = tdo_data >> 1;
|
||||
if (PIN_TDO)
|
||||
tdo_data |= 0x80;
|
||||
}
|
||||
|
||||
/* Copy TDO data to EP1INBUF */
|
||||
EP1INBUF[i + in_offset] = tdo_data;
|
||||
}
|
||||
tdi_data = EP1OUTBUF[i + out_offset + 5];
|
||||
tdo_data = 0;
|
||||
|
||||
/* Shift the last byte */
|
||||
for (j = 0; j < bits_last_byte; j++) {
|
||||
if (tdi_data & 0x01)
|
||||
outb_buffer |= bmbit3;
|
||||
else
|
||||
outb_buffer &= ~bmbit3;
|
||||
|
||||
/* Assert TMS signal if requested and this is the last bit */
|
||||
if (j == (bits_last_byte - 1) && tms_count_end > 0) {
|
||||
outb_buffer |= bmbit1;
|
||||
tms_count_end--;
|
||||
tms_sequence_end = tms_sequence_end >> 1;
|
||||
}
|
||||
IOB = outb_buffer; /* TDI and TCK change here */
|
||||
tdi_data = tdi_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
tdo_data = tdo_data >> 1;
|
||||
if (PIN_TDO)
|
||||
tdo_data |= 0x80;
|
||||
}
|
||||
tdo_data = tdo_data >> (8 - bits_last_byte);
|
||||
|
||||
/* Copy TDO data to EP1INBUF */
|
||||
EP1INBUF[i + in_offset] = tdo_data;
|
||||
|
||||
/* Move to correct end state */
|
||||
if (tms_count_end > 0)
|
||||
jtag_clock_tms(tms_count_end, tms_sequence_end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform bidirectional JTAG SCAN operation at maximum TCK frequency.
|
||||
*
|
||||
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
|
||||
* data is sampled and stored in the EP2 IN buffer.
|
||||
* The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 78 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param out_offset offset in EP1OUTBUF where payload data starts
|
||||
* @param in_offset
|
||||
*/
|
||||
void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset)
|
||||
{
|
||||
uint8_t scan_size_bytes, bits_last_byte;
|
||||
uint8_t tms_count_start, tms_count_end;
|
||||
uint8_t tms_sequence_start, tms_sequence_end;
|
||||
uint8_t tdi_data, tdo_data, i, j, k;
|
||||
uint8_t outb_buffer;
|
||||
|
||||
/* Get parameters from EP1OUTBUF */
|
||||
scan_size_bytes = EP1OUTBUF[out_offset];
|
||||
bits_last_byte = EP1OUTBUF[out_offset + 1];
|
||||
tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
|
||||
tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
|
||||
tms_sequence_start = EP1OUTBUF[out_offset + 3];
|
||||
tms_sequence_end = EP1OUTBUF[out_offset + 4];
|
||||
|
||||
if (tms_count_start > 0)
|
||||
jtag_slow_clock_tms(tms_count_start, tms_sequence_start);
|
||||
outb_buffer = IOB & ~(bmbit2 | bmbit1);
|
||||
|
||||
/* Shift all bytes except the last byte */
|
||||
for (i = 0; i < scan_size_bytes - 1; i++) {
|
||||
tdi_data = EP1OUTBUF[i + out_offset + 5];
|
||||
tdo_data = 0;
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (tdi_data & 0x01)
|
||||
outb_buffer |= bmbit3;
|
||||
else
|
||||
outb_buffer &= ~bmbit3;
|
||||
IOB = outb_buffer; /* TDI and TCK change here */
|
||||
for (k = 0; k < delay_scan_io; k++)
|
||||
;
|
||||
tdi_data = tdi_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
for (k = 0; k < delay_scan_io; k++)
|
||||
;
|
||||
tdo_data = tdo_data >> 1;
|
||||
if (PIN_TDO)
|
||||
tdo_data |= 0x80;
|
||||
}
|
||||
|
||||
/* Copy TDO data to EP1INBUF */
|
||||
EP1INBUF[i + in_offset] = tdo_data;
|
||||
}
|
||||
tdi_data = EP1OUTBUF[i + out_offset + 5];
|
||||
tdo_data = 0;
|
||||
|
||||
/* Shift the last byte */
|
||||
for (j = 0; j < bits_last_byte; j++) {
|
||||
if (tdi_data & 0x01)
|
||||
outb_buffer |= bmbit3;
|
||||
else
|
||||
outb_buffer &= ~bmbit3;
|
||||
|
||||
/* Assert TMS signal if requested and this is the last bit */
|
||||
if (j == (bits_last_byte - 1) && tms_count_end > 0) {
|
||||
outb_buffer |= bmbit1;
|
||||
tms_count_end--;
|
||||
tms_sequence_end = tms_sequence_end >> 1;
|
||||
}
|
||||
IOB = outb_buffer; /* TDI and TCK change here */
|
||||
for (k = 0; k < delay_scan_io; k++)
|
||||
;
|
||||
tdi_data = tdi_data >> 1;
|
||||
IOB = (outb_buffer | bmbit2);
|
||||
for (k = 0; k < delay_scan_io; k++)
|
||||
;
|
||||
tdo_data = tdo_data >> 1;
|
||||
if (PIN_TDO)
|
||||
tdo_data |= 0x80;
|
||||
}
|
||||
tdo_data = tdo_data >> (8 - bits_last_byte);
|
||||
|
||||
/* Copy TDO data to EP1INBUF */
|
||||
EP1INBUF[i + in_offset] = tdo_data;
|
||||
|
||||
/* Move to correct end state */
|
||||
if (tms_count_end > 0)
|
||||
jtag_slow_clock_tms(tms_count_end, tms_sequence_end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate TCK clock cycles.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 375 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param count number of TCK clock cycles to generate.
|
||||
*/
|
||||
void jtag_clock_tck(uint16_t count)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t outb_buffer = IOB & ~(bmbit2);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
IOB = outb_buffer;
|
||||
IOB = outb_buffer | bmbit2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate TCK clock cycles at variable frequency.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 166.6 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param count number of TCK clock cycles to generate.
|
||||
*/
|
||||
void jtag_slow_clock_tck(uint16_t count)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t j;
|
||||
uint8_t outb_buffer = IOB & ~(bmbit2);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
IOB = outb_buffer;
|
||||
for (j = 0; j < delay_tck; j++)
|
||||
;
|
||||
IOB = outb_buffer | bmbit2;
|
||||
for (j = 0; j < delay_tck; j++)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform TAP FSM state transitions at maximum TCK frequency.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 176 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param count the number of state transitions to perform.
|
||||
* @param sequence the TMS pin levels for each state transition, starting with
|
||||
* the least-significant bit.
|
||||
*/
|
||||
void jtag_clock_tms(uint8_t count, uint8_t sequence)
|
||||
{
|
||||
uint8_t outb_buffer = IOB & ~(bmbit2);
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Set TMS pin according to sequence parameter */
|
||||
if (sequence & 0x1)
|
||||
outb_buffer |= bmbit1;
|
||||
else
|
||||
outb_buffer &= ~bmbit1;
|
||||
IOB = outb_buffer;
|
||||
sequence = sequence >> 1;
|
||||
IOB = outb_buffer | bmbit2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform TAP-FSM state transitions at less than maximum TCK frequency.
|
||||
*
|
||||
* Maximum achievable TCK frequency is 117 kHz for ANGIE clocked at 24 MHz.
|
||||
*
|
||||
* @param count the number of state transitions to perform.
|
||||
* @param sequence the TMS pin levels for each state transition, starting with
|
||||
* the least-significant bit.
|
||||
*/
|
||||
void jtag_slow_clock_tms(uint8_t count, uint8_t sequence)
|
||||
{
|
||||
uint8_t outb_buffer = IOB & ~(bmbit2);
|
||||
uint8_t i, j;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Set TMS pin according to sequence parameter */
|
||||
if (sequence & 0x1)
|
||||
outb_buffer |= bmbit1;
|
||||
else
|
||||
outb_buffer &= ~bmbit1;
|
||||
IOB = outb_buffer;
|
||||
for (j = 0; j < delay_tms; j++)
|
||||
;
|
||||
sequence = sequence >> 1;
|
||||
IOB = outb_buffer | bmbit2;
|
||||
for (j = 0; j < delay_tms; j++)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t jtag_get_signals(void)
|
||||
{
|
||||
uint8_t input_signal_state, output_signal_state;
|
||||
input_signal_state = 0;
|
||||
output_signal_state = 0;
|
||||
|
||||
/* Get states of input pins */
|
||||
if (PIN_TDO)
|
||||
input_signal_state |= SIGNAL_TDO;
|
||||
|
||||
/* Get states of output pins */
|
||||
output_signal_state = IOB & MASK_PORTB_DIRECTION_OUT;
|
||||
|
||||
return ((uint16_t)input_signal_state << 8) | ((uint16_t)output_signal_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set state of JTAG output signals.
|
||||
*
|
||||
* @param low signals which should be de-asserted.
|
||||
* @param high signals which should be asserted.
|
||||
*/
|
||||
void jtag_set_signals(uint8_t low, uint8_t high)
|
||||
{
|
||||
IOB &= ~(low & MASK_PORTB_DIRECTION_OUT);
|
||||
IOB |= (high & MASK_PORTB_DIRECTION_OUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure TCK delay parameters.
|
||||
*
|
||||
* @param scan_in number of delay cycles in scan_in operations.
|
||||
* @param scan_out number of delay cycles in scan_out operations.
|
||||
* @param scan_io number of delay cycles in scan_io operations.
|
||||
* @param tck number of delay cycles in clock_tck operations.
|
||||
* @param tms number of delay cycles in clock_tms operations.
|
||||
*/
|
||||
void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out,
|
||||
uint8_t scan_io, uint8_t tck, uint8_t tms)
|
||||
{
|
||||
delay_scan_in = scan_in;
|
||||
delay_scan_out = scan_out;
|
||||
delay_scan_io = scan_io;
|
||||
delay_tck = tck;
|
||||
delay_tms = tms;
|
||||
}
|
||||
85
contrib/firmware/angie/c/src/main.c
Normal file
85
contrib/firmware/angie/c/src/main.c
Normal file
@@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/****************************************************************************
|
||||
File : main.c *
|
||||
Contents : main code for NanoXplore USB-JTAG ANGIE adapter *
|
||||
hardware. *
|
||||
Based on openULINK project code by: Martin Schmoelzer. *
|
||||
Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
|
||||
<aboudjelida@nanoxplore.com> *
|
||||
<ahmederrachedbjld@gmail.com> *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "usb.h"
|
||||
#include "delay.h"
|
||||
#include "protocol.h"
|
||||
#include "reg_ezusb.h"
|
||||
#include <serial.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern void sudav_isr(void)__interrupt SUDAV_ISR;
|
||||
extern void sof_isr(void)__interrupt;
|
||||
extern void sutok_isr(void)__interrupt;
|
||||
extern void suspend_isr(void)__interrupt;
|
||||
extern void usbreset_isr(void)__interrupt;
|
||||
extern void highspeed_isr(void)__interrupt;
|
||||
extern void ep0ack_isr(void)__interrupt;
|
||||
extern void stub_isr(void)__interrupt;
|
||||
extern void ep0in_isr(void)__interrupt;
|
||||
extern void ep0out_isr(void)__interrupt;
|
||||
extern void ep1in_isr(void)__interrupt;
|
||||
extern void ep1out_isr(void)__interrupt;
|
||||
extern void ep2_isr(void)__interrupt;
|
||||
extern void ep4_isr(void)__interrupt;
|
||||
extern void ep6_isr(void)__interrupt;
|
||||
extern void ep8_isr(void)__interrupt;
|
||||
extern void ibn_isr(void)__interrupt;
|
||||
extern void ep0pingnak_isr(void)__interrupt;
|
||||
extern void ep1pingnak_isr(void)__interrupt;
|
||||
extern void ep2pingnak_isr(void)__interrupt;
|
||||
extern void ep4pingnak_isr(void)__interrupt;
|
||||
extern void ep6pingnak_isr(void)__interrupt;
|
||||
extern void ep8pingnak_isr(void)__interrupt;
|
||||
extern void errorlimit_isr(void)__interrupt;
|
||||
extern void ep2piderror_isr(void)__interrupt;
|
||||
extern void ep4piderror_isr(void)__interrupt;
|
||||
extern void ep6piderror_isr(void)__interrupt;
|
||||
extern void ep8piderror_isr(void)__interrupt;
|
||||
extern void ep2pflag_isr(void)__interrupt;
|
||||
extern void ep4pflag_isr(void)__interrupt;
|
||||
extern void ep6pflag_isr(void)__interrupt;
|
||||
extern void ep8pflag_isr(void)__interrupt;
|
||||
extern void ep2eflag_isr(void)__interrupt;
|
||||
extern void ep4eflag_isr(void)__interrupt;
|
||||
extern void ep6eflag_isr(void)__interrupt;
|
||||
extern void ep8eflag_isr(void)__interrupt;
|
||||
extern void ep2fflag_isr(void)__interrupt;
|
||||
extern void ep4fflag_isr(void)__interrupt;
|
||||
extern void ep6fflag_isr(void)__interrupt;
|
||||
extern void ep8fflag_isr(void)__interrupt;
|
||||
extern void gpifcomplete_isr(void)__interrupt;
|
||||
extern void gpifwaveform_isr(void)__interrupt;
|
||||
|
||||
void gpif_init(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CPUCS = ((CPUCS & ~bmclkspd) | (CLK_48M << 3) | CLKOE); /* required for sio0_init */
|
||||
sio0_init(57600); /* needed for printf */
|
||||
|
||||
ep_init();
|
||||
gpif_init();
|
||||
interrupt_init();
|
||||
io_init();
|
||||
|
||||
/* Perform ReNumeration */
|
||||
USBCS |= (DISCON | RENUM);
|
||||
delay_ms(250);
|
||||
USBCS &= ~DISCON;
|
||||
|
||||
/* Begin executing command(s). This function never returns. */
|
||||
command_loop();
|
||||
|
||||
/* Never reached, but SDCC complains about missing return statement */
|
||||
return 0;
|
||||
}
|
||||
189
contrib/firmware/angie/c/src/protocol.c
Normal file
189
contrib/firmware/angie/c/src/protocol.c
Normal file
@@ -0,0 +1,189 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/****************************************************************************
|
||||
File : protocol.c *
|
||||
Contents : Jtag commands handling protocol code for NanoXplore *
|
||||
USB-JTAG ANGIE adapter hardware. *
|
||||
Based on openULINK project code by: Martin Schmoelzer. *
|
||||
Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
|
||||
<aboudjelida@nanoxplore.com> *
|
||||
<ahmederrachedbjld@gmail.com> *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "usb.h"
|
||||
#include "protocol.h"
|
||||
#include "jtag.h"
|
||||
#include "delay.h"
|
||||
#include "io.h"
|
||||
#include "msgtypes.h"
|
||||
#include "reg_ezusb.h"
|
||||
#include <serial.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/** Index in EP1 Bulk-OUT data buffer that contains the current command ID */
|
||||
volatile uint8_t cmd_id_index;
|
||||
|
||||
/** Number of data bytes already in EP1 Bulk-IN buffer */
|
||||
volatile uint8_t payload_index_in;
|
||||
|
||||
/**
|
||||
* Executes one command and updates global command indexes.
|
||||
*
|
||||
* @return true if this command was the last command.
|
||||
* @return false if there are more commands within the current contents of the
|
||||
* Bulk EP1-OUT data buffer.
|
||||
*/
|
||||
bool execute_command(void)
|
||||
{
|
||||
uint8_t usb_out_bytecount, usb_in_bytecount;
|
||||
uint16_t signal_state = 0;
|
||||
uint16_t count;
|
||||
|
||||
/* Most commands do not transfer IN data. To save code space, we write 0 to
|
||||
* usb_in_bytecount here, then modify it in the switch statement below where
|
||||
* necessary */
|
||||
usb_in_bytecount = 0;
|
||||
|
||||
switch (EP1OUTBUF[cmd_id_index] /* Command ID */) {
|
||||
case CMD_SCAN_IN:
|
||||
usb_out_bytecount = 5;
|
||||
usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
|
||||
jtag_scan_in((cmd_id_index + 1), payload_index_in);
|
||||
break;
|
||||
case CMD_SCAN_OUT:
|
||||
usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5;
|
||||
jtag_scan_out(cmd_id_index + 1);
|
||||
break;
|
||||
case CMD_SCAN_IO:
|
||||
usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
|
||||
usb_out_bytecount = usb_in_bytecount + 5;
|
||||
jtag_scan_io((cmd_id_index + 1), payload_index_in);
|
||||
break;
|
||||
case CMD_CLOCK_TMS:
|
||||
usb_out_bytecount = 2;
|
||||
jtag_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]);
|
||||
break;
|
||||
case CMD_CLOCK_TCK:
|
||||
usb_out_bytecount = 2;
|
||||
count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
|
||||
count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
|
||||
jtag_clock_tck(count);
|
||||
break;
|
||||
case CMD_SLOW_SCAN_IN:
|
||||
usb_out_bytecount = 5;
|
||||
usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
|
||||
jtag_slow_scan_in(cmd_id_index + 1, payload_index_in);
|
||||
break;
|
||||
case CMD_SLOW_SCAN_OUT:
|
||||
usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5;
|
||||
jtag_slow_scan_out(cmd_id_index + 1);
|
||||
break;
|
||||
case CMD_SLOW_SCAN_IO:
|
||||
usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
|
||||
usb_out_bytecount = usb_in_bytecount + 5;
|
||||
jtag_slow_scan_io(cmd_id_index + 1, payload_index_in);
|
||||
break;
|
||||
case CMD_SLOW_CLOCK_TMS:
|
||||
usb_out_bytecount = 2;
|
||||
jtag_slow_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]);
|
||||
break;
|
||||
case CMD_SLOW_CLOCK_TCK:
|
||||
usb_out_bytecount = 2;
|
||||
count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
|
||||
count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
|
||||
jtag_slow_clock_tck(count);
|
||||
break;
|
||||
case CMD_SLEEP_US:
|
||||
usb_out_bytecount = 2;
|
||||
count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
|
||||
count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
|
||||
delay_us(count);
|
||||
break;
|
||||
case CMD_SLEEP_MS:
|
||||
usb_out_bytecount = 2;
|
||||
count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
|
||||
count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
|
||||
delay_ms(count);
|
||||
break;
|
||||
case CMD_GET_SIGNALS:
|
||||
usb_out_bytecount = 0;
|
||||
usb_in_bytecount = 2;
|
||||
signal_state = jtag_get_signals();
|
||||
EP1INBUF[payload_index_in] = (signal_state >> 8);
|
||||
EP1INBUF[payload_index_in + 1] = (signal_state & 0xFF);
|
||||
break;
|
||||
case CMD_SET_SIGNALS:
|
||||
usb_out_bytecount = 2;
|
||||
jtag_set_signals(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]);
|
||||
break;
|
||||
case CMD_CONFIGURE_TCK_FREQ:
|
||||
usb_out_bytecount = 5;
|
||||
jtag_configure_tck_delay(EP1OUTBUF[cmd_id_index + 1], /* scan_in */
|
||||
EP1OUTBUF[cmd_id_index + 2], /* scan_out */
|
||||
EP1OUTBUF[cmd_id_index + 3], /* scan_io */
|
||||
EP1OUTBUF[cmd_id_index + 4], /* clock_tck */
|
||||
EP1OUTBUF[cmd_id_index + 5]); /* clock_tms */
|
||||
break;
|
||||
case CMD_TEST:
|
||||
usb_out_bytecount = 1;
|
||||
/* Do nothing... This command is only used to test if the device is ready
|
||||
* to accept new commands */
|
||||
break;
|
||||
default:
|
||||
/* Should never be reached */
|
||||
usb_out_bytecount = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update EP1 Bulk-IN data byte count */
|
||||
payload_index_in += usb_in_bytecount;
|
||||
|
||||
/* Determine if this was the last command */
|
||||
if ((cmd_id_index + usb_out_bytecount + 1) >= EP1OUTBC) {
|
||||
return true;
|
||||
/* Line between return and else required by checkpatch: */
|
||||
uint8_t a = 0;
|
||||
} else {
|
||||
/* Not the last command, update cmd_id_index */
|
||||
cmd_id_index += (usb_out_bytecount + 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forever wait for commands and execute them as they arrive.
|
||||
*/
|
||||
void command_loop(void)
|
||||
{
|
||||
bool last_command;
|
||||
while (1) {
|
||||
cmd_id_index = 0;
|
||||
payload_index_in = 0;
|
||||
|
||||
/* Wait until host sends EP1 Bulk-OUT packet */
|
||||
while (!ep1_out)
|
||||
;
|
||||
ep1_out = false;
|
||||
|
||||
/* Execute the commands */
|
||||
last_command = false;
|
||||
while (!last_command)
|
||||
last_command = execute_command();
|
||||
|
||||
/* Send back EP6 Bulk-IN packet if required */
|
||||
if (payload_index_in > 0) {
|
||||
EP1INBC = payload_index_in;
|
||||
syncdelay(3);
|
||||
|
||||
while (!ep1_in)
|
||||
;
|
||||
ep1_in = false;
|
||||
}
|
||||
|
||||
/* Re-arm EP1-OUT after command execution */
|
||||
EP1OUTBC = 0;
|
||||
syncdelay(3);
|
||||
EP1OUTBC = 0;
|
||||
syncdelay(3);
|
||||
}
|
||||
}
|
||||
77
contrib/firmware/angie/c/src/serial.c
Normal file
77
contrib/firmware/angie/c/src/serial.c
Normal file
@@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/*
|
||||
* This code was taken from the fx2lib project from this link:
|
||||
* https://github.com/djmuhlestein/fx2lib
|
||||
*
|
||||
* Copyright (C) 2009 Ubixum, Inc.
|
||||
*/
|
||||
|
||||
#include <reg_ezusb.h>
|
||||
#include <fx2macros.h>
|
||||
#include <serial.h>
|
||||
#include <stdint.h>
|
||||
/**
|
||||
* using the comp port implies that timer 2 will be used as
|
||||
* a baud rate generator. (Don't use timer 2)
|
||||
**/
|
||||
void sio0_init(uint32_t baud_rate) __critical
|
||||
{
|
||||
uint16_t hl; /* hl value for reload */
|
||||
uint8_t mult; /* multiplier for clock speed */
|
||||
uint32_t tmp; /* scratch for mult/divide */
|
||||
|
||||
mult = (CPUFREQ == CLK_12M) ? 1 : ((CPUFREQ == CLK_24M) ? 2 : 4);
|
||||
|
||||
/* set the clock rate */
|
||||
/* use clock 2 */
|
||||
RCLK = 1; TCLK = 1;
|
||||
tmp = mult * 375000L * 2;
|
||||
tmp /= baud_rate;
|
||||
tmp += 1;
|
||||
tmp /= 2;
|
||||
hl = 0xFFFF - (uint16_t)tmp;
|
||||
RCAP2H = (uint8_t)(((uint16_t)(hl) >> 8) & 0xff);
|
||||
|
||||
/* seems that the 24/48mhz calculations are always one less than suggested values */
|
||||
/* trm table 14-16 */
|
||||
RCAP2L = ((uint8_t)((uint16_t)(hl) & 0xff)) + (mult > 0 ? 1 : 0);
|
||||
|
||||
/* start the timer */
|
||||
TR2 = 1;
|
||||
|
||||
/* set up the serial port */
|
||||
SM0 = 0; SM1 = 1; /* serial mode 1 (asyncronous) */
|
||||
SM2 = 0 ; /* has to do with receiving */
|
||||
REN = 1 ; /* to enable receiving */
|
||||
PCON |= 0x80; /* SET SMOD0, baud rate doubler */
|
||||
TI = 1; /* we send initial byte */
|
||||
}
|
||||
|
||||
int getchar(void)
|
||||
{
|
||||
char c;
|
||||
while (!RI)
|
||||
;
|
||||
c = SBUF0;
|
||||
RI = 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
void _transchar(char c)
|
||||
{
|
||||
while (!TI)
|
||||
; /* wait for TI=1 */
|
||||
TI = 0;
|
||||
SBUF0 = c;
|
||||
}
|
||||
|
||||
int putchar (char c)
|
||||
{
|
||||
if (c == '\n')
|
||||
_transchar('\r'); /* transmit \r\n */
|
||||
_transchar(c);
|
||||
if (c == '\r')
|
||||
_transchar('\n'); /* transmit \r\n */
|
||||
return c;
|
||||
}
|
||||
784
contrib/firmware/angie/c/src/usb.c
Normal file
784
contrib/firmware/angie/c/src/usb.c
Normal file
@@ -0,0 +1,784 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/****************************************************************************
|
||||
File : usb.c *
|
||||
Contents : usb communication handling code for NanoXplore USB-JTAG *
|
||||
ANGIE adapter hardware. *
|
||||
Based on openULINK project code by: Martin Schmoelzer. *
|
||||
Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
|
||||
<aboudjelida@nanoxplore.com> *
|
||||
<ahmederrachedbjld@gmail.com> *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "usb.h"
|
||||
#include "stdint.h"
|
||||
#include "delay.h"
|
||||
#include "io.h"
|
||||
#include "reg_ezusb.h"
|
||||
#include <fx2macros.h>
|
||||
#include <serial.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Also update external declarations in "include/usb.h" if making changes to
|
||||
* these variables!
|
||||
*/
|
||||
volatile bool ep1_out;
|
||||
volatile bool ep1_in;
|
||||
|
||||
volatile __xdata __at 0xE6B8 struct setup_data setup_data;
|
||||
|
||||
/* Define number of endpoints (except Control Endpoint 0) in a central place.
|
||||
* Be sure to include the necessary endpoint descriptors!
|
||||
*/
|
||||
#define NUM_ENDPOINTS 3
|
||||
|
||||
__code struct usb_device_descriptor device_descriptor = {
|
||||
.blength = sizeof(struct usb_device_descriptor),
|
||||
.bdescriptortype = DESCRIPTOR_TYPE_DEVICE,
|
||||
.bcdusb = 0x0200, /* BCD: 02.00 (Version 2.0 USB spec) */
|
||||
.bdeviceclass = 0xFF, /* 0xFF = vendor-specific */
|
||||
.bdevicesubclass = 0xFF,
|
||||
.bdeviceprotocol = 0xFF,
|
||||
.bmaxpacketsize0 = 64,
|
||||
.idvendor = 0x584e,
|
||||
.idproduct = 0x424e,
|
||||
.bcddevice = 0x0000,
|
||||
.imanufacturer = 1,
|
||||
.iproduct = 2,
|
||||
.iserialnumber = 3,
|
||||
.bnumconfigurations = 1
|
||||
};
|
||||
|
||||
/* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */
|
||||
|
||||
__code struct usb_config_descriptor config_descriptor = {
|
||||
.blength = sizeof(struct usb_config_descriptor),
|
||||
.bdescriptortype = DESCRIPTOR_TYPE_CONFIGURATION,
|
||||
.wtotallength = sizeof(struct usb_config_descriptor) +
|
||||
sizeof(struct usb_interface_descriptor) +
|
||||
(NUM_ENDPOINTS * sizeof(struct usb_endpoint_descriptor)),
|
||||
.bnuminterfaces = 1,
|
||||
.bconfigurationvalue = 1,
|
||||
.iconfiguration = 4, /* String describing this configuration */
|
||||
.bmattributes = 0x80, /* Only MSB set according to USB spec */
|
||||
.maxpower = 50 /* 100 mA */
|
||||
};
|
||||
|
||||
__code struct usb_interface_descriptor interface_descriptor00 = {
|
||||
.blength = sizeof(struct usb_interface_descriptor),
|
||||
.bdescriptortype = DESCRIPTOR_TYPE_INTERFACE,
|
||||
.binterfacenumber = 0,
|
||||
.balternatesetting = 0,
|
||||
.bnumendpoints = NUM_ENDPOINTS,
|
||||
.binterfaceclass = 0xFF,
|
||||
.binterfacesubclass = 0xFF,
|
||||
.binterfaceprotocol = 0xFF,
|
||||
.iinterface = 0
|
||||
};
|
||||
|
||||
__code struct usb_endpoint_descriptor bulk_ep1_out_endpoint_descriptor = {
|
||||
.blength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bdescriptortype = 0x05,
|
||||
.bendpointaddress = (1 | USB_DIR_OUT),
|
||||
.bmattributes = 0x02,
|
||||
.wmaxpacketsize = 64,
|
||||
.binterval = 0
|
||||
};
|
||||
|
||||
__code struct usb_endpoint_descriptor bulk_ep1_in_endpoint_descriptor = {
|
||||
.blength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bdescriptortype = 0x05,
|
||||
.bendpointaddress = (1 | USB_DIR_IN),
|
||||
.bmattributes = 0x02,
|
||||
.wmaxpacketsize = 64,
|
||||
.binterval = 0
|
||||
};
|
||||
|
||||
__code struct usb_endpoint_descriptor bulk_ep2_endpoint_descriptor = {
|
||||
.blength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bdescriptortype = 0x05,
|
||||
.bendpointaddress = (2 | USB_DIR_OUT),
|
||||
.bmattributes = 0x02,
|
||||
.wmaxpacketsize = 512,
|
||||
.binterval = 0
|
||||
};
|
||||
|
||||
__code struct usb_endpoint_descriptor bulk_ep4_endpoint_descriptor = {
|
||||
.blength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bdescriptortype = 0x05,
|
||||
.bendpointaddress = (4 | USB_DIR_IN),
|
||||
.bmattributes = 0x02,
|
||||
.wmaxpacketsize = 512,
|
||||
.binterval = 0
|
||||
};
|
||||
|
||||
__code struct usb_endpoint_descriptor bulk_ep6_endpoint_descriptor = {
|
||||
.blength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bdescriptortype = 0x05,
|
||||
.bendpointaddress = (6 | USB_DIR_OUT),
|
||||
.bmattributes = 0x02,
|
||||
.wmaxpacketsize = 512,
|
||||
.binterval = 0
|
||||
};
|
||||
|
||||
__code struct usb_endpoint_descriptor bulk_ep8_endpoint_descriptor = {
|
||||
.blength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bdescriptortype = 0x05,
|
||||
.bendpointaddress = (8 | USB_DIR_OUT),
|
||||
.bmattributes = 0x02,
|
||||
.wmaxpacketsize = 512,
|
||||
.binterval = 0
|
||||
};
|
||||
|
||||
__code struct usb_language_descriptor language_descriptor = {
|
||||
.blength = 4,
|
||||
.bdescriptortype = DESCRIPTOR_TYPE_STRING,
|
||||
.wlangid = {0x0409 /* US English */}
|
||||
};
|
||||
|
||||
__code struct usb_string_descriptor strmanufacturer =
|
||||
STR_DESCR(16, 'N', 'a', 'n', 'o', 'X', 'p', 'l', 'o', 'r', 'e', ',', ' ', 'S', 'A', 'S', '.');
|
||||
|
||||
__code struct usb_string_descriptor strproduct =
|
||||
STR_DESCR(13, 'A', 'N', 'G', 'I', 'E', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
|
||||
|
||||
__code struct usb_string_descriptor strserialnumber =
|
||||
STR_DESCR(6, '0', '0', '0', '0', '0', '1');
|
||||
|
||||
__code struct usb_string_descriptor strconfigdescr =
|
||||
STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
|
||||
|
||||
/* Table containing pointers to string descriptors */
|
||||
__code struct usb_string_descriptor *__code en_string_descriptors[4] = {
|
||||
&strmanufacturer,
|
||||
&strproduct,
|
||||
&strserialnumber,
|
||||
&strconfigdescr
|
||||
};
|
||||
void sudav_isr(void)__interrupt SUDAV_ISR
|
||||
{
|
||||
EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
|
||||
USBIRQ = SUDAVI;
|
||||
EP0CS |= HSNAK;
|
||||
usb_handle_setup_data();
|
||||
}
|
||||
void sof_isr(void)__interrupt SOF_ISR
|
||||
{
|
||||
}
|
||||
void sutok_isr(void)__interrupt SUTOK_ISR
|
||||
{
|
||||
}
|
||||
void suspend_isr(void)__interrupt SUSPEND_ISR
|
||||
{
|
||||
}
|
||||
void usbreset_isr(void)__interrupt USBRESET_ISR
|
||||
{
|
||||
}
|
||||
void highspeed_isr(void)__interrupt HIGHSPEED_ISR
|
||||
{
|
||||
}
|
||||
void ep0ack_isr(void)__interrupt EP0ACK_ISR
|
||||
{
|
||||
}
|
||||
void stub_isr(void)__interrupt STUB_ISR
|
||||
{
|
||||
}
|
||||
void ep0in_isr(void)__interrupt EP0IN_ISR
|
||||
{
|
||||
}
|
||||
void ep0out_isr(void)__interrupt EP0OUT_ISR
|
||||
{
|
||||
}
|
||||
void ep1in_isr(void)__interrupt EP1IN_ISR
|
||||
{
|
||||
ep1_in = true;
|
||||
|
||||
EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
|
||||
EPIRQ = 0x04; /* Clear individual EP1IN IRQ */
|
||||
}
|
||||
void ep1out_isr(void)__interrupt EP1OUT_ISR
|
||||
{
|
||||
ep1_out = true;
|
||||
|
||||
EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
|
||||
EPIRQ = 0x08; /* Clear individual EP1OUT IRQ */
|
||||
}
|
||||
void ep2_isr(void)__interrupt EP2_ISR
|
||||
{
|
||||
ep1_out = false; /* Does nothing but required by the compiler */
|
||||
}
|
||||
void ep4_isr(void)__interrupt EP4_ISR
|
||||
{
|
||||
}
|
||||
void ep6_isr(void)__interrupt EP6_ISR
|
||||
{
|
||||
}
|
||||
void ep8_isr(void)__interrupt EP8_ISR
|
||||
{
|
||||
}
|
||||
void ibn_isr(void)__interrupt IBN_ISR
|
||||
{
|
||||
}
|
||||
void ep0pingnak_isr(void)__interrupt EP0PINGNAK_ISR
|
||||
{
|
||||
}
|
||||
void ep1pingnak_isr(void)__interrupt EP1PINGNAK_ISR
|
||||
{
|
||||
}
|
||||
void ep2pingnak_isr(void)__interrupt EP2PINGNAK_ISR
|
||||
{
|
||||
}
|
||||
void ep4pingnak_isr(void)__interrupt EP4PINGNAK_ISR
|
||||
{
|
||||
}
|
||||
void ep6pingnak_isr(void)__interrupt EP6PINGNAK_ISR
|
||||
{
|
||||
}
|
||||
void ep8pingnak_isr(void)__interrupt EP8PINGNAK_ISR
|
||||
{
|
||||
}
|
||||
void errorlimit_isr(void)__interrupt ERRORLIMIT_ISR
|
||||
{
|
||||
}
|
||||
void ep2piderror_isr(void)__interrupt EP2PIDERROR_ISR
|
||||
{
|
||||
}
|
||||
void ep4piderror_isr(void)__interrupt EP4PIDERROR_ISR
|
||||
{
|
||||
}
|
||||
void ep6piderror_isr(void)__interrupt EP6PIDERROR_ISR
|
||||
{
|
||||
}
|
||||
void ep8piderror_isr(void)__interrupt EP8PIDERROR_ISR
|
||||
{
|
||||
}
|
||||
void ep2pflag_isr(void)__interrupt EP2PFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep4pflag_isr(void)__interrupt EP4PFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep6pflag_isr(void)__interrupt EP6PFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep8pflag_isr(void)__interrupt EP8PFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep2eflag_isr(void)__interrupt EP2EFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep4eflag_isr(void)__interrupt EP4EFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep6eflag_isr(void)__interrupt EP6EFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep8eflag_isr(void)__interrupt EP8EFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep2fflag_isr(void)__interrupt EP2FFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep4fflag_isr(void)__interrupt EP4FFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep6fflag_isr(void)__interrupt EP6FFLAG_ISR
|
||||
{
|
||||
}
|
||||
void ep8fflag_isr(void)__interrupt EP8FFLAG_ISR
|
||||
{
|
||||
}
|
||||
void gpifcomplete_isr(void)__interrupt GPIFCOMPLETE_ISR
|
||||
{
|
||||
}
|
||||
void gpifwaveform_isr(void)__interrupt GPIFWAVEFORM_ISR
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the control/status register for an endpoint
|
||||
*
|
||||
* @param ep endpoint address
|
||||
* @return on success: pointer to Control & Status register for endpoint
|
||||
* specified in \a ep
|
||||
* @return on failure: NULL
|
||||
*/
|
||||
__xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep)
|
||||
{
|
||||
/* Mask direction bit */
|
||||
uint8_t ep_num = ep & ~0x80;
|
||||
|
||||
switch (ep_num) {
|
||||
case 0:
|
||||
return &EP0CS;
|
||||
case 1:
|
||||
return ep & 0x80 ? &EP1INCS : &EP1OUTCS;
|
||||
case 2:
|
||||
return &EP2CS;
|
||||
case 4:
|
||||
return &EP4CS;
|
||||
case 6:
|
||||
return &EP6CS;
|
||||
case 8:
|
||||
return &EP8CS;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_reset_data_toggle(uint8_t ep)
|
||||
{
|
||||
/* TOGCTL register:
|
||||
+----+-----+-----+------+-----+-------+-------+-------+
|
||||
| Q | S | R | IO | EP3 | EP2 | EP1 | EP0 |
|
||||
+----+-----+-----+------+-----+-------+-------+-------+
|
||||
|
||||
To reset data toggle bits, we have to write the endpoint direction (IN/OUT)
|
||||
to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a
|
||||
separate write cycle, the R bit needs to be set.
|
||||
*/
|
||||
TOGCTL = (((ep & 0x80) >> 3) + (ep & 0x0F));
|
||||
TOGCTL |= BMRESETTOGGLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle GET_STATUS request.
|
||||
*
|
||||
* @return on success: true
|
||||
* @return on failure: false
|
||||
*/
|
||||
bool usb_handle_get_status(void)
|
||||
{
|
||||
uint8_t *ep_cs;
|
||||
switch (setup_data.bmrequesttype) {
|
||||
case GS_DEVICE:
|
||||
/* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup.
|
||||
* Byte 1: reserved, reset to zero */
|
||||
EP0BUF[0] = 0;
|
||||
EP0BUF[1] = 0;
|
||||
|
||||
/* Send response */
|
||||
EP0BCH = 0;
|
||||
syncdelay(3);
|
||||
EP0BCL = 2;
|
||||
syncdelay(3);
|
||||
break;
|
||||
case GS_INTERFACE:
|
||||
/* Always return two zero bytes according to USB 1.1 spec, p. 191 */
|
||||
EP0BUF[0] = 0;
|
||||
EP0BUF[1] = 0;
|
||||
|
||||
/* Send response */
|
||||
EP0BCH = 0;
|
||||
syncdelay(3);
|
||||
EP0BCL = 2;
|
||||
syncdelay(3);
|
||||
break;
|
||||
case GS_ENDPOINT:
|
||||
/* Get stall bit for endpoint specified in low byte of wIndex */
|
||||
ep_cs = usb_get_endpoint_cs_reg(setup_data.windex & 0xff);
|
||||
|
||||
if (*ep_cs & EPSTALL)
|
||||
EP0BUF[0] = 0x01;
|
||||
else
|
||||
EP0BUF[0] = 0x00;
|
||||
|
||||
/* Second byte sent has to be always zero */
|
||||
EP0BUF[1] = 0;
|
||||
|
||||
/* Send response */
|
||||
EP0BCH = 0;
|
||||
syncdelay(3);
|
||||
EP0BCL = 2;
|
||||
syncdelay(3);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle CLEAR_FEATURE request.
|
||||
*
|
||||
* @return on success: true
|
||||
* @return on failure: false
|
||||
*/
|
||||
bool usb_handle_clear_feature(void)
|
||||
{
|
||||
__xdata uint8_t *ep_cs;
|
||||
|
||||
switch (setup_data.bmrequesttype) {
|
||||
case CF_DEVICE:
|
||||
/* Clear remote wakeup not supported: stall EP0 */
|
||||
STALL_EP0();
|
||||
break;
|
||||
case CF_ENDPOINT:
|
||||
if (setup_data.wvalue == 0) {
|
||||
/* Unstall the endpoint specified in wIndex */
|
||||
ep_cs = usb_get_endpoint_cs_reg(setup_data.windex);
|
||||
if (!ep_cs)
|
||||
return false;
|
||||
*ep_cs &= ~EPSTALL;
|
||||
} else {
|
||||
/* Unsupported feature, stall EP0 */
|
||||
STALL_EP0();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Vendor commands... */
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle SET_FEATURE request.
|
||||
*
|
||||
* @return on success: true
|
||||
* @return on failure: false
|
||||
*/
|
||||
bool usb_handle_set_feature(void)
|
||||
{
|
||||
__xdata uint8_t *ep_cs;
|
||||
|
||||
switch (setup_data.bmrequesttype) {
|
||||
case SF_DEVICE:
|
||||
if (setup_data.wvalue == 2)
|
||||
return true;
|
||||
break;
|
||||
case SF_ENDPOINT:
|
||||
if (setup_data.wvalue == 0) {
|
||||
/* Stall the endpoint specified in wIndex */
|
||||
ep_cs = usb_get_endpoint_cs_reg(setup_data.windex);
|
||||
if (!ep_cs)
|
||||
return false;
|
||||
*ep_cs |= EPSTALL;
|
||||
} else {
|
||||
/* Unsupported endpoint feature */
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Vendor commands... */
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle GET_DESCRIPTOR request.
|
||||
*
|
||||
* @return on success: true
|
||||
* @return on failure: false
|
||||
*/
|
||||
bool usb_handle_get_descriptor(void)
|
||||
{
|
||||
__xdata uint8_t descriptor_type;
|
||||
__xdata uint8_t descriptor_index;
|
||||
|
||||
descriptor_type = (setup_data.wvalue & 0xff00) >> 8;
|
||||
descriptor_index = setup_data.wvalue & 0x00ff;
|
||||
|
||||
switch (descriptor_type) {
|
||||
case DESCRIPTOR_TYPE_DEVICE:
|
||||
SUDPTRH = HI8(&device_descriptor);
|
||||
SUDPTRL = LO8(&device_descriptor);
|
||||
break;
|
||||
case DESCRIPTOR_TYPE_CONFIGURATION:
|
||||
SUDPTRH = HI8(&config_descriptor);
|
||||
SUDPTRL = LO8(&config_descriptor);
|
||||
break;
|
||||
case DESCRIPTOR_TYPE_STRING:
|
||||
if (setup_data.windex == 0) {
|
||||
/* Supply language descriptor */
|
||||
SUDPTRH = HI8(&language_descriptor);
|
||||
SUDPTRL = LO8(&language_descriptor);
|
||||
} else if (setup_data.windex == 0x0409 /* US English */) {
|
||||
/* Supply string descriptor */
|
||||
SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]);
|
||||
SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Unsupported descriptor type */
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle SET_INTERFACE request.
|
||||
*/
|
||||
void usb_handle_set_interface(void)
|
||||
{
|
||||
/* Reset Data Toggle */
|
||||
usb_reset_data_toggle(USB_DIR_IN | 4);
|
||||
usb_reset_data_toggle(USB_DIR_OUT | 2);
|
||||
|
||||
/* Unstall & clear busy flag of all valid IN endpoints */
|
||||
EP1INCS = 0 | EPBSY;
|
||||
|
||||
/* Unstall all valid OUT endpoints, reset bytecounts */
|
||||
EP1OUTCS = 0;
|
||||
EP1OUTBC = 0;
|
||||
syncdelay(3);
|
||||
}
|
||||
|
||||
/* Initialize GPIF interface transfer count */
|
||||
void set_gpif_cnt(uint32_t count)
|
||||
{
|
||||
GPIFTCB3 = (uint8_t)(((uint32_t)(count) >> 24) & 0x000000ff);
|
||||
syncdelay(3);
|
||||
GPIFTCB2 = (uint8_t)(((uint32_t)(count) >> 16) & 0x000000ff);
|
||||
syncdelay(3);
|
||||
GPIFTCB1 = (uint8_t)(((uint32_t)(count) >> 8) & 0x000000ff);
|
||||
syncdelay(3);
|
||||
GPIFTCB0 = (uint8_t)((uint32_t)(count) & 0x000000ff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vendor commands handling:
|
||||
*/
|
||||
#define VR_CFGOPEN 0xB0
|
||||
#define VR_CFGCLOSE 0xB1
|
||||
|
||||
uint8_t ix;
|
||||
uint8_t bcnt;
|
||||
uint8_t __xdata *eptr;
|
||||
uint16_t wcnt;
|
||||
uint32_t __xdata gcnt;
|
||||
bool usb_handle_send_bitstream(void)
|
||||
{
|
||||
eptr = EP0BUF; /* points to EP0BUF 64-byte register */
|
||||
wcnt = setup_data.wlength; /* total transfer count */
|
||||
|
||||
/* Clear EP0BUF for OUT requests */
|
||||
if (setup_data.bmrequesttype & 0x80) {
|
||||
bcnt = ((wcnt > 64) ? 64 : wcnt);
|
||||
for (ix = 0; ix < bcnt; ix++)
|
||||
eptr[ix] = 0;
|
||||
}
|
||||
|
||||
switch (setup_data.brequest) {
|
||||
case VR_CFGOPEN:
|
||||
/* Clear bytecount / to allow new data in / to stops NAKing */
|
||||
EP0BCH = 0;
|
||||
EP0BCL = 0;
|
||||
while (EP0CS & EPBSY)
|
||||
; /* wait to finish transferring in EP0BUF, until not busy */
|
||||
gcnt = ((uint32_t)(eptr[0]) << 24) | ((uint32_t)(eptr[1]) << 16)
|
||||
| ((uint32_t)(eptr[2]) << 8) | (uint32_t)(eptr[3]);
|
||||
/* Angie board FPGA bitstream download */
|
||||
switch ((setup_data.wvalue) & 0x00C0) {
|
||||
case 0x00:
|
||||
PIN_PROGRAM_B = 0; /* Apply RPGM- pulse */
|
||||
GPIFWFSELECT = 0xF2; /* Restore Config mode waveforms select */
|
||||
syncdelay(3);
|
||||
EP2FIFOCFG = BMAUTOOUT; /* and Automatic 8-bit GPIF OUT mode */
|
||||
syncdelay(3);
|
||||
PIN_PROGRAM_B = 1; /* Negate RPGM- pulse */
|
||||
delay_ms(10); /* FPGA init time < 10mS */
|
||||
set_gpif_cnt(gcnt); /* Initialize GPIF interface transfer count */
|
||||
PIN_RDWR_B = 0;
|
||||
PIN_CSI_B = 0;
|
||||
GPIFTRIG = GPIF_EP2; /* Trigger GPIF OUT transfer on EP2 */
|
||||
syncdelay(3);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VR_CFGCLOSE:
|
||||
ix = 10;
|
||||
/* wait until GPIF transaction has been completed */
|
||||
while ((GPIFTRIG & BMGPIFDONE) == 0) {
|
||||
if (ix-- == 0) {
|
||||
printf("GPIF done time out\n");
|
||||
break;
|
||||
}
|
||||
delay_ms(1);
|
||||
}
|
||||
switch ((setup_data.wvalue) & 0x00C0) {
|
||||
case 0x00:
|
||||
PIN_CSI_B = 1;
|
||||
PIN_RDWR_B = 1;
|
||||
IFCONFIG &= 0xFC; /* Exit gpif mode */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
EP0BCH = 0;
|
||||
EP0BCL = (uint8_t)(setup_data.wlength); /* Signal buffer is filled */
|
||||
break;
|
||||
default:
|
||||
return true; /* Error: unknown VR command */
|
||||
}
|
||||
return false; /* no error; command handled OK */
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the arrival of a USB Control Setup Packet.
|
||||
*/
|
||||
void usb_handle_setup_data(void)
|
||||
{
|
||||
switch (setup_data.brequest) {
|
||||
case GET_STATUS:
|
||||
if (!usb_handle_get_status())
|
||||
STALL_EP0();
|
||||
break;
|
||||
case CLEAR_FEATURE:
|
||||
if (!usb_handle_clear_feature())
|
||||
STALL_EP0();
|
||||
break;
|
||||
case 2: case 4:
|
||||
/* Reserved values */
|
||||
STALL_EP0();
|
||||
break;
|
||||
case SET_FEATURE:
|
||||
if (!usb_handle_set_feature())
|
||||
STALL_EP0();
|
||||
break;
|
||||
case SET_ADDRESS:
|
||||
/* Handled by USB core */
|
||||
break;
|
||||
case SET_DESCRIPTOR:
|
||||
/* Set Descriptor not supported. */
|
||||
STALL_EP0();
|
||||
break;
|
||||
case GET_DESCRIPTOR:
|
||||
if (!usb_handle_get_descriptor())
|
||||
STALL_EP0();
|
||||
break;
|
||||
case GET_CONFIGURATION:
|
||||
/* ANGIE has only one configuration, return its index */
|
||||
EP0BUF[0] = config_descriptor.bconfigurationvalue;
|
||||
EP0BCH = 0;
|
||||
EP0BCL = 1;
|
||||
syncdelay(3);
|
||||
break;
|
||||
case SET_CONFIGURATION:
|
||||
/* ANGIE has only one configuration -> nothing to do */
|
||||
break;
|
||||
case GET_INTERFACE:
|
||||
/* ANGIE only has one interface, return its number */
|
||||
EP0BUF[0] = interface_descriptor00.binterfacenumber;
|
||||
EP0BCH = 0;
|
||||
EP0BCL = 1;
|
||||
syncdelay(3);
|
||||
break;
|
||||
case SET_INTERFACE:
|
||||
usb_handle_set_interface();
|
||||
break;
|
||||
case SYNCH_FRAME:
|
||||
/* Isochronous endpoints not used -> nothing to do */
|
||||
break;
|
||||
default:
|
||||
/* if not Vendor command, Stall EndPoint 0 */
|
||||
if (usb_handle_send_bitstream())
|
||||
STALL_EP0();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the initialization of endpoints.
|
||||
*/
|
||||
void ep_init(void)
|
||||
{
|
||||
EP1INCFG = 0xA0;
|
||||
syncdelay(3);
|
||||
EP1OUTCFG = 0xA0;
|
||||
syncdelay(3);
|
||||
EP2CFG = 0xA0;
|
||||
syncdelay(3);
|
||||
EP4CFG = 0x00;
|
||||
syncdelay(3);
|
||||
EP6CFG = 0x00;
|
||||
syncdelay(3);
|
||||
EP8CFG = 0x00;
|
||||
syncdelay(3);
|
||||
|
||||
/* arm EP1-OUT */
|
||||
EP1OUTBC = 0;
|
||||
syncdelay(3);
|
||||
EP1OUTBC = 0;
|
||||
syncdelay(3);
|
||||
|
||||
/* arm EP1-IN */
|
||||
EP1INBC = 0;
|
||||
syncdelay(3);
|
||||
EP1INBC = 0;
|
||||
syncdelay(3);
|
||||
|
||||
/* Standard procedure to reset FIFOs */
|
||||
FIFORESET = BMNAKALL; /* NAK all transfers during the reset */
|
||||
syncdelay(3);
|
||||
FIFORESET = 0x02; /* reset EP2 FIFO */
|
||||
syncdelay(3);
|
||||
FIFORESET = 0x00; /* deactivate the NAK all */
|
||||
syncdelay(3);
|
||||
EP2FIFOCFG = 0x00;
|
||||
syncdelay(3);
|
||||
EP2FIFOCFG = BMAUTOOUT; /* Automatic 8-bit GPIF OUT mode */
|
||||
syncdelay(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupt initialization. Configures USB interrupts.
|
||||
*/
|
||||
void interrupt_init(void)
|
||||
{
|
||||
/* Enable Interrupts */
|
||||
EA = 1;
|
||||
|
||||
/* Enable USB interrupt (EIE register) */
|
||||
EUSB = 1;
|
||||
EICON |= 0x20;
|
||||
|
||||
/* Enable INT 2 & 4 Autovectoring */
|
||||
INTSETUP |= (AV2EN | AV4EN);
|
||||
|
||||
/* Enable individual EP1OUT&IN interrupts */
|
||||
EPIE |= 0x0C;
|
||||
|
||||
/* Clear individual USB interrupt IRQ */
|
||||
EPIRQ = 0x0C;
|
||||
|
||||
/* Enable SUDAV interrupt */
|
||||
USBIEN |= SUDAVI;
|
||||
|
||||
/* Clear SUDAV interrupt */
|
||||
USBIRQ = SUDAVI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the initialization of io ports.
|
||||
*/
|
||||
void io_init(void)
|
||||
{
|
||||
/* PORT A */
|
||||
PORTACFG = 0x01; /* 0: normal ou 1: alternate function (each bit) */
|
||||
OEA = 0xEF; /* all OUT exept INIT_B IN */
|
||||
IOA = 0xFF;
|
||||
PIN_RDWR_B = 1;
|
||||
PIN_CSI_B = 1;
|
||||
PIN_PROGRAM_B = 1;
|
||||
|
||||
/* PORT B */
|
||||
OEB = 0xEF; /* all OUT exept TDO */
|
||||
IOB = 0xFF;
|
||||
PIN_TRST = 1;
|
||||
PIN_TMS = 0;
|
||||
PIN_TCK = 0;
|
||||
PIN_TDI = 0;
|
||||
PIN_SRST = 1;
|
||||
|
||||
/* PORT C */
|
||||
PORTCCFG = 0x00; /* 0: normal ou 1: alternate function (each bit) */
|
||||
OEC = 0xEF;
|
||||
IOC = 0xFF;
|
||||
}
|
||||
Reference in New Issue
Block a user