2019-03-16 10:53:19 +00:00
/*
( banner font : aciiart . eu )
_____________________________________________________________
| _ __ _ _ \
| / \ / _ | | _ ___ _ _ | | __ _ _ _ __ ___ ___ _ _ | \
| / _ \ | | _ | ' _ / _ \ | ' _ / ' _ \ | | | | ' _ / _ \ / _ \ | ' _ / | |
| / ___ \ _ | | _ | __ / | | | | _ ) | | _ | | | | | | | __ / | | | |
| / _ / \ _ \ | \ __ \ ___ | | _ | | ____ / \ ___ , _ | _ | | _ | | _ | ___ | | _ | | |
\ _____________________________________________________________ | |
' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '
Afterburner : GAL IC Programmer for Arduino by - = olin = -
Based on ATFblast 3.1 by Bruce Abbott
http : //www.bhabbott.net.nz/atfblast.html
Based on GALBLAST by Manfred Winterhoff
http : //www.armory.com/%7Erstevew/Public/Pgmrs/GAL/_ClikMe1st.htm
2023-03-21 20:48:47 +00:00
Based on GALmate by Yorck Thiele
https : //www.ythiee.com/2021/06/06/galmate-hardware/
2019-03-16 10:53:19 +00:00
Supports :
* National GAL16V8
* Lattice GAL16V8A , GAL16V8B , GAL16V8D
* Lattice GAL22V10B
2023-03-25 21:21:59 +00:00
* Lattice GAL20V8
2023-03-21 20:48:47 +00:00
* Atmel ATF16V8B , ATF16V8C , ATF22V10B , ATF22V10CQZ
2019-03-16 10:53:19 +00:00
Requires :
* afterburner PC program to upload JED fuse map , erase , read etc .
2023-01-24 20:12:35 +00:00
* simple programming circuit . See : https : //github.com/ole00/afterburner
2019-03-16 10:53:19 +00:00
2024-02-02 21:38:50 +00:00
* 2024 - 02 - 02 Fixed : Command ' B9 ' ( Calibration Offset = 0 , 25 V ) doesn ' t work
Note : Also requires elimination of a in the PC program afterburner . c
Added : 10.0 V measurement in measureVppValues ( ( )
2019-03-16 10:53:19 +00:00
*/
2024-03-17 21:09:20 +00:00
# define VERSION "0.5.8"
2019-03-16 10:53:19 +00:00
2023-11-01 03:23:08 +00:00
//#define DEBUG_PES
2019-04-09 18:56:49 +00:00
//#define DEBUG_VERIFY
2019-03-16 10:53:19 +00:00
//ARDUINO UNO pin mapping
// GAL PIN NAME | ARDUINO UNO PIN NUMBER
//programing voltage control pin
# define PIN_VPP 11
# define PIN_SDOUT 12
# define PIN_STROBE 13
# define PIN_PV 9
# define PIN_SDIN 8
# define PIN_RA0 10
# define PIN_RA1 2
# define PIN_RA2 3
# define PIN_RA3 4
# define PIN_RA4 5
# define PIN_RA5 6
# define PIN_SCLK 7
2023-03-27 20:58:14 +00:00
// pin multiplex: ZIF_PIN <----> ARDUINO PIN or Shift register pin (0b1xxx)
# define PIN_ZIF3 2
# define PIN_ZIF4 0b1
# define PIN_ZIF5 0b1000
# define PIN_ZIF6 0b100
# define PIN_ZIF7 0b10
# define PIN_ZIF8 5
# define PIN_ZIF9 6
# define PIN_ZIF10 7
# define PIN_ZIF11 8
# define PIN_ZIF13 12
# define PIN_ZIF14 11
# define PIN_ZIF15 10
# define PIN_ZIF16 9
2023-09-17 04:55:40 +00:00
# define PIN_ZIF20 0b100000
2023-03-27 20:58:14 +00:00
# define PIN_ZIF21 0b10000
# define PIN_ZIF22 4
# define PIN_ZIF23 3
# define PIN_ZIF_GND_CTRL 13
//A0: VPP sense
//A3: DIGI_POT CS
# define PIN_SHR_EN A1
# define PIN_SHR_CS A2
//clk and dat is shared SPI bus
# define PIN_SHR_CLK A4
# define PIN_SHR_DAT A5
2019-03-16 10:53:19 +00:00
# define COMMAND_NONE 0
# define COMMAND_UNKNOWN 1
# define COMMAND_IDENTIFY_PROGRAMMER '*'
# define COMMAND_HELP 'h'
# define COMMAND_UPLOAD 'u'
# define COMMAND_DEBUG 'd'
# define COMMAND_READ_PES 'p'
2023-03-30 22:00:21 +00:00
# define COMMAND_WRITE_PES 'P'
2019-03-16 10:53:19 +00:00
# define COMMAND_READ_FUSES 'r'
# define COMMAND_WRITE_FUSES 'w'
# define COMMAND_VERIFY_FUSES 'v'
# define COMMAND_ERASE_GAL 'c'
2023-03-30 22:00:21 +00:00
# define COMMAND_ERASE_GAL_ALL '~'
2019-03-16 10:53:19 +00:00
# define COMMAND_UTX '#'
# define COMMAND_ECHO 'e'
# define COMMAND_TEST_VOLTAGE 't'
2019-04-09 18:56:49 +00:00
# define COMMAND_SET_GAL_TYPE 'g'
# define COMMAND_ENABLE_CHECK_TYPE 'f'
# define COMMAND_DISABLE_CHECK_TYPE 'F'
2023-03-25 19:40:03 +00:00
# define COMMAND_ENABLE_SECURITY 's'
2023-03-25 19:53:13 +00:00
# define COMMAND_ENABLE_APD 'z'
# define COMMAND_DISABLE_APD 'Z'
2023-03-27 20:58:14 +00:00
# define COMMAND_MEASURE_VPP 'm'
# define COMMAND_CALIBRATE_VPP 'b'
# define COMMAND_CALIBRATION_OFFSET 'B'
2019-03-16 10:53:19 +00:00
# define READGAL 0
# define VERIFYGAL 1
# define READPES 2
# define SCLKTEST 3
# define WRITEGAL 4
# define ERASEGAL 5
# define ERASEALL 6
# define BURNSECURITY 7
# define WRITEPES 8
# define VPPTEST 9
# define INIT 100
2023-03-21 19:58:40 +00:00
//check GAL type before starting an operation
# define FLAG_BIT_TYPE_CHECK (1 << 0)
// ATF16V8C flavour
# define FLAG_BIT_ATF16V8C (1 << 1)
2019-03-16 10:53:19 +00:00
2023-03-25 19:53:13 +00:00
// Keep the power-down feature enabled for ATF C GALs
# define FLAG_BIT_APD (1 << 2)
2019-03-16 10:53:19 +00:00
// contents of pes[3]
// Atmel PES is text string eg. 1B8V61F1 or 3Z01V22F1
// ^ ^
# define LATTICE 0xA1
# define NATIONAL 0x8F
# define SGSTHOMSON 0x20
# define ATMEL16 'V'
2019-04-09 18:56:49 +00:00
# define ATMEL22 '1'
2023-12-09 10:56:24 +00:00
# define ATMEL750 'C'
2019-03-16 10:53:19 +00:00
typedef enum {
UNKNOWN ,
GAL16V8 ,
2023-09-17 04:55:40 +00:00
GAL18V10 ,
2019-03-16 10:53:19 +00:00
GAL20V8 ,
2023-11-22 03:48:09 +00:00
GAL20RA10 ,
2023-09-16 06:20:12 +00:00
GAL20XV10 ,
2019-03-16 10:53:19 +00:00
GAL22V10 ,
2023-10-30 13:10:28 +00:00
GAL26CV12 ,
GAL26V12 ,
2023-09-22 15:32:15 +00:00
GAL6001 ,
GAL6002 ,
2019-03-16 10:53:19 +00:00
ATF16V8B ,
2023-10-30 14:13:25 +00:00
ATF20V8B ,
2019-03-16 10:53:19 +00:00
ATF22V10B ,
2019-04-09 18:56:49 +00:00
ATF22V10C ,
2023-12-09 10:56:24 +00:00
ATF750C ,
2019-04-09 18:56:49 +00:00
LAST_GAL_TYPE //dummy
2019-03-16 10:53:19 +00:00
} GALTYPE ;
2023-10-30 13:10:28 +00:00
typedef enum {
PINOUT_UNKNOWN ,
PINOUT_16V8 ,
PINOUT_18V10 ,
PINOUT_20V8 ,
PINOUT_22V10 ,
PINOUT_600 ,
} PINOUT ;
2023-03-21 20:48:47 +00:00
# define BIT_NONE 0
# define BIT_ZERO 1
# define BIT_ONE 2
2019-03-16 10:53:19 +00:00
// config bit numbers
2023-09-16 06:20:12 +00:00
# define CFG_BASE_16 2048
2023-09-17 04:55:40 +00:00
# define CFG_BASE_18 3456
2023-09-16 06:20:12 +00:00
# define CFG_BASE_20 2560
2023-11-22 03:48:09 +00:00
# define CFG_BASE_20RA 3200
2023-09-16 06:20:12 +00:00
# define CFG_BASE_20XV 1600
# define CFG_BASE_22 5808
2023-10-30 13:10:28 +00:00
# define CFG_BASE_26CV 6344
# define CFG_BASE_26V 7800
2023-09-22 15:32:15 +00:00
# define CFG_BASE_600 8154
2023-12-09 10:56:24 +00:00
# define CFG_BASE_750 14364
2019-03-16 10:53:19 +00:00
2019-04-09 18:56:49 +00:00
# define CFG_STROBE_ROW 0
# define CFG_SET_ROW 1
2023-12-09 10:56:24 +00:00
# define CFG_STROBE_ROW2 3
2019-04-09 18:56:49 +00:00
2023-03-25 19:53:13 +00:00
// Atmel power-down row
# define CFG_ROW_APD 59
2023-12-09 10:56:24 +00:00
// Naive detection of the board's RAM size - for support of big Fuse map:
// PIN_A11 - present on MEGA (8kB) or Leonardo (2.5kB SRAM)
// _RENESAS_RA_ - Uno R4 (32kB)
# if defined(PIN_A11) || defined(_RENESAS_RA_)
# define RAM_BIG
# endif
2019-03-16 10:53:19 +00:00
// common CFG fuse address map for cfg16V8 and cfg20V8
// the only difference is the starting address: 2048 for cfg16V8 and 2560 for cfg20V8
// total size: 82
2023-10-05 05:23:55 +00:00
static const unsigned char cfgV8 [ ] PROGMEM =
2019-03-16 10:53:19 +00:00
{
80 , 81 , 82 , 83 , 84 , 85 , 86 , 87 , 88 , 89 , 90 , 91 , 92 , 93 , 94 , 95 , 96 , 97 , 98 , 99 , 100 , 101 , 102 , 103 , 104 , 105 , 106 , 107 , 108 , 109 , 110 , 111 ,
0 , 1 , 2 , 3 ,
145 ,
72 , 73 , 74 , 75 , 76 , 77 , 78 , 79 ,
144 ,
4 , 5 , 6 , 7 ,
112 , 113 , 114 , 115 , 116 , 117 , 118 , 119 , 120 , 121 , 122 , 123 , 124 , 125 , 126 , 127 , 128 , 129 , 130 , 131 , 132 , 133 , 134 , 135 , 136 , 137 , 138 , 139 , 140 , 141 , 142 , 143 ,
} ;
// common CFG fuse address map for cfg16V8AB and cfg20V8AB
// the only difference is the starting address: 2048 for cfg16V8AB and 2560 for cfg20V8AB
// total size: 82
2023-10-05 05:23:55 +00:00
static const unsigned char cfgV8AB [ ] PROGMEM =
2019-03-16 10:53:19 +00:00
{
0 , 1 , 2 , 3 ,
145 ,
72 , 73 , 74 , 75 ,
80 , 81 , 82 , 83 , 84 , 85 , 86 , 87 , 88 , 89 , 90 , 91 , 92 , 93 , 94 , 95 , 96 , 97 , 98 , 99 , 100 , 101 , 102 , 103 , 104 , 105 , 106 , 107 , 108 , 109 , 110 , 111 , 112 , 113 , 114 , 115 , 116 , 117 , 118 , 119 , 120 , 121 , 122 , 123 , 124 , 125 , 126 , 127 , 128 , 129 , 130 , 131 , 132 , 133 , 134 , 135 , 136 , 137 , 138 , 139 , 140 , 141 , 142 , 143 ,
76 , 77 , 78 , 79 ,
144 ,
4 , 5 , 6 , 7 ,
} ;
2023-09-17 06:33:25 +00:00
// common CFG fuse address map for cfg18V10
2023-09-17 04:55:40 +00:00
// starting address: 3456
// total size 20
2023-10-05 05:23:55 +00:00
static const unsigned char cfg18V10 [ ] PROGMEM =
2023-09-17 04:55:40 +00:00
{
1 , 0 , 3 , 2 , 5 , 4 , 7 , 6 , 9 , 8 , 11 , 10 , 13 , 12 , 15 , 14 , 17 , 16 , 19 , 18
} ;
2023-11-22 03:48:09 +00:00
// common CFG fuse address map for cfg20RA10
// starting address: 3200
// total size 10
static const unsigned char cfgRA10 [ ] PROGMEM =
{
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9
} ;
2023-09-16 06:20:12 +00:00
// common CFG fuse address map for cfg20XV10
// starting address: 1600
// total size 31
2023-10-05 05:23:55 +00:00
static const unsigned char cfgXV10 [ ] PROGMEM =
2023-09-16 06:20:12 +00:00
{
30 ,
28 , 29 ,
20 , 21 , 22 ,
10 , 11 , 12 , 13 , 14 ,
0 , 1 , 2 , 3 , 4 ,
27 , 26 ,
23 , 24 , 25 ,
19 , 18 , 17 , 16 , 15 ,
9 , 8 , 7 , 6 , 5
} ;
2019-03-16 10:53:19 +00:00
// common CFG fuse address map for cfg22V10
// starting address: 5808
2023-03-25 19:53:13 +00:00
// total size 20
2023-10-02 21:22:09 +00:00
static const unsigned char cfgV10 [ ] PROGMEM =
2019-03-16 10:53:19 +00:00
{
1 , 0 , 3 , 2 , 5 , 4 , 7 , 6 , 9 , 8 , 11 , 10 , 13 , 12 , 15 , 14 , 17 , 16 , 19 , 18 ,
} ;
2023-10-30 13:10:28 +00:00
// common CFG fuse address map for cfg26CV12
// starting address: 6344
// total size 24
static const unsigned char cfg26CV12 [ ] PROGMEM =
{
1 , 0 , 3 , 2 , 5 , 4 , 7 , 6 , 9 , 8 , 11 , 10 , 13 , 12 , 15 , 14 , 17 , 16 , 19 , 18 , 21 , 20 , 23 , 22
} ;
// common CFG fuse address map for cfg26V12
// starting address: 7800
// total size 48
static const unsigned char cfg26V12 [ ] PROGMEM =
{
36 , 24 , 12 , 0 , 37 , 25 , 13 , 1 , 38 , 26 , 14 , 2 , 39 , 27 , 15 , 3 ,
40 , 28 , 16 , 4 , 41 , 29 , 17 , 5 , 42 , 30 , 18 , 6 , 43 , 31 , 19 , 7 ,
44 , 32 , 20 , 8 , 45 , 33 , 21 , 9 , 46 , 34 , 22 , 10 , 47 , 35 , 23 , 11
} ;
2023-09-22 15:32:15 +00:00
// common CFG fuse address map for cfg6001
// starting address: 8154
// total size 68
2023-10-02 21:22:09 +00:00
static const unsigned char cfg6001 [ ] PROGMEM =
2023-09-22 15:32:15 +00:00
{
67 , 66 ,
25 , 29 , 33 , 37 , 41 , 45 , 49 , 53 , 57 , 61 ,
60 , 56 , 52 , 48 , 44 , 40 , 36 , 32 , 28 , 24 ,
62 , 63 , 58 , 59 , 54 , 55 , 50 , 51 , 46 , 47 ,
42 , 43 , 38 , 39 , 34 , 35 , 30 , 31 , 26 , 27 ,
2 , 5 , 8 , 11 , 14 , 17 , 20 , 23 ,
0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 ,
22 , 19 , 16 , 13 , 10 , 7 , 4 , 1 ,
64 , 65
} ;
// common CFG fuse address map for cfg6002
// starting address: 8154
// total size 104
2023-10-02 21:22:09 +00:00
static const unsigned char cfg6002 [ ] PROGMEM =
2023-09-22 15:32:15 +00:00
{
103 , 102 ,
25 , 29 , 33 , 37 , 41 , 45 , 49 , 53 , 57 , 61 ,
60 , 56 , 52 , 48 , 44 , 40 , 36 , 32 , 28 , 24 ,
62 , 63 , 58 , 59 , 54 , 55 , 50 , 51 , 46 , 47 ,
42 , 43 , 38 , 39 , 34 , 35 , 30 , 31 , 26 , 27 ,
101 , 100 , 99 , 98 , 97 , 96 , 95 , 94 , 93 ,
92 , 91 , 90 , 89 , 88 , 87 , 86 , 85 , 84 ,
66 , 67 , 68 , 69 , 70 , 71 , 72 , 73 , 74 ,
75 , 76 , 77 , 78 , 79 , 80 , 81 , 82 , 83 ,
2 , 5 , 8 , 11 , 14 , 17 , 20 , 23 ,
0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 ,
22 , 19 , 16 , 13 , 10 , 7 , 4 , 1 ,
64 , 65
} ;
2023-12-09 10:56:24 +00:00
// TODO: handle those:
/*
30 , // 75: Security?
135 , // 70: Powerdown
136 , // 71: PinKeeper
137 , // 72: reserved1
138 , // 73: reserved2
139 , // 74: reserved3
*/
static const uint8_t cfgV750 [ ] PROGMEM = {
0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 , 24 , 27 , // S0
1 , 4 , 7 , 10 , 13 , 16 , 19 , 22 , 25 , 28 , // S1
2 , 5 , 8 , 11 , 14 , 17 , 20 , 23 , 26 , 29 , // S2
31 , 35 , 39 , 43 , 47 , 51 , 55 , 59 , 63 , 67 , // S3
32 , 36 , 40 , 44 , 48 , 52 , 56 , 60 , 64 , 68 , // S4
33 , 37 , 41 , 45 , 49 , 53 , 57 , 61 , 65 , 69 , // S5
34 , 38 , 42 , 46 , 50 , 54 , 58 , 62 , 66 , 70 // S6
} ;
2019-03-16 10:53:19 +00:00
// UES user electronic signature
// PES programmer electronic signature (ATF = text string, others = Vendor/Vpp/timing)
// cfg configuration bits for OLMCs
// GAL info
2023-11-22 00:31:08 +00:00
typedef struct
2019-03-16 10:53:19 +00:00
{
GALTYPE type ;
unsigned char id0 , id1 ; /* variant 1, variant 2 (eg. 16V8=0x00, 16V8A+=0x1A)*/
short fuses ; /* total number of fuses */
char pins ; /* number of pins on chip */
char rows ; /* number of fuse rows */
unsigned char bits ; /* number of fuses per row */
char uesrow ; /* UES row number */
short uesfuse ; /* first UES fuse number */
char uesbytes ; /* number of UES bytes */
char eraserow ; /* row adddeess for erase */
2023-03-21 20:07:52 +00:00
char eraseallrow ; /* row address for erase all (also PES) */
2019-03-16 10:53:19 +00:00
char pesrow ; /* row address for PES read/write */
char pesbytes ; /* number of PES bytes */
2023-03-21 20:07:52 +00:00
char cfgrow ; /* row address of config bits (ACW) */
2019-03-16 10:53:19 +00:00
unsigned short cfgbase ; /* base address of the config bit numbers */
const unsigned char * cfg ; /* pointer to config bit numbers */
unsigned char cfgbits ; /* number of config bits */
2019-04-09 18:56:49 +00:00
unsigned char cfgmethod ; /* strobe or set row for reading config */
2023-10-30 13:10:28 +00:00
PINOUT pinout ;
2023-11-22 00:31:08 +00:00
} galinfo_t ;
const static galinfo_t galInfoList [ ] PROGMEM =
2019-03-16 10:53:19 +00:00
{
2023-12-09 10:56:24 +00:00
// +fuses +bits +uesbytes +pesrow +cfgbase
2023-11-21 08:17:20 +00:00
// | +pins | +uesrow | +eraserow| +pesbytes | +cfg
// +-- type + id0 + id1 | | +rows | | +uesfuse | +eraseallrow +cfgrow | | + cfgbits +cfgmethod +pinout
// | | | | | | | | | | | | | | | | | | | |
{ UNKNOWN , 0x00 , 0x00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 8 , 0 , 0 , NULL , 0 , 0 , PINOUT_UNKNOWN } ,
{ GAL16V8 , 0x00 , 0x1A , 2194 , 20 , 32 , 64 , 32 , 2056 , 8 , 63 , 62 , 58 , 8 , 60 , CFG_BASE_16 , cfgV8AB , sizeof ( cfgV8AB ) , CFG_STROBE_ROW , PINOUT_16V8 } ,
{ GAL18V10 , 0x50 , 0x51 , 3540 , 20 , 36 , 96 , 44 , 3476 , 8 , 61 , 60 , 58 , 10 , 16 , CFG_BASE_18 , cfg18V10 , sizeof ( cfg18V10 ) , CFG_SET_ROW , PINOUT_18V10 } ,
{ GAL20V8 , 0x20 , 0x3A , 2706 , 24 , 40 , 64 , 40 , 2568 , 8 , 63 , 62 , 58 , 8 , 60 , CFG_BASE_20 , cfgV8AB , sizeof ( cfgV8AB ) , CFG_STROBE_ROW , PINOUT_20V8 } ,
2023-11-22 03:48:09 +00:00
{ GAL20RA10 , 0x60 , 0x61 , 3274 , 24 , 40 , 80 , 40 , 3210 , 8 , 61 , 60 , 58 , 10 , 16 , CFG_BASE_20RA , cfgRA10 , sizeof ( cfgRA10 ) , CFG_SET_ROW , PINOUT_22V10 } ,
2023-11-21 08:17:20 +00:00
{ GAL20XV10 , 0x65 , 0x66 , 1671 , 24 , 40 , 40 , 44 , 1631 , 5 , 61 , 60 , 58 , 5 , 16 , CFG_BASE_20XV , cfgXV10 , sizeof ( cfgXV10 ) , CFG_SET_ROW , PINOUT_22V10 } ,
2023-10-30 13:10:28 +00:00
{ GAL22V10 , 0x48 , 0x49 , 5892 , 24 , 44 , 132 , 44 , 5828 , 8 , 61 , 62 , 58 , 10 , 16 , CFG_BASE_22 , cfgV10 , sizeof ( cfgV10 ) , CFG_SET_ROW , PINOUT_22V10 } ,
{ GAL26CV12 , 0x58 , 0x59 , 6432 , 28 , 52 , 122 , 52 , 6368 , 8 , 61 , 60 , 58 , 12 , 16 , CFG_BASE_26CV , cfg26CV12 , sizeof ( cfg26CV12 ) , CFG_SET_ROW , PINOUT_22V10 } ,
2023-10-30 13:25:08 +00:00
{ GAL26V12 , 0x5D , 0x5D , 7912 , 28 , 52 , 150 , 52 , 7848 , 8 , 61 , 60 , 58 , 12 , 16 , CFG_BASE_26V , cfg26V12 , sizeof ( cfg26V12 ) , CFG_SET_ROW , PINOUT_22V10 } ,
2023-10-30 13:10:28 +00:00
{ GAL6001 , 0x40 , 0x41 , 8294 , 24 , 78 , 75 , 97 , 8222 , 9 , 63 , 62 , 96 , 8 , 8 , CFG_BASE_600 , cfg6001 , sizeof ( cfg6001 ) , CFG_SET_ROW , PINOUT_600 } ,
{ GAL6002 , 0x44 , 0x44 , 8330 , 24 , 78 , 75 , 97 , 8258 , 9 , 63 , 62 , 96 , 8 , 8 , CFG_BASE_600 , cfg6002 , sizeof ( cfg6002 ) , CFG_SET_ROW , PINOUT_600 } ,
{ ATF16V8B , 0x00 , 0x00 , 2194 , 20 , 32 , 64 , 32 , 2056 , 8 , 63 , 62 , 58 , 8 , 60 , CFG_BASE_16 , cfgV8AB , sizeof ( cfgV8AB ) , CFG_STROBE_ROW , PINOUT_16V8 } ,
{ ATF20V8B , 0x00 , 0x00 , 2706 , 24 , 40 , 64 , 40 , 2568 , 8 , 63 , 62 , 58 , 8 , 60 , CFG_BASE_20 , cfgV8AB , sizeof ( cfgV8AB ) , CFG_STROBE_ROW , PINOUT_20V8 } ,
{ ATF22V10B , 0x00 , 0x00 , 5892 , 24 , 44 , 132 , 44 , 5828 , 8 , 61 , 62 , 58 , 10 , 16 , CFG_BASE_22 , cfgV10 , sizeof ( cfgV10 ) , CFG_SET_ROW , PINOUT_22V10 } ,
{ ATF22V10C , 0x00 , 0x00 , 5892 , 24 , 44 , 132 , 44 , 5828 , 8 , 61 , 62 , 58 , 10 , 16 , CFG_BASE_22 , cfgV10 , sizeof ( cfgV10 ) , CFG_SET_ROW , PINOUT_22V10 } ,
2023-12-09 10:56:24 +00:00
{ ATF750C , 0x00 , 0x00 , 14499 , 24 , 84 , 171 , 84 , 14435 , 8 , 61 , 60 , 127 , 10 , 16 , CFG_BASE_750 , cfgV750 , sizeof ( cfgV750 ) , CFG_STROBE_ROW2 , PINOUT_22V10 } , // TODO: not all numbers are clear
2019-03-16 10:53:19 +00:00
} ;
2023-11-22 00:31:08 +00:00
galinfo_t galinfo __attribute__ ( ( section ( " .noinit " ) ) ) ; //preserve data between resets
2019-03-16 10:53:19 +00:00
2023-12-09 10:56:24 +00:00
# ifdef RAM_BIG
// for ATF750C
// MAXFUSES = (((171 * 84 bits) + uesbits + (10*3 + 1 + 10*4 + 5)) + 7) / 8
// (14504 + 7) / 8 = 1813
# define MAXFUSES 1813
# else
// Boards with small RAM (< 2.5kB) do not support ATF750C
2023-09-22 15:32:15 +00:00
// MAXFUSES calculated as the biggest required space to hold the fuse bitmap
// MAXFUSES = GAL6002 8330 bits = 8330/8 = 1041.25 bytes rounded up to 1042 bytes
2023-12-10 16:13:14 +00:00
//#define MAXFUSES 1042
2024-02-02 08:58:48 +00:00
//extra space added for sparse fusemap (just enough to fit erased ATF750C)
# define MAXFUSES 1332
2023-12-10 16:13:14 +00:00
# define USE_SPARSE_FUSEMAP
2023-12-09 10:56:24 +00:00
# endif
2019-03-16 10:53:19 +00:00
2023-12-10 16:13:14 +00:00
2023-11-22 00:31:08 +00:00
GALTYPE gal __attribute__ ( ( section ( " .noinit " ) ) ) ; //the gal device index pointing to galInfoList, value is preserved between resets
2022-03-30 21:14:32 +00:00
2023-03-27 20:58:14 +00:00
static short erasetime = 100 , progtime = 100 ;
static uint8_t vpp = 0 ;
2019-03-16 10:53:19 +00:00
char echoEnabled ;
unsigned char pes [ 12 ] ;
2023-10-03 12:02:43 +00:00
char line [ 32 ] ;
2019-03-16 10:53:19 +00:00
short lineIndex ;
char endOfLine ;
char mapUploaded ;
char isUploading ;
2019-04-09 18:56:49 +00:00
char uploadError ;
2019-03-16 10:53:19 +00:00
unsigned char fusemap [ MAXFUSES ] ;
2023-03-21 19:58:40 +00:00
unsigned char flagBits ;
2023-03-27 20:58:14 +00:00
char varVppExists ;
2023-09-17 04:55:40 +00:00
uint8_t lastShiftRegVal = 0 ;
2019-03-16 10:53:19 +00:00
static void setFuseBit ( unsigned short bitPos ) ;
static unsigned short checkSum ( unsigned short n ) ;
static char checkGalTypeViaPes ( void ) ;
static void turnOff ( void ) ;
2019-04-09 18:56:49 +00:00
static void printFormatedNumberHex2 ( unsigned char num ) ;
2019-03-16 10:53:19 +00:00
2023-03-27 20:58:14 +00:00
# include "aftb_vpp.h"
2023-12-10 16:13:14 +00:00
# include "aftb_sparse.h"
2023-03-27 20:58:14 +00:00
2019-03-16 10:53:19 +00:00
// print some help on the serial console
void printHelp ( char full ) {
Serial . println ( F ( " AFTerburner v. " VERSION ) ) ;
2023-03-27 20:58:14 +00:00
// indication for PC software that the new board desgin is used
if ( varVppExists ) {
Serial . println ( F ( " varVpp " ) ) ;
}
2023-12-09 10:56:24 +00:00
# ifdef RAM_BIG
Serial . println ( F ( " RAM-BIG " ) ) ;
# endif
2019-03-16 10:53:19 +00:00
if ( ! full ) {
Serial . println ( F ( " type 'h' for help " ) ) ;
return ;
}
Serial . println ( F ( " commands: " ) ) ;
Serial . println ( F ( " h - print help " ) ) ;
Serial . println ( F ( " e - toggle echo " ) ) ;
Serial . println ( F ( " p - read & print PES " ) ) ;
Serial . println ( F ( " r - read & print fuses " ) ) ;
Serial . println ( F ( " u - upload fuses " ) ) ;
Serial . println ( F ( " w - write uploaded fuses " ) ) ;
Serial . println ( F ( " v - verify fuses " ) ) ;
Serial . println ( F ( " c - erase chip " ) ) ;
2023-03-27 20:58:14 +00:00
Serial . println ( F ( " t - test & set VPP " ) ) ;
Serial . println ( F ( " b - calibrate VPP " ) ) ;
Serial . println ( F ( " m - measure VPP " ) ) ;
2019-03-16 10:53:19 +00:00
}
2023-03-21 19:58:40 +00:00
static void setFlagBit ( uint8_t flag , uint8_t value ) {
if ( value ) {
flagBits | = flag ;
} else {
flagBits & = ~ flag ;
}
}
2023-03-27 20:58:14 +00:00
static void setPinMux ( uint8_t pm ) {
2024-03-22 07:14:51 +00:00
// ensure pull-up is enabled during reading and disabled when inactive on DOUT pin
uint8_t doutMode = pm = = OUTPUT ? INPUT_PULLUP : INPUT ;
2023-03-27 20:58:14 +00:00
switch ( gal ) {
case GAL16V8 :
case ATF16V8B :
pinMode ( PIN_ZIF10 , INPUT ) ; //GND via MOSFET
pinMode ( PIN_ZIF11 , INPUT ) ;
pinMode ( PIN_ZIF13 , INPUT ) ;
pinMode ( PIN_ZIF14 , INPUT ) ;
2024-03-22 07:14:51 +00:00
pinMode ( PIN_ZIF16 , doutMode ) ; //DOUT
2023-03-27 20:58:14 +00:00
// ensure ZIF10 is Grounded via transistor
digitalWrite ( PIN_ZIF_GND_CTRL , pm = = OUTPUT ? HIGH : LOW ) ;
break ;
2023-09-17 04:55:40 +00:00
case GAL18V10 :
pinMode ( PIN_ZIF10 , INPUT ) ; //GND via MOSFET
pinMode ( PIN_ZIF11 , INPUT ) ;
pinMode ( PIN_ZIF13 , INPUT ) ;
pinMode ( PIN_ZIF14 , INPUT ) ;
2024-03-22 07:14:51 +00:00
pinMode ( PIN_ZIF9 , doutMode ) ; //DOUT
2023-09-17 04:55:40 +00:00
// ensure ZIF10 is Grounded via transistor
digitalWrite ( PIN_ZIF_GND_CTRL , pm = = OUTPUT ? HIGH : LOW ) ;
2023-09-17 06:01:00 +00:00
//pull down unused pins
pinMode ( PIN_ZIF15 , pm ) ;
pinMode ( PIN_ZIF16 , pm ) ;
digitalWrite ( PIN_ZIF15 , LOW ) ;
digitalWrite ( PIN_ZIF16 , LOW ) ;
2023-09-17 04:55:40 +00:00
break ;
2023-03-27 20:58:14 +00:00
case GAL20V8 :
2023-10-30 14:13:25 +00:00
case ATF20V8B :
2023-03-27 20:58:14 +00:00
pinMode ( PIN_ZIF10 , pm ) ;
pinMode ( PIN_ZIF11 , pm ) ;
pinMode ( PIN_ZIF13 , pm ) ;
2023-04-01 22:10:12 +00:00
pinMode ( PIN_ZIF14 , pm ) ;
2024-03-22 07:14:51 +00:00
pinMode ( PIN_ZIF15 , doutMode ) ; //DOUT
2023-03-27 20:58:14 +00:00
pinMode ( PIN_ZIF16 , pm ) ;
// ensure ZIF10 GND pull is disabled
digitalWrite ( PIN_ZIF_GND_CTRL , LOW ) ;
//pull down unused pins
digitalWrite ( PIN_ZIF14 , LOW ) ;
digitalWrite ( PIN_ZIF16 , LOW ) ;
digitalWrite ( PIN_ZIF23 , LOW ) ;
break ;
2023-11-22 03:48:09 +00:00
case GAL20RA10 :
2023-09-16 06:20:12 +00:00
case GAL20XV10 :
2023-03-27 20:58:14 +00:00
case GAL22V10 :
2023-10-30 13:10:28 +00:00
case GAL26CV12 :
case GAL26V12 :
2023-03-27 20:58:14 +00:00
case ATF22V10B :
case ATF22V10C :
2023-12-09 10:56:24 +00:00
case ATF750C :
2023-03-27 20:58:14 +00:00
pinMode ( PIN_ZIF10 , pm ) ;
pinMode ( PIN_ZIF11 , pm ) ;
pinMode ( PIN_ZIF13 , pm ) ;
2024-03-22 07:14:51 +00:00
pinMode ( PIN_ZIF14 , doutMode ) ; //DOUT
2023-03-27 20:58:14 +00:00
pinMode ( PIN_ZIF15 , pm ) ;
pinMode ( PIN_ZIF16 , pm ) ;
// ensure ZIF10 GND pull is disabled
digitalWrite ( PIN_ZIF_GND_CTRL , LOW ) ;
//pull down unused pins
digitalWrite ( PIN_ZIF15 , LOW ) ;
digitalWrite ( PIN_ZIF16 , LOW ) ;
digitalWrite ( PIN_ZIF22 , LOW ) ;
2023-09-22 15:32:15 +00:00
digitalWrite ( PIN_ZIF23 , LOW ) ;
break ;
case GAL6001 :
case GAL6002 :
pinMode ( PIN_ZIF10 , pm ) ;
pinMode ( PIN_ZIF11 , pm ) ;
pinMode ( PIN_ZIF13 , pm ) ;
2024-03-22 07:14:51 +00:00
pinMode ( PIN_ZIF14 , doutMode ) ; //DOUT
2023-09-22 15:32:15 +00:00
pinMode ( PIN_ZIF15 , pm ) ;
pinMode ( PIN_ZIF16 , pm ) ;
// ensure ZIF10 GND pull is disabled
digitalWrite ( PIN_ZIF_GND_CTRL , LOW ) ;
//pull down unused pins
digitalWrite ( PIN_ZIF3 , LOW ) ;
digitalWrite ( PIN_ZIF15 , LOW ) ;
digitalWrite ( PIN_ZIF16 , LOW ) ;
2023-03-27 20:58:14 +00:00
digitalWrite ( PIN_ZIF22 , LOW ) ;
break ;
2023-09-22 15:32:15 +00:00
2023-03-27 20:58:14 +00:00
}
}
2023-03-21 19:58:40 +00:00
2023-01-24 20:17:49 +00:00
static void setupGpios ( uint8_t pm ) {
// Serial input of the GAL chip, output from Arduino
pinMode ( PIN_SDIN , pm ) ;
pinMode ( PIN_STROBE , pm ) ;
pinMode ( PIN_PV , pm ) ;
pinMode ( PIN_RA0 , pm ) ;
pinMode ( PIN_RA1 , pm ) ;
pinMode ( PIN_RA2 , pm ) ;
pinMode ( PIN_RA3 , pm ) ;
pinMode ( PIN_RA4 , pm ) ;
pinMode ( PIN_RA5 , pm ) ;
pinMode ( PIN_SCLK , pm ) ;
pinMode ( PIN_VPP , pm ) ;
2023-03-27 20:58:14 +00:00
if ( varVppExists ) {
pinMode ( PIN_ZIF_GND_CTRL , OUTPUT ) ;
//disconnect shift register pins (High Z) when pm == Input
digitalWrite ( PIN_SHR_EN , pm = = INPUT ? HIGH : LOW ) ;
setPinMux ( pm ) ;
}
}
# define SHR_SET_BIT(X) digitalWrite(PIN_SHR_CLK, 0); \
digitalWrite ( PIN_SHR_DAT , ( X ) ? HIGH : LOW ) ; \
digitalWrite ( PIN_SHR_CLK , 1 )
static void setShiftReg ( uint8_t val ) {
2023-09-17 04:55:40 +00:00
lastShiftRegVal = val ;
2023-03-27 20:58:14 +00:00
//assume CS is high
//ensure CLK is high (might be set low by other SPI devices)
digitalWrite ( PIN_SHR_CLK , 1 ) ;
// set CS low
digitalWrite ( PIN_SHR_CS , 0 ) ;
SHR_SET_BIT ( val & 0 b10000000 ) ;
SHR_SET_BIT ( val & 0 b1000000 ) ;
SHR_SET_BIT ( val & 0 b100000 ) ;
SHR_SET_BIT ( val & 0 b10000 ) ;
SHR_SET_BIT ( val & 0 b1000 ) ;
SHR_SET_BIT ( val & 0 b100 ) ;
SHR_SET_BIT ( val & 0 b10 ) ;
SHR_SET_BIT ( val & 0 b1 ) ;
digitalWrite ( PIN_SHR_CS , 1 ) ;
2023-01-24 20:17:49 +00:00
}
2019-03-16 10:53:19 +00:00
// setup the Arduino board
void setup ( ) {
// initialize serial:
2022-04-01 21:15:43 +00:00
Serial . begin ( 57600 ) ;
2019-03-16 10:53:19 +00:00
isUploading = 0 ;
endOfLine = 0 ;
echoEnabled = 0 ;
mapUploaded = 0 ;
2023-03-21 20:48:47 +00:00
lineIndex = 0 ;
2023-03-21 19:58:40 +00:00
setFlagBit ( FLAG_BIT_TYPE_CHECK , 1 ) ; //do type check
2019-03-16 10:53:19 +00:00
2023-03-27 20:58:14 +00:00
//check & initialise variable voltage (old / new board design)
varVppExists = varVppInit ( ) ;
// shift register
pinMode ( PIN_SHR_EN , OUTPUT ) ;
2019-03-16 10:53:19 +00:00
// Serial output from the GAL chip, input for Arduino
pinMode ( PIN_SDOUT , INPUT ) ;
2023-01-24 20:17:49 +00:00
// Set all GPIO pins to Input to prevent accidents when
// inserting the GAL IC into socket.
setupGpios ( INPUT ) ;
2019-03-16 10:53:19 +00:00
printHelp ( 0 ) ;
2023-03-27 20:58:14 +00:00
if ( varVppExists ) {
// reads the calibration values
if ( varVppCheckCalibration ( ) ) {
Serial . println ( F ( " I: VPP calib. OK " ) ) ;
}
// set shift reg Chip select
pinMode ( PIN_SHR_CS , OUTPUT ) ;
digitalWrite ( PIN_SHR_CS , 1 ) ; //unselect the POT's SPI bus
}
2019-03-16 10:53:19 +00:00
Serial . println ( " > " ) ;
}
2024-02-04 23:36:45 +00:00
static void sparseSetup ( char clearArray ) {
2023-12-10 16:13:14 +00:00
// Note: Sparse fuse map is ignored on MCUs with big SRAM
2024-02-04 23:36:45 +00:00
if ( gal = = ATF750C ) {
sparseInit ( clearArray ) ;
2023-12-10 16:13:14 +00:00
} else {
sparseDisable ( ) ;
}
2023-11-22 00:31:08 +00:00
}
2019-03-16 10:53:19 +00:00
2024-02-04 23:36:45 +00:00
//copy galinfo item from the flash array into RAM backed struct
static void copyGalInfo ( void ) {
memcpy_P ( & galinfo , & galInfoList [ gal ] , sizeof ( galinfo_t ) ) ;
sparseSetup ( 0 ) ;
}
2019-03-16 10:53:19 +00:00
// read from serial line and discard the data
void readGarbage ( ) {
while ( Serial . available ( ) > 0 ) {
Serial . read ( ) ;
}
}
// Reads input from the serial terminal and returns the command
// which is the first character of the entered text.
char handleTerminalCommands ( ) {
char c ;
while ( Serial . available ( ) > 0 ) {
c = Serial . read ( ) ;
line [ lineIndex ] = c ;
if ( c = = ' \n ' | | c = = ' \r ' ) {
endOfLine = 1 ;
}
//echo input to output
else {
if ( ! isUploading & & echoEnabled ) {
Serial . print ( c ) ;
}
}
2023-10-02 21:22:09 +00:00
if ( lineIndex > = sizeof ( line ) - 2 ) {
2019-03-16 10:53:19 +00:00
lineIndex = 0 ;
readGarbage ( ) ;
Serial . println ( ) ;
2023-10-03 11:45:38 +00:00
Serial . println ( F ( " Error: line too long. " ) ) ;
2019-03-16 10:53:19 +00:00
} else {
lineIndex + + ;
}
}
if ( endOfLine ) {
c = COMMAND_NONE ;
//single letter command entered
if ( lineIndex = = 2 ) {
c = line [ 0 ] ;
} else if ( lineIndex > 2 ) {
c = line [ 0 ] ;
if ( ! isUploading | | c ! = ' # ' ) {
2023-03-27 20:58:14 +00:00
// prevent 2 character commands from being flagged as invalid
if ( ! ( c = = COMMAND_SET_GAL_TYPE | | c = = COMMAND_CALIBRATION_OFFSET ) ) {
2019-04-09 18:56:49 +00:00
c = COMMAND_UNKNOWN ;
}
2019-03-16 10:53:19 +00:00
}
}
if ( ! isUploading ) {
Serial . println ( ) ;
line [ lineIndex ] = 0 ;
lineIndex = 0 ;
}
endOfLine = 0 ;
return c ;
}
return COMMAND_NONE ;
}
2024-02-02 08:58:48 +00:00
// Parses decimal integer number typed as 4 or 5 digits.
2019-03-16 10:53:19 +00:00
// Returns the number value.
2024-02-02 08:58:48 +00:00
unsigned short parse45dec ( char i , char five ) {
unsigned short v = 0 ;
if ( five ) { //containts 5 digits
v = ( line [ i + + ] - ' 0 ' ) * 10000 ;
}
v + = ( line [ i + + ] - ' 0 ' ) * 1000 ;
2019-03-16 10:53:19 +00:00
v + = ( line [ i + + ] - ' 0 ' ) * 100 ;
v + = ( line [ i + + ] - ' 0 ' ) * 10 ;
v + = line [ i ] - ' 0 ' ;
return v ;
}
// Converts textual hex value 0-9, A-F to a number.
unsigned char toHex ( char c ) {
if ( c > = ' 0 ' & & c < = ' 9 ' ) return c - ' 0 ' ;
if ( c > = ' A ' & & c < = ' F ' ) return c - ' A ' + 10 ;
if ( c > = ' a ' & & c < = ' f ' ) return c - ' a ' + 10 ;
return 0 ;
}
// Parses hexdecimal integer number typed as 2 digit.
// Returns the number value.
unsigned short parse2hex ( char i ) {
if ( line [ i ] = = ' \r ' | | line [ i ] = = 0 | | line [ i ] = = ' ' ) {
return - 1 ;
}
unsigned short v = toHex ( line [ i + + ] ) < < 4 ;
return v + toHex ( line [ i ] ) ;
}
// Parses hexdecimal integer number typed as 4 digit.
// Returns the number value.
unsigned short parse4hex ( char i ) {
2024-02-02 08:58:48 +00:00
unsigned short v ;
2019-03-16 10:53:19 +00:00
if ( line [ i ] = = ' \r ' | | line [ i ] = = 0 | | line [ i ] = = ' ' ) {
return - 1 ;
}
2024-02-02 08:58:48 +00:00
v = toHex ( line [ i + + ] ) ;
v < < = 4 ;
v | = toHex ( line [ i + + ] ) ;
v < < = 4 ;
v | = toHex ( line [ i + + ] ) ;
v < < = 4 ;
v | = toHex ( line [ i ] ) ;
return v ;
2019-03-16 10:53:19 +00:00
}
// Parses a line fed by the serial connection.
// This hnadles a primitive upload protocol that
// expects a programatic data feed - not suitable
// for human interaction.
// Data: each command on its own line
// line starts with '#' character followed by a command
// and a space. Then a command specific data follow.
// Commands:
// t <gal index>: gal type index to the GALTYPEE enum
// f <fuse index> <row>: row of fuse-map data starting on fuse bit index
// c <checksum> : checksum of the whole fuse map
// e : end ofthe upload transfer - returns to terminal
void parseUploadLine ( ) {
switch ( line [ 1 ] ) {
case ' e ' : {
2019-04-09 18:56:49 +00:00
if ( uploadError ) {
Serial . print ( F ( " ER upload failed " ) ) ;
} else {
Serial . print ( F ( " OK upload finished " ) ) ;
}
2019-03-16 10:53:19 +00:00
isUploading = 0 ;
} break ;
// gal type
case ' t ' : {
short v = line [ 3 ] - ' 0 ' ;
2019-04-09 18:56:49 +00:00
if ( v > 0 & & v < LAST_GAL_TYPE ) {
2019-03-16 10:53:19 +00:00
gal = ( GALTYPE ) v ;
2023-11-22 00:31:08 +00:00
copyGalInfo ( ) ;
2019-03-16 10:53:19 +00:00
Serial . print ( F ( " OK gal set: " ) ) ;
Serial . println ( ( short ) gal , DEC ) ;
} else {
Serial . println ( F ( " ER unknown gal index " ) ) ;
2019-04-09 18:56:49 +00:00
uploadError = 1 ;
2019-03-16 10:53:19 +00:00
}
} break ;
//fusemap data
case ' f ' : {
char i = 8 ;
char j ;
2024-02-02 08:58:48 +00:00
unsigned short addr ;
2019-03-16 10:53:19 +00:00
short v ;
2024-02-02 08:58:48 +00:00
char fiveDigitAddr = ( line [ 7 ] ! = ' ' ) ? 1 : 0 ;
addr = parse45dec ( 3 , fiveDigitAddr ) ;
i + = fiveDigitAddr ;
2019-03-16 10:53:19 +00:00
do {
v = parse2hex ( i ) ;
if ( v > = 0 ) {
for ( j = 0 ; j < 8 ; j + + ) {
// if fuse bit is set -> then change the fusemap
if ( v & ( 1 < < j ) ) {
setFuseBit ( addr ) ;
}
addr + + ;
}
i + = 2 ;
}
} while ( v > = 0 ) ;
//any fuse being set is considered as uploaded fuse map
mapUploaded = 1 ;
Serial . print ( F ( " OK " ) ) ;
Serial . println ( ( short ) addr , DEC ) ;
} break ;
//checksum
case ' c ' : {
unsigned short val = parse4hex ( 3 ) ;
2023-03-25 19:53:13 +00:00
unsigned char apdFuse = ( flagBits & FLAG_BIT_APD ) ? 1 : 0 ;
2023-11-22 00:31:08 +00:00
unsigned short cs = checkSum ( galinfo . fuses + apdFuse ) ;
2019-03-16 10:53:19 +00:00
if ( cs = = val ) {
2019-04-09 18:56:49 +00:00
Serial . println ( F ( " OK checksum matches " ) ) ;
2023-03-27 20:58:14 +00:00
// Conditioning jed files might not have any fuse set, so as long as
// they supply empty checksum (C0000) the upload is OK.
mapUploaded = 1 ;
2019-03-16 10:53:19 +00:00
} else {
2019-04-09 18:56:49 +00:00
uploadError = 1 ;
2019-03-16 10:53:19 +00:00
Serial . print ( F ( " ER checksum: " ) ) ;
Serial . print ( cs , HEX ) ;
Serial . print ( F ( " expected: " ) ) ;
Serial . println ( val , HEX ) ;
}
} break ;
2023-03-30 22:00:21 +00:00
// PES
case ' p ' : {
uint8_t i = 0 ;
uint8_t j = 3 ;
while ( i < 8 ) {
pes [ i ] = parse2hex ( j ) ;
i + + ;
j + = 3 ; //AB:00:... - 3 characters per one PES byte
}
} break ;
2019-04-09 18:56:49 +00:00
default :
uploadError = 1 ;
Serial . println ( F ( " ER unknown upload cmd " ) ) ;
2019-03-16 10:53:19 +00:00
}
lineIndex = 0 ;
}
// *********************************************************
// set/reset individual pins of GAL
static void setVCC ( char on ) {
//no control for turning the voltage on of
//it is assumed the voltage is always on
}
static void setVPP ( char on ) {
2023-03-27 20:58:14 +00:00
// new board desgin
if ( varVppExists ) {
uint8_t v = VPP_11V0 ;
// when PES is read the VPP is not determined via PES
if ( on = = READPES ) {
2023-12-09 10:56:24 +00:00
if ( gal = = ATF16V8B | | gal = = ATF20V8B | | gal = = ATF22V10B | | gal = = ATF22V10C | | gal = = ATF750C ) {
2024-02-16 19:26:17 +00:00
v = VPP_10V5 ;
2023-03-27 20:58:14 +00:00
} else {
v = VPP_11V5 ;
}
2023-12-09 10:56:24 +00:00
#if 0
Serial . print ( F ( " VPP index= " ) ) ;
Serial . println ( v ) ;
# endif
2023-03-27 20:58:14 +00:00
} else {
//safety check
if ( vpp < 36 ) {
vpp = 36 ; //9V
} else
if ( vpp > 66 ) {
2024-02-16 19:26:17 +00:00
vpp = 48 ; //12V
2023-03-27 20:58:14 +00:00
}
v = ( vpp > > 1 ) - 18 ; // 18: 2 * 9V, resolution 0.5V (not 0.25V) hence 'vpp >> 1'
2023-12-09 10:56:24 +00:00
#if 0
2023-03-27 20:58:14 +00:00
Serial . print ( F ( " setVPP " ) ) ;
Serial . print ( vpp ) ;
Serial . print ( F ( " index= " ) ) ;
Serial . println ( v ) ;
2023-12-09 10:56:24 +00:00
# endif
2023-03-27 20:58:14 +00:00
}
varVppSet ( on ? v : VPP_5V0 ) ;
delay ( 50 ) ; //settle the voltage
}
// old board design
else {
//programming voltage is controlled by VPP_PIN,
//but the programming voltage must be set manually by user turning a Pot
digitalWrite ( PIN_VPP , on ? 1 : 0 ) ;
//Serial.print(F("VPP set to:"));
//Serial.println( on ? "12V": "5V");
delay ( 10 ) ;
}
2019-03-16 10:53:19 +00:00
2023-03-27 20:58:14 +00:00
}
2019-03-16 10:53:19 +00:00
static void setSTB ( char on ) {
2023-03-27 20:58:14 +00:00
if ( varVppExists ) {
2023-11-22 00:31:08 +00:00
const PINOUT p = galinfo . pinout ;
2023-09-17 04:55:40 +00:00
uint8_t pin = PIN_ZIF13 ;
2023-11-05 05:43:47 +00:00
if ( p = = PINOUT_16V8 ) {
2023-09-17 04:55:40 +00:00
pin = PIN_ZIF15 ;
} else
2023-11-05 05:43:47 +00:00
if ( p = = PINOUT_18V10 ) {
2023-09-17 04:55:40 +00:00
pin = PIN_ZIF8 ;
}
2023-03-27 20:58:14 +00:00
digitalWrite ( pin , on ? 1 : 0 ) ;
} else {
digitalWrite ( PIN_STROBE , on ? 1 : 0 ) ;
}
2019-03-16 10:53:19 +00:00
}
static void setPV ( char on ) {
2023-03-27 20:58:14 +00:00
if ( varVppExists ) {
2023-11-22 00:31:08 +00:00
const PINOUT p = galinfo . pinout ;
2023-03-27 20:58:14 +00:00
uint8_t pin = PIN_ZIF23 ;
2023-10-30 13:10:28 +00:00
if ( p = = PINOUT_22V10 ) {
2023-03-27 20:58:14 +00:00
pin = PIN_ZIF3 ;
} else
2023-10-30 13:10:28 +00:00
if ( p = = PINOUT_20V8 ) {
2023-03-27 20:58:14 +00:00
pin = PIN_ZIF22 ;
}
digitalWrite ( pin , on ? 1 : 0 ) ;
} else {
digitalWrite ( PIN_PV , on ? 1 : 0 ) ;
}
2019-03-16 10:53:19 +00:00
}
static void setSDIN ( char on ) {
2023-03-27 20:58:14 +00:00
if ( varVppExists ) {
2023-11-22 00:31:08 +00:00
const PINOUT p = galinfo . pinout ;
2023-11-05 05:43:47 +00:00
if ( p = = PINOUT_18V10 ) {
2023-09-17 04:55:40 +00:00
if ( on ) {
lastShiftRegVal | = PIN_ZIF7 ;
} else {
lastShiftRegVal & = ~ PIN_ZIF7 ;
}
setShiftReg ( lastShiftRegVal ) ;
} else {
2023-11-05 05:43:47 +00:00
const uint8_t pin = ( p = = PINOUT_16V8 ) ? PIN_ZIF9 : PIN_ZIF11 ;
2023-03-27 20:58:14 +00:00
digitalWrite ( pin , on ? 1 : 0 ) ;
2023-09-17 04:55:40 +00:00
}
2023-03-27 20:58:14 +00:00
} else {
digitalWrite ( PIN_SDIN , on ? 1 : 0 ) ;
}
2019-03-16 10:53:19 +00:00
}
static void setSCLK ( char on ) {
2023-03-27 20:58:14 +00:00
if ( varVppExists ) {
2023-11-22 00:31:08 +00:00
const PINOUT p = galinfo . pinout ;
2023-11-05 05:43:47 +00:00
if ( p = = PINOUT_18V10 ) {
2023-09-17 04:55:40 +00:00
if ( on ) {
lastShiftRegVal | = PIN_ZIF6 ;
} else {
lastShiftRegVal & = ~ PIN_ZIF6 ;
}
setShiftReg ( lastShiftRegVal ) ;
} else {
2023-11-05 05:43:47 +00:00
uint8_t pin = ( p = = PINOUT_16V8 ) ? PIN_ZIF8 : PIN_ZIF10 ;
2023-03-27 20:58:14 +00:00
digitalWrite ( pin , on ? 1 : 0 ) ;
2023-09-17 04:55:40 +00:00
}
2023-03-27 20:58:14 +00:00
} else {
digitalWrite ( PIN_SCLK , on ? 1 : 0 ) ;
}
2019-03-16 10:53:19 +00:00
}
// output row address (RA0-5)
static void setRow ( char row )
{
2023-03-27 20:58:14 +00:00
if ( varVppExists ) {
uint8_t srval = 0 ;
2023-11-22 00:31:08 +00:00
const PINOUT p = galinfo . pinout ;
2023-10-30 13:10:28 +00:00
if ( p = = PINOUT_16V8 ) {
2023-03-27 20:58:14 +00:00
digitalWrite ( PIN_ZIF22 , ( row & 0x1 ) ) ; //RA0
digitalWrite ( PIN_ZIF3 , ( row & 0x2 ) ) ; //RA1
if ( row & 0x4 ) srval | = PIN_ZIF4 ; //RA2
if ( row & 0x8 ) srval | = PIN_ZIF5 ; //RA3
if ( row & 0x10 ) srval | = PIN_ZIF6 ; //RA4
if ( row & 0x20 ) srval | = PIN_ZIF7 ; //RA5
} else
2023-10-30 13:10:28 +00:00
if ( p = = PINOUT_18V10 ) {
2023-09-17 04:55:40 +00:00
digitalWrite ( PIN_ZIF22 , ( row & 0x1 ) ) ; //RA0
if ( row & 0x2 ) srval | = PIN_ZIF21 ; //RA1
if ( row & 0x4 ) srval | = PIN_ZIF20 ; //RA2
digitalWrite ( PIN_ZIF3 , ( row & 0x8 ) ) ; //RA3
if ( row & 0x10 ) srval | = PIN_ZIF4 ; //RA4
if ( row & 0x20 ) srval | = PIN_ZIF5 ; //RA5
} else
2023-10-30 13:10:28 +00:00
if ( p = = PINOUT_22V10 | | p = = PINOUT_600 ) {
2023-03-27 20:58:14 +00:00
if ( row & 0x1 ) srval | = PIN_ZIF4 ; //RA0
if ( row & 0x2 ) srval | = PIN_ZIF5 ; //RA1
if ( row & 0x4 ) srval | = PIN_ZIF6 ; //RA2
if ( row & 0x8 ) srval | = PIN_ZIF7 ; //RA3
digitalWrite ( PIN_ZIF8 , ( row & 0x10 ) ) ; //RA4
digitalWrite ( PIN_ZIF9 , ( row & 0x20 ) ) ; //RA5
2023-10-30 13:10:28 +00:00
} else { //PINOUT_20V8
2023-03-27 20:58:14 +00:00
if ( row & 0x1 ) srval | = PIN_ZIF21 ; //RA0
digitalWrite ( PIN_ZIF3 , ( row & 0x2 ) ) ; //RA1
if ( row & 0x4 ) srval | = PIN_ZIF4 ; //RA2
if ( row & 0x8 ) srval | = PIN_ZIF5 ; //RA3
digitalWrite ( PIN_ZIF8 , ( row & 0x10 ) ) ; //RA4
digitalWrite ( PIN_ZIF9 , ( row & 0x20 ) ) ; //RA5
}
setShiftReg ( srval ) ;
} else {
digitalWrite ( PIN_RA0 , ( row & 0x1 ) ) ;
digitalWrite ( PIN_RA1 , ( ( row & 0x2 ) ? 1 : 0 ) ) ;
digitalWrite ( PIN_RA2 , ( ( row & 0x4 ) ? 1 : 0 ) ) ;
digitalWrite ( PIN_RA3 , ( ( row & 0x8 ) ? 1 : 0 ) ) ;
digitalWrite ( PIN_RA4 , ( ( row & 0x10 ) ? 1 : 0 ) ) ;
digitalWrite ( PIN_RA5 , ( ( row & 0x20 ) ? 1 : 0 ) ) ;
}
2019-03-16 10:53:19 +00:00
}
// serial data out form the GAL chip -> received by Arduino
static char getSDOUT ( void )
{
2023-03-27 20:58:14 +00:00
if ( varVppExists ) {
2023-11-22 00:31:08 +00:00
const PINOUT p = galinfo . pinout ;
2023-03-27 20:58:14 +00:00
uint8_t pin = PIN_ZIF16 ;
2023-10-30 13:10:28 +00:00
if ( p = = PINOUT_22V10 | | p = = PINOUT_600 ) {
2023-03-27 20:58:14 +00:00
pin = PIN_ZIF14 ;
} else
2023-10-30 13:10:28 +00:00
if ( p = = PINOUT_20V8 ) {
2023-03-27 20:58:14 +00:00
pin = PIN_ZIF15 ;
2023-09-17 04:55:40 +00:00
} else
2023-11-05 05:43:47 +00:00
if ( p = = PINOUT_18V10 ) {
2023-09-17 04:55:40 +00:00
pin = PIN_ZIF9 ;
2023-03-27 20:58:14 +00:00
}
return digitalRead ( pin ) ! = 0 ;
} else {
return digitalRead ( PIN_SDOUT ) ! = 0 ;
}
2019-03-16 10:53:19 +00:00
}
// GAL finish sequence
static void turnOff ( void )
{
delay ( 100 ) ;
setPV ( 0 ) ; // P/V- low
setRow ( 0x3F ) ; // RA0-5 high
setSDIN ( 1 ) ; // SDIN high
setVPP ( 0 ) ; // Vpp off (+12V)
setPV ( 1 ) ; // P/V- high
delay ( 2 ) ;
setVCC ( 0 ) ; // turn off VCC (if controlled)
2023-01-24 20:17:49 +00:00
setupGpios ( INPUT ) ;
2023-03-21 20:48:47 +00:00
delay ( 100 ) ; //ensure VPP is low
2019-03-16 10:53:19 +00:00
}
// GAL init sequence
static void turnOn ( char mode ) {
2023-01-24 20:17:49 +00:00
setupGpios ( OUTPUT ) ;
2019-03-16 10:53:19 +00:00
2023-03-27 20:58:14 +00:00
if ( mode = = READPES ) {
mode = 2 ;
} else
2019-03-16 10:53:19 +00:00
if (
mode = = WRITEGAL | |
mode = = ERASEGAL | |
mode = = ERASEALL | |
mode = = BURNSECURITY | |
mode = = WRITEPES | |
mode = = VPPTEST | |
mode = = READGAL
) {
mode = 1 ;
} else {
mode = 0 ;
}
// setVPP(mode);
setVPP ( 0 ) ; // VPP off
setPV ( 0 ) ; // P/V- low
setRow ( 0x3F ) ; // RA0-5 high - erase sequence ?
//setRow(0); // RA0-5 low
setSDIN ( 1 ) ; // SDIN high
setSCLK ( 1 ) ; // SCLK high
setSTB ( 1 ) ; // STB high
setVCC ( 1 ) ; // turn on VCC (if controlled)
delay ( 100 ) ;
setSCLK ( 0 ) ; // SCLK low
setVPP ( mode ) ;
delay ( 20 ) ;
}
// clock and receive a bit in from GAL SDOUT
static char receiveBit ( void )
{
char b = getSDOUT ( ) ;
setSCLK ( 1 ) ;
setSCLK ( 0 ) ;
return b ;
}
// read n number of bits
static void discardBits ( short n )
{
while ( n - - > 0 ) {
receiveBit ( ) ;
}
}
// clock a bit and send it out to GAL SDIN
2023-03-21 20:48:47 +00:00
static void sendBit ( char bitValue , char skipClkLow = 0 )
2019-03-16 10:53:19 +00:00
{
setSDIN ( bitValue ) ;
setSCLK ( 1 ) ;
2023-10-30 14:13:25 +00:00
// For some reason ATF20V8B needs a slower clock
if ( gal = = ATF20V8B ) {
delay ( 1 ) ;
}
2023-03-21 20:48:47 +00:00
if ( ! skipClkLow ) {
setSCLK ( 0 ) ;
}
2019-03-16 10:53:19 +00:00
}
// send n number of bits to GAL
static void sendBits ( short n , char bitValue )
{
2023-03-21 20:48:47 +00:00
char skipClkLow = flagBits & FLAG_BIT_ATF16V8C ;
2019-03-16 10:53:19 +00:00
while ( n - - > 0 ) {
2023-03-21 20:48:47 +00:00
sendBit ( bitValue , skipClkLow & & n = = 0 ) ;
2019-03-16 10:53:19 +00:00
}
}
// send row address bits to SDIN
// ATF22V10C MSb first, other 22V10 LSb first
static void sendAddress ( unsigned char n , unsigned char row )
{
switch ( gal ) {
case ATF22V10C :
while ( n - - > 1 ) {
sendBit ( row & 32 ) ; // clock in row number bits 5-1
row < < = 1 ;
}
setSDIN ( row & 32 ) ; // SDIN = row number bit 0
break ;
2023-12-09 10:56:24 +00:00
case ATF750C :
while ( n - - > 1 ) {
sendBit ( row & 1 ) ; // clock in row number bits 0-5
row > > = 1 ;
}
setSDIN ( row & 1 ) ; // SDIN = row number bit 6
break ;
2019-03-16 10:53:19 +00:00
default :
while ( n - - > 0 ) {
sendBit ( row & 1 ) ; // clock in row number bits 0-5
row > > = 1 ;
}
setSDIN ( 0 ) ; // SDIN = low
}
}
// pulse STB pin low for some milliseconds
static void strobe ( unsigned short msec )
{
setSTB ( 0 ) ;
delay ( msec ) ;
setSTB ( 1 ) ;
}
// 16V8, 20V8 RA0-5 = row address, strobe.
// 22V10 RA0-5 = 0, send row address (6 bits), strobe.
2023-03-21 20:48:47 +00:00
// setBit: 0 - do not set bit, 1- set bit value 0, 2 - set bit value 1
static void strobeRow ( char row , char setBit = BIT_NONE )
2019-03-16 10:53:19 +00:00
{
2023-12-09 10:56:24 +00:00
unsigned char nBits = 6 ;
2019-03-16 10:53:19 +00:00
switch ( gal ) {
case GAL16V8 :
case GAL20V8 :
2023-10-30 14:13:25 +00:00
case ATF20V8B :
2019-03-16 10:53:19 +00:00
case ATF16V8B :
setRow ( row ) ; // set RA0-5 to row number
2023-03-21 20:48:47 +00:00
if ( setBit ) {
sendBits ( 1 , setBit - 1 ) ;
2023-03-27 20:58:14 +00:00
}
2019-03-16 10:53:19 +00:00
strobe ( 2 ) ; // pulse /STB for 2ms
break ;
2023-12-09 10:56:24 +00:00
case ATF750C :
nBits = 7 ;
//fall through
2023-09-17 04:55:40 +00:00
case GAL18V10 :
2023-11-22 03:48:09 +00:00
case GAL20RA10 :
2023-09-16 06:20:12 +00:00
case GAL20XV10 :
2019-03-16 10:53:19 +00:00
case GAL22V10 :
2023-10-30 13:10:28 +00:00
case GAL26CV12 :
case GAL26V12 :
2019-03-16 10:53:19 +00:00
case ATF22V10B :
case ATF22V10C :
setRow ( 0 ) ; // set RA0-5 low
2023-12-09 10:56:24 +00:00
sendAddress ( nBits , row ) ; // send row number (6 or 7 bits)
2019-03-16 10:53:19 +00:00
setSTB ( 0 ) ;
setSTB ( 1 ) ; // pulse /STB
setSDIN ( 0 ) ; // SDIN low
2023-09-22 15:32:15 +00:00
break ;
case GAL6001 :
case GAL6002 :
setRow ( 0 ) ;
sendBits ( 95 , 0 ) ;
sendBit ( 1 ) ;
sendAddress ( 7 , row ) ;
sendBits ( 16 , 0 ) ;
2023-09-28 10:23:17 +00:00
strobe ( 2 ) ; // pulse /STB for 2ms
2023-09-22 15:32:15 +00:00
break ;
2019-03-16 10:53:19 +00:00
}
}
2023-12-09 10:56:24 +00:00
static void strobeConfigRow ( char row )
{
switch ( gal ) {
case ATF750C :
setRow ( 0 ) ; // set RA0-5 low
setRow ( galinfo . cfgrow ) ;
sendAddress ( 7 , row ) ; // send row number (6 bits)
setSDIN ( 1 ) ; // SDIN high
setSTB ( 0 ) ;
setSTB ( 1 ) ; // pulse /STB
break ;
}
}
2019-03-16 10:53:19 +00:00
// read PES: programmer electronic signature (ATF = text string, others = Vendor/Vpp/timing)
2019-04-09 18:56:49 +00:00
static void readPes ( void ) {
2019-03-16 10:53:19 +00:00
unsigned short bitmask ;
short byteIndex ;
2019-04-09 18:56:49 +00:00
# ifdef DEBUG_PES
Serial . print ( F ( " testing gal " ) ) ;
Serial . print ( gal , DEC ) ;
Serial . println ( ) ;
# endif
2019-03-16 10:53:19 +00:00
turnOn ( READPES ) ;
2023-11-22 00:31:08 +00:00
strobeRow ( galinfo . pesrow ) ;
2019-03-16 10:53:19 +00:00
2023-03-21 19:58:40 +00:00
if ( gal = = ATF16V8B ) {
setPV ( 1 ) ; //Required for ATF16V8C
}
2019-03-16 10:53:19 +00:00
2023-09-22 15:32:15 +00:00
if ( gal = = GAL6001 | | gal = = GAL6002 ) {
discardBits ( 20 ) ;
}
2023-11-22 00:31:08 +00:00
for ( byteIndex = 0 ; byteIndex < galinfo . pesbytes ; byteIndex + + ) {
2019-03-16 10:53:19 +00:00
unsigned char value = 0 ;
for ( bitmask = 0x1 ; bitmask < = 0x80 ; bitmask < < = 1 ) {
if ( receiveBit ( ) ) {
value | = bitmask ;
}
}
pes [ byteIndex ] = value ;
}
turnOff ( ) ;
}
2023-03-30 22:00:21 +00:00
static void writePes ( void ) {
uint8_t rbit ;
uint8_t b , p ;
2023-10-30 14:13:25 +00:00
if ( gal = = ATF16V8B | | gal = = ATF20V8B | | gal = = ATF22V10B | | gal = = ATF22V10C ) {
2023-03-30 22:00:21 +00:00
Serial . println ( F ( " ER write PES not supported " ) ) ;
return ;
}
turnOn ( WRITEPES ) ;
setPV ( 1 ) ;
2023-10-01 17:11:17 +00:00
switch ( gal ) {
2023-10-07 11:34:03 +00:00
case GAL6001 :
case GAL6002 :
2023-10-01 17:11:17 +00:00
setRow ( 0 ) ;
sendBits ( 20 , 0 ) ;
for ( rbit = 0 ; rbit < 64 ; rbit + + ) {
b = pes [ rbit > > 3 ] ;
p = b & ( 1 < < ( rbit & 0 b111 ) ) ;
sendBit ( p ) ;
}
sendBits ( 11 , 0 ) ;
sendBit ( 1 ) ;
2023-11-22 00:31:08 +00:00
sendAddress ( 7 , galinfo . pesrow ) ;
2023-10-01 17:11:17 +00:00
sendBits ( 16 , 0 ) ;
setSDIN ( 0 ) ;
break ;
default :
2023-11-22 00:31:08 +00:00
setRow ( galinfo . pesrow ) ;
2023-10-01 17:11:17 +00:00
for ( rbit = 0 ; rbit < 64 ; rbit + + ) {
b = pes [ rbit > > 3 ] ;
p = b & ( 1 < < ( rbit & 0 b111 ) ) ;
sendBit ( p ) ;
}
break ;
2023-03-30 22:00:21 +00:00
}
2023-10-01 17:11:17 +00:00
2023-03-30 22:00:21 +00:00
strobe ( progtime ) ;
turnOff ( ) ;
}
2023-10-03 12:17:18 +00:00
static const unsigned char PROGMEM duration [ ] = {
1 , 2 , 5 , 10 , 20 , 30 , 40 , 50 , 60 , 70 , 80 , 90 , 100 , 200
} ;
2019-04-09 18:56:49 +00:00
2019-03-16 10:53:19 +00:00
static unsigned char getDuration ( unsigned char index ) {
2023-10-03 12:17:18 +00:00
if ( index > 13 ) {
return 0 ;
2019-03-16 10:53:19 +00:00
}
2023-10-03 12:17:18 +00:00
return pgm_read_byte ( & duration [ index ] ) ;
2019-03-16 10:53:19 +00:00
}
2023-03-27 20:58:14 +00:00
static void setGalDefaults ( void ) {
2023-12-09 10:56:24 +00:00
if ( gal = = ATF16V8B | | gal = = ATF20V8B | | gal = = ATF22V10B | | gal = = ATF22V10C | | gal = = ATF750C ) {
2023-03-27 20:58:14 +00:00
progtime = 20 ;
erasetime = 100 ;
2024-02-05 22:52:49 +00:00
vpp = 42 ; /* 10.5V */
2023-03-27 20:58:14 +00:00
} else {
progtime = 80 ;
erasetime = 80 ;
2023-03-30 21:58:51 +00:00
vpp = 48 ; /* 12V */
2023-03-27 20:58:14 +00:00
}
}
2019-03-16 10:53:19 +00:00
void parsePes ( char type ) {
unsigned char algo ;
if ( UNKNOWN = = type ) {
type = gal ;
}
2023-03-27 20:58:14 +00:00
2023-10-15 08:53:25 +00:00
# ifdef DEBUG_PES
2023-03-27 20:58:14 +00:00
Serial . print ( F ( " Parse pes. gal= " ) ) ;
Serial . println ( type , DEC ) ;
# endif
2019-03-16 10:53:19 +00:00
switch ( type ) {
case ATF16V8B :
2023-10-30 14:13:25 +00:00
case ATF20V8B :
2019-03-16 10:53:19 +00:00
case ATF22V10B :
case ATF22V10C :
2023-12-09 10:56:24 +00:00
case ATF750C :
2023-03-21 20:48:47 +00:00
progtime = 20 ;
2019-03-16 10:53:19 +00:00
erasetime = 100 ;
vpp = 48 ; /* 12.0V */
break ;
default :
algo = pes [ 1 ] & 0x0F ;
if ( algo = = 5 ) {
erasetime = ( 25 < < ( ( pes [ 4 ] > > 2 ) & 7 ) ) / 2 ;
progtime = getDuration ( ( ( ( ( unsigned short ) pes [ 5 ] < < 8 ) | pes [ 4 ] ) > > 5 ) & 15 ) ;
vpp = 2 * ( ( pes [ 5 ] > > 1 ) & 31 ) + 20 ;
}
2023-03-30 22:00:21 +00:00
else switch ( type ) {
2019-03-16 10:53:19 +00:00
case GAL16V8 :
case GAL20V8 :
erasetime = 100 ;
2023-09-29 10:24:03 +00:00
goto more ;
case GAL6001 :
case GAL6002 :
erasetime = 50 ;
more :
2019-03-16 10:53:19 +00:00
switch ( algo ) {
case 0 :
vpp = 63 ; // 15.75V
progtime = 100 ;
break ;
case 1 :
vpp = 63 ; // 15.75V
progtime = 80 ;
break ;
case 2 :
vpp = 66 ; // 16.5V
progtime = 10 ;
break ;
case 3 :
vpp = ( pes [ 3 ] = = NATIONAL ) ? 60 : 58 ; // 15.0V or 14.5V
progtime = 40 ;
break ;
case 4 :
vpp = 56 ; // 14V
progtime = 100 ;
break ;
}
break ;
default :
erasetime = ( pes [ 3 ] = = NATIONAL ) ? 50 : 100 ;
switch ( algo ) {
case 0 :
vpp = 66 ; // 16.5V
progtime = 10 ;
break ;
case 1 :
vpp = 63 ; // 15.75V
progtime = 100 ;
break ;
case 2 :
vpp = ( pes [ 3 ] = = NATIONAL ) ? 60 : 58 ; // 15.0V or 14.5V
progtime = 40 ;
break ;
case 3 :
vpp = 56 ; // 14V
progtime = 100 ;
break ;
}
}
}
2019-04-09 18:56:49 +00:00
2024-02-05 22:52:49 +00:00
//Afterburnes seems to work with programming voltages reduced by 1V
vpp - = 4 ; // -1V
2019-03-16 10:53:19 +00:00
}
// print PES information
void printPes ( char type ) {
Serial . print ( F ( " PES info: " ) ) ;
//voltage
2023-12-09 10:56:24 +00:00
if ( pes [ 3 ] = = ATMEL16 | | pes [ 3 ] = = ATMEL22 | | pes [ 3 ] = = ATMEL750 ) {
2019-03-16 10:53:19 +00:00
//Serial.print(" ");
} else {
if ( pes [ 1 ] & 0x10 ) {
Serial . print ( F ( " 3.3V " ) ) ;
} else {
Serial . print ( F ( " 5V " ) ) ;
}
}
//manufacturer
switch ( pes [ 3 ] ) {
case LATTICE : Serial . print ( F ( " Lattice " ) ) ; break ;
case NATIONAL : Serial . print ( F ( " National " ) ) ; break ;
case SGSTHOMSON : Serial . print ( F ( " ST Microsystems " ) ) ; break ;
2023-12-09 10:56:24 +00:00
case ATMEL750 :
2019-03-16 10:53:19 +00:00
case ATMEL16 :
case ATMEL22 : Serial . print ( F ( " Atmel " ) ) ; break ;
default : Serial . print ( F ( " Unknown GAL, " ) ) ;
}
// GAL type
switch ( type ) {
case GAL16V8 : Serial . print ( F ( " GAL16V8 " ) ) ; break ;
2023-09-17 04:55:40 +00:00
case GAL18V10 : Serial . print ( F ( " GAL18V10 " ) ) ; break ;
2019-03-16 10:53:19 +00:00
case GAL20V8 : Serial . print ( F ( " GAL20V8 " ) ) ; break ;
2023-11-22 03:48:09 +00:00
case GAL20RA10 : Serial . print ( F ( " GAL20RA10 " ) ) ; break ;
2023-09-16 06:20:12 +00:00
case GAL20XV10 : Serial . print ( F ( " GAL20XV10 " ) ) ; break ;
2023-05-16 21:37:52 +00:00
case GAL22V10 : Serial . print ( F ( " GAL22V10 " ) ) ; break ;
2023-10-30 13:10:28 +00:00
case GAL26CV12 : Serial . print ( F ( " GAL26CV12 " ) ) ; break ;
case GAL26V12 : Serial . print ( F ( " GAL26V12 " ) ) ; break ;
2023-09-22 15:32:15 +00:00
case GAL6001 : Serial . print ( F ( " GAL6001 " ) ) ; break ;
case GAL6002 : Serial . print ( F ( " GAL6002 " ) ) ; break ;
2023-03-25 19:40:03 +00:00
case ATF16V8B : Serial . print ( 0 = = ( flagBits & FLAG_BIT_ATF16V8C ) ? F ( " ATF16V8B " ) : F ( " ATF16V8C " ) ) ; break ;
2023-10-30 14:13:25 +00:00
case ATF20V8B : Serial . print ( F ( " ATF20V8B " ) ) ; break ;
2019-03-16 10:53:19 +00:00
case ATF22V10B : Serial . print ( F ( " ATF22V10B " ) ) ; break ;
case ATF22V10C : Serial . print ( F ( " ATF22V10C " ) ) ; break ;
2023-12-09 10:56:24 +00:00
case ATF750C : Serial . print ( F ( " ATF750C " ) ) ; break ;
2019-03-16 10:53:19 +00:00
}
//programming info
if ( UNKNOWN ! = type ) {
2023-03-25 19:40:03 +00:00
Serial . print ( F ( " VPP= " ) ) ;
2019-03-16 10:53:19 +00:00
Serial . print ( vpp > > 2 , DEC ) ;
Serial . print ( F ( " . " ) ) ;
Serial . print ( ( vpp & 3 ) * 25 , DEC ) ;
Serial . print ( F ( " Timing: prog= " ) ) ;
Serial . print ( progtime , DEC ) ;
Serial . print ( F ( " erase= " ) ) ;
Serial . print ( erasetime / 4 , DEC ) ;
} else {
Serial . print ( F ( " try VPP=10..14 in 1V steps " ) ) ;
}
Serial . println ( ) ;
}
// sets a fuse bit on particular position
// expects that the fusemap was cleared (set to zero) beforehand
static void setFuseBit ( unsigned short bitPos ) {
2023-12-10 16:13:14 +00:00
uint16_t pos ;
if ( sparseFusemapStat ) {
pos = sparseSetFuseBit ( bitPos ) ;
} else {
pos = bitPos > > 3 ; //divide the bit position by 8 to get the byte position
}
fusemap [ pos ] | = ( 1 < < ( bitPos & 7 ) ) ;
2019-03-16 10:53:19 +00:00
}
// gets a fuse bit from specific fuse position
static char getFuseBit ( unsigned short bitPos ) {
2023-12-10 16:13:14 +00:00
uint16_t pos ;
if ( sparseFusemapStat ) {
pos = sparseGetFuseBit ( bitPos ) ;
2023-12-13 22:02:42 +00:00
if ( pos > = 0xFF00 ) {
return pos & 0x1 ;
}
2023-12-10 16:13:14 +00:00
} else {
pos = bitPos > > 3 ;
}
return ( fusemap [ pos ] & ( 1 < < ( bitPos & 7 ) ) ) ? 1 : 0 ;
2019-03-16 10:53:19 +00:00
}
2023-09-23 03:05:12 +00:00
static void setFuseBitVal ( unsigned short bitPos , char val ) {
if ( val ) {
setFuseBit ( bitPos ) ;
}
}
2019-03-16 10:53:19 +00:00
// generic fuse-map reading, fuse-map bits are stored in fusemap array
static void readGalFuseMap ( const unsigned char * cfgArray , char useDelay , char doDiscardBits ) {
2023-11-22 00:31:08 +00:00
unsigned short cfgAddr = galinfo . cfgbase ;
2019-03-16 10:53:19 +00:00
unsigned short row , bit ;
unsigned short addr ;
2023-03-21 20:48:47 +00:00
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setPV ( 0 ) ;
}
2023-11-22 00:31:08 +00:00
for ( row = 0 ; row < galinfo . rows ; row + + ) {
2023-03-21 20:48:47 +00:00
strobeRow ( row ) ; //set address of the row
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setSDIN ( 0 ) ;
setPV ( 1 ) ;
}
2023-11-22 00:31:08 +00:00
for ( bit = 0 ; bit < galinfo . bits ; bit + + ) {
2019-03-16 10:53:19 +00:00
// check the received bit is 1 and if so then set the fuse map
if ( receiveBit ( ) ) {
2023-11-22 00:31:08 +00:00
addr = galinfo . rows ;
2019-03-16 10:53:19 +00:00
addr * = bit ;
addr + = row ;
setFuseBit ( addr ) ;
}
}
if ( useDelay ) {
delay ( useDelay ) ;
}
2023-03-21 20:48:47 +00:00
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setPV ( 0 ) ;
2023-03-27 20:58:14 +00:00
}
2019-03-16 10:53:19 +00:00
}
2023-03-27 20:58:14 +00:00
// read UES
2023-11-22 00:31:08 +00:00
strobeRow ( galinfo . uesrow ) ;
2023-03-21 20:48:47 +00:00
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setSDIN ( 0 ) ;
setPV ( 1 ) ;
}
2019-03-16 10:53:19 +00:00
if ( doDiscardBits ) {
discardBits ( doDiscardBits ) ;
}
2023-11-22 00:31:08 +00:00
for ( bit = 0 ; bit < galinfo . uesbytes * 8 ; bit + + ) {
2019-03-16 10:53:19 +00:00
if ( receiveBit ( ) ) {
2023-11-22 00:31:08 +00:00
addr = galinfo . uesfuse ;
2019-03-16 10:53:19 +00:00
addr + = bit ;
setFuseBit ( addr ) ;
}
}
if ( useDelay ) {
delay ( useDelay ) ;
}
2023-03-21 20:48:47 +00:00
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setPV ( 0 ) ;
}
2019-03-16 10:53:19 +00:00
// read CFG
2024-02-02 08:58:48 +00:00
if ( galinfo . cfgmethod = = CFG_STROBE_ROW2 ) { //ATF750C
const uint8_t cfgstroberow = 96 ;
const uint8_t cfgrowlen = 10 ;
const uint8_t cfgrowcount = ( galinfo . cfgbits + ( cfgrowlen - 1 ) ) / cfgrowlen ;
uint8_t i ;
for ( i = 0 ; i < cfgrowcount ; i + + ) {
strobeConfigRow ( cfgstroberow + i ) ;
for ( bit = 0 ; bit < cfgrowlen ; bit + + ) {
uint8_t absBit = ( cfgrowlen * i ) + bit ;
if ( absBit > = galinfo . cfgbits )
break ;
if ( receiveBit ( ) ) {
unsigned char cfgOffset = pgm_read_byte ( & cfgArray [ absBit ] ) ;
setFuseBit ( cfgAddr + cfgOffset ) ;
}
}
if ( useDelay ) {
delay ( useDelay ) ;
}
2023-03-27 20:58:14 +00:00
}
2019-04-09 18:56:49 +00:00
} else {
2024-02-02 08:58:48 +00:00
if ( galinfo . cfgmethod = = CFG_STROBE_ROW ) {
strobeRow ( galinfo . cfgrow ) ;
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setSDIN ( 0 ) ;
setPV ( 1 ) ;
}
}
else {
setRow ( galinfo . cfgrow ) ;
strobe ( 1 ) ;
}
for ( bit = 0 ; bit < galinfo . cfgbits ; bit + + ) {
if ( receiveBit ( ) ) {
unsigned char cfgOffset = pgm_read_byte ( & cfgArray [ bit ] ) ; //read array byte flom flash
setFuseBit ( cfgAddr + cfgOffset ) ;
}
2019-03-16 10:53:19 +00:00
}
}
2023-03-25 19:53:13 +00:00
//check APD fuse bit - only for ATF16V8C or ATF22V10C
if ( ( flagBits & FLAG_BIT_ATF16V8C ) | | gal = = ATF22V10C ) {
setPV ( 0 ) ;
if ( gal = = ATF22V10C ) {
setRow ( 0 ) ;
sendAddress ( 6 , CFG_ROW_APD ) ;
strobe ( 1 ) ;
} else { //ATF16V8C
setRow ( CFG_ROW_APD ) ;
strobe ( 1 ) ;
setPV ( 1 ) ;
}
setFlagBit ( FLAG_BIT_APD , receiveBit ( ) ) ;
}
2023-12-10 16:13:14 +00:00
#if 0
if ( sparseFusemapStat ) {
sparsePrintStat ( ) ;
}
# endif
2019-03-16 10:53:19 +00:00
}
2023-09-23 03:05:12 +00:00
static void readGalFuseMap600 ( const unsigned char * cfgArray ) {
unsigned short row , bit ;
unsigned short addr ;
for ( row = 0 ; row < 78 ; row + + )
{
strobeRow ( row ) ;
discardBits ( 20 ) ;
for ( bit = 0 ; bit < 11 ; bit + + )
setFuseBitVal ( 7296 + 78 * bit + row , receiveBit ( ) ) ;
for ( bit = 0 ; bit < 64 ; bit + + )
setFuseBitVal ( 114 * bit + row , receiveBit ( ) ) ;
discardBits ( 24 ) ;
}
for ( row = 0 ; row < 64 ; row + + )
{
sendBits ( 31 , 0 ) ;
for ( bit = 0 ; bit < 64 ; bit + + )
sendBit ( bit ! = row ) ;
sendBits ( 24 , 0 ) ;
setSDIN ( 0 ) ;
strobe ( 2 ) ;
for ( bit = 0 ; bit < 20 ; bit + + )
setFuseBitVal ( 78 + 114 * row + bit , receiveBit ( ) ) ;
discardBits ( 83 ) ;
for ( bit = 0 ; bit < 16 ; bit + + )
setFuseBitVal ( 98 + 114 * row + bit , receiveBit ( ) ) ;
}
// UES
2023-11-22 00:31:08 +00:00
strobeRow ( galinfo . uesrow ) ;
2023-09-23 03:05:12 +00:00
discardBits ( 20 ) ;
2023-11-22 00:31:08 +00:00
addr = galinfo . uesfuse ;
2023-09-23 03:05:12 +00:00
for ( bit = 0 ; bit < 72 ; bit + + )
setFuseBitVal ( addr + bit , receiveBit ( ) ) ;
// CFG
2023-11-22 00:31:08 +00:00
setRow ( galinfo . cfgrow ) ;
2023-09-23 03:05:12 +00:00
strobe ( 2 ) ;
2023-11-22 00:31:08 +00:00
addr = galinfo . cfgbase ;
for ( bit = 0 ; bit < galinfo . cfgbits ; bit + + ) {
2023-10-02 21:22:09 +00:00
unsigned char cfgOffset = pgm_read_byte ( & cfgArray [ bit ] ) ; //read array byte flom flash
setFuseBitVal ( addr + cfgOffset , receiveBit ( ) ) ;
}
2023-09-23 03:05:12 +00:00
}
2019-03-16 10:53:19 +00:00
// generic fuse-map verification, fuse map bits are compared against read bits
static unsigned short verifyGalFuseMap ( const unsigned char * cfgArray , char useDelay , char doDiscardBits ) {
2023-11-22 00:31:08 +00:00
unsigned short cfgAddr = galinfo . cfgbase ;
2019-03-16 10:53:19 +00:00
unsigned short row , bit ;
unsigned short addr ;
char fuseBit ; // fuse bit received from GAL
char mapBit ; // fuse bit stored in RAM
unsigned short errors = 0 ;
2024-02-02 08:58:48 +00:00
# ifdef DEBUG_VERIFY
Serial . print ( F ( " rot f: " ) ) ;
Serial . println ( rotatedFuseMap , DEC ) ;
# endif
2023-03-21 20:48:47 +00:00
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setPV ( 0 ) ;
}
2019-03-16 10:53:19 +00:00
// read fuse rows
2023-11-22 00:31:08 +00:00
for ( row = 0 ; row < galinfo . rows ; row + + ) {
2019-03-16 10:53:19 +00:00
strobeRow ( row ) ;
2023-03-21 20:48:47 +00:00
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setSDIN ( 0 ) ;
setPV ( 1 ) ;
2023-03-27 20:58:14 +00:00
}
2023-11-22 00:31:08 +00:00
for ( bit = 0 ; bit < galinfo . bits ; bit + + ) {
addr = galinfo . rows ;
2019-03-16 10:53:19 +00:00
addr * = bit ;
addr + = row ;
2024-02-02 08:58:48 +00:00
mapBit = getFuseBit ( addr ) ; //bit from RAM
fuseBit = receiveBit ( ) ; // read from GAL
2019-03-16 10:53:19 +00:00
if ( mapBit ! = fuseBit ) {
2019-04-09 18:56:49 +00:00
# ifdef DEBUG_VERIFY
Serial . print ( F ( " f a= " ) ) ;
2024-02-02 08:58:48 +00:00
Serial . print ( addr , DEC ) ;
2019-04-09 18:56:49 +00:00
# endif
2019-03-16 10:53:19 +00:00
errors + + ;
}
}
if ( useDelay ) {
delay ( useDelay ) ;
}
2023-03-21 20:48:47 +00:00
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setPV ( 0 ) ;
2023-03-27 20:58:14 +00:00
}
2019-03-16 10:53:19 +00:00
}
// read UES
2023-11-22 00:31:08 +00:00
strobeRow ( galinfo . uesrow ) ;
2023-03-21 20:48:47 +00:00
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setSDIN ( 0 ) ;
setPV ( 1 ) ;
}
2019-03-16 10:53:19 +00:00
if ( doDiscardBits ) {
discardBits ( doDiscardBits ) ;
}
2023-11-22 00:31:08 +00:00
for ( bit = 0 ; bit < galinfo . uesbytes * 8 ; bit + + ) {
addr = galinfo . uesfuse ;
2019-03-16 10:53:19 +00:00
addr + = bit ;
mapBit = getFuseBit ( addr ) ;
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
2019-04-09 18:56:49 +00:00
# ifdef DEBUG_VERIFY
Serial . print ( F ( " U a= " ) ) ;
Serial . println ( bit , DEC ) ;
# endif
2019-03-16 10:53:19 +00:00
errors + + ;
}
}
if ( useDelay ) {
delay ( useDelay ) ;
}
2023-03-21 20:48:47 +00:00
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setPV ( 0 ) ;
}
2024-02-02 08:58:48 +00:00
if ( galinfo . cfgmethod = = CFG_STROBE_ROW2 ) { //ATF750C
const uint8_t cfgstroberow = 96 ;
const uint8_t cfgrowlen = 10 ;
const uint8_t cfgrowcount = ( galinfo . cfgbits + ( cfgrowlen - 1 ) ) / cfgrowlen ;
uint8_t i ;
for ( i = 0 ; i < cfgrowcount ; i + + ) {
strobeConfigRow ( cfgstroberow + i ) ;
for ( bit = 0 ; bit < cfgrowlen ; bit + + ) {
uint8_t absBit = ( cfgrowlen * i ) + bit ;
if ( absBit > = galinfo . cfgbits ) {
break ;
}
mapBit = getFuseBit ( cfgAddr + pgm_read_byte ( & cfgArray [ absBit ] ) ) ; // cfgAddr + cfgOffset
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
# ifdef DEBUG_VERIFY
Serial . print ( F ( " C a= " ) ) ;
Serial . println ( absBit , DEC ) ;
# endif
errors + + ;
}
}
if ( useDelay ) {
delay ( useDelay ) ;
}
}
2019-04-09 18:56:49 +00:00
} else {
2024-02-02 08:58:48 +00:00
if ( galinfo . cfgmethod = = CFG_STROBE_ROW ) {
strobeRow ( galinfo . cfgrow ) ;
if ( flagBits & FLAG_BIT_ATF16V8C ) {
setSDIN ( 0 ) ;
setPV ( 1 ) ;
}
} else {
setRow ( galinfo . cfgrow ) ;
strobe ( 1 ) ;
}
for ( bit = 0 ; bit < galinfo . cfgbits ; bit + + ) {
unsigned char cfgOffset = pgm_read_byte ( & cfgArray [ bit ] ) ; //read array byte flom flash
mapBit = getFuseBit ( cfgAddr + cfgOffset ) ;
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
# ifdef DEBUG_VERIFY
Serial . print ( F ( " C a= " ) ) ;
Serial . println ( bit , DEC ) ;
# endif
errors + + ;
}
2019-03-16 10:53:19 +00:00
}
}
2023-03-25 19:53:13 +00:00
//verify PD fuse on Atmel's C GALs
if ( ( flagBits & FLAG_BIT_ATF16V8C ) | | gal = = ATF22V10C ) {
setPV ( 0 ) ;
if ( gal = = ATF22V10C ) {
setRow ( 0 ) ;
sendAddress ( 6 , CFG_ROW_APD ) ;
strobe ( 1 ) ;
} else { //ATF16V8C
setRow ( CFG_ROW_APD ) ;
strobe ( 1 ) ;
setPV ( 1 ) ;
}
mapBit = ( flagBits & FLAG_BIT_APD ) ? 1 : 0 ;
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
# ifdef DEBUG_VERIFY
Serial . println ( F ( " C pd " ) ) ;
# endif
errors + + ;
}
}
2019-03-16 10:53:19 +00:00
return errors ;
}
2023-09-28 10:23:17 +00:00
static unsigned short verifyGalFuseMap600 ( const unsigned char * cfgArray ) {
unsigned short row , bit ;
unsigned short addr ;
char fuseBit ; // fuse bit received from GAL
char mapBit ; // fuse bit stored in RAM
unsigned short errors = 0 ;
for ( row = 0 ; row < 78 ; row + + )
{
strobeRow ( row ) ;
discardBits ( 20 ) ;
for ( bit = 0 ; bit < 11 ; bit + + ) {
mapBit = getFuseBit ( 7296 + 78 * bit + row ) ;
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
# ifdef DEBUG_VERIFY
Serial . print ( F ( " f a= " ) ) ;
Serial . println ( 7296 + 78 * bit + row , DEC ) ;
# endif
errors + + ;
}
}
for ( bit = 0 ; bit < 64 ; bit + + ) {
mapBit = getFuseBit ( 114 * bit + row ) ;
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
# ifdef DEBUG_VERIFY
Serial . print ( F ( " f a= " ) ) ;
Serial . println ( 114 * bit + row , DEC ) ;
# endif
errors + + ;
}
}
discardBits ( 24 ) ;
}
for ( row = 0 ; row < 64 ; row + + )
{
sendBits ( 31 , 0 ) ;
for ( bit = 0 ; bit < 64 ; bit + + )
sendBit ( bit ! = row ) ;
sendBits ( 24 , 0 ) ;
setSDIN ( 0 ) ;
strobe ( 2 ) ;
for ( bit = 0 ; bit < 20 ; bit + + ) {
mapBit = getFuseBit ( 78 + 114 * row + bit ) ;
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
# ifdef DEBUG_VERIFY
Serial . print ( F ( " f a= " ) ) ;
Serial . println ( 78 + 114 * row + bit , DEC ) ;
# endif
errors + + ;
}
}
discardBits ( 83 ) ;
for ( bit = 0 ; bit < 16 ; bit + + ) {
mapBit = getFuseBit ( 98 + 114 * row + bit ) ;
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
# ifdef DEBUG_VERIFY
Serial . print ( F ( " f a= " ) ) ;
Serial . println ( 98 + 114 * row + bit , DEC ) ;
# endif
errors + + ;
}
}
}
// UES
2023-11-22 00:31:08 +00:00
strobeRow ( galinfo . uesrow ) ;
2023-09-28 10:23:17 +00:00
discardBits ( 20 ) ;
2023-11-22 00:31:08 +00:00
addr = galinfo . uesfuse ;
2023-09-28 10:23:17 +00:00
for ( bit = 0 ; bit < 72 ; bit + + ) {
mapBit = getFuseBit ( addr + bit ) ;
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
# ifdef DEBUG_VERIFY
Serial . print ( F ( " f a= " ) ) ;
Serial . println ( addr + bit , DEC ) ;
# endif
errors + + ;
}
}
// CFG
2023-11-22 00:31:08 +00:00
setRow ( galinfo . cfgrow ) ;
2023-09-28 10:23:17 +00:00
strobe ( 2 ) ;
2023-11-22 00:31:08 +00:00
addr = galinfo . cfgbase ;
for ( bit = 0 ; bit < galinfo . cfgbits ; bit + + ) {
2023-10-02 21:22:09 +00:00
unsigned char cfgOffset = pgm_read_byte ( & cfgArray [ bit ] ) ; //read array byte flom flash
mapBit = getFuseBit ( addr + cfgOffset ) ;
2023-09-28 10:23:17 +00:00
fuseBit = receiveBit ( ) ;
if ( mapBit ! = fuseBit ) {
# ifdef DEBUG_VERIFY
Serial . print ( F ( " f a= " ) ) ;
2023-10-15 08:53:25 +00:00
Serial . println ( addr + cfgOffset , DEC ) ;
2023-09-28 10:23:17 +00:00
# endif
errors + + ;
}
}
return errors ;
}
2019-03-16 10:53:19 +00:00
// main fuse-map reading and verification function
// READING: reads fuse rows, UES, CFG from GAL and stores into fusemap bit array RAM.
// VERIFY: reads fuse rows, UES, CFG from GAL and compares with fusemap bit array in RAM.
static void readOrVerifyGal ( char verify )
{
unsigned short i ;
unsigned char * cfgArray = ( unsigned char * ) cfgV8 ;
//ensure fusemap is cleared before READ operation, keep it for VERIFY operation.
if ( ! verify ) {
for ( i = 0 ; i < MAXFUSES ; i + + ) {
fusemap [ i ] = 0 ;
}
2024-02-04 23:36:45 +00:00
sparseSetup ( 1 ) ;
2019-03-16 10:53:19 +00:00
}
turnOn ( READGAL ) ;
switch ( gal )
{
case GAL16V8 :
case GAL20V8 :
if ( pes [ 2 ] = = 0x1A | | pes [ 2 ] = = 0x3A ) {
cfgArray = ( unsigned char * ) cfgV8AB ;
}
//read without delay, no discard
if ( verify ) {
i = verifyGalFuseMap ( cfgArray , 0 , 0 ) ;
} else {
readGalFuseMap ( cfgArray , 0 , 0 ) ;
}
break ;
case ATF16V8B :
2023-10-30 14:13:25 +00:00
case ATF20V8B :
2023-11-22 03:48:09 +00:00
case GAL18V10 :
case GAL20RA10 :
case GAL20XV10 :
case GAL26V12 :
case GAL26CV12 :
cfgArray = ( unsigned char * ) galinfo . cfg ;
2019-03-16 10:53:19 +00:00
//read without delay, no discard
if ( verify ) {
2023-11-22 03:48:09 +00:00
i = verifyGalFuseMap ( cfgArray , 0 , 0 ) ;
2019-03-16 10:53:19 +00:00
} else {
2023-11-22 03:48:09 +00:00
readGalFuseMap ( cfgArray , 0 , 0 ) ;
2019-03-16 10:53:19 +00:00
}
break ;
2023-10-30 14:13:25 +00:00
2023-09-23 03:05:12 +00:00
case GAL6001 :
case GAL6002 :
cfgArray = ( gal = = GAL6001 ) ? ( unsigned char * ) cfg6001 : ( unsigned char * ) cfg6002 ;
//read without delay, no discard
if ( verify ) {
2023-09-28 10:23:17 +00:00
i = verifyGalFuseMap600 ( cfgArray ) ;
2023-09-23 03:05:12 +00:00
} else {
readGalFuseMap600 ( cfgArray ) ;
}
break ;
2023-09-17 06:33:25 +00:00
2019-03-16 10:53:19 +00:00
case GAL22V10 :
case ATF22V10B :
case ATF22V10C :
//read with delay 1 ms, discard 68 cfg bits on ATFxx
if ( verify ) {
2023-09-17 04:55:40 +00:00
i = verifyGalFuseMap ( cfgV10 , 1 , ( gal = = GAL22V10 ) ? 0 : 68 ) ;
2019-03-16 10:53:19 +00:00
} else {
2023-09-17 04:55:40 +00:00
readGalFuseMap ( cfgV10 , 1 , ( gal = = GAL22V10 ) ? 0 : 68 ) ;
2019-03-16 10:53:19 +00:00
}
break ;
2023-12-09 10:56:24 +00:00
case ATF750C :
//read with delay 1 ms, discard 107 bits on ATF750C
if ( verify ) {
i = verifyGalFuseMap ( galinfo . cfg , 1 , galinfo . bits - 8 * galinfo . uesbytes - 1 ) ;
} else {
readGalFuseMap ( galinfo . cfg , 1 , galinfo . bits - 8 * galinfo . uesbytes - 1 ) ;
}
2019-03-16 10:53:19 +00:00
}
turnOff ( ) ;
if ( verify & & i > 0 ) {
Serial . print ( F ( " ER verify failed. Bit errors: " ) ) ;
Serial . println ( i , DEC ) ;
}
}
// fuse-map writing function for V8 GAL chips
static void writeGalFuseMapV8 ( const unsigned char * cfgArray ) {
2023-11-22 00:31:08 +00:00
unsigned short cfgAddr = galinfo . cfgbase ;
2019-03-16 10:53:19 +00:00
unsigned char row , rbit ;
unsigned short addr ;
2023-11-22 00:31:08 +00:00
unsigned char rbitMax = galinfo . bits ;
2023-03-27 20:58:14 +00:00
const unsigned char skipLastClk = ( flagBits & FLAG_BIT_ATF16V8C ) ? 1 : 0 ;
2019-03-16 10:53:19 +00:00
setPV ( 1 ) ;
// write fuse rows
2023-11-22 00:31:08 +00:00
for ( row = 0 ; row < galinfo . rows ; row + + ) {
2019-03-16 10:53:19 +00:00
setRow ( row ) ;
2023-03-21 20:48:47 +00:00
for ( rbit = 0 ; rbit < rbitMax ; rbit + + ) {
2023-11-22 00:31:08 +00:00
addr = galinfo . rows ;
2019-03-16 10:53:19 +00:00
addr * = rbit ;
addr + = row ;
2023-03-21 20:48:47 +00:00
sendBit ( getFuseBit ( addr ) , rbit = = rbitMax - 1 ? skipLastClk : 0 ) ;
2019-03-16 10:53:19 +00:00
}
strobe ( progtime ) ;
}
// write UES
2023-11-22 00:31:08 +00:00
setRow ( galinfo . uesrow ) ;
2019-03-16 10:53:19 +00:00
for ( rbit = 0 ; rbit < 64 ; rbit + + ) {
2023-11-22 00:31:08 +00:00
addr = galinfo . uesfuse ;
2019-03-16 10:53:19 +00:00
addr + = rbit ;
2023-03-21 20:48:47 +00:00
sendBit ( getFuseBit ( addr ) , rbit = = 63 ? skipLastClk : 0 ) ;
2019-03-16 10:53:19 +00:00
}
strobe ( progtime ) ;
2019-04-09 18:56:49 +00:00
// write CFG (all ICs use setRow)
2023-11-22 00:31:08 +00:00
rbitMax = galinfo . cfgbits ;
setRow ( galinfo . cfgrow ) ;
2023-03-21 20:48:47 +00:00
for ( rbit = 0 ; rbit < rbitMax ; rbit + + ) {
2023-10-02 21:22:09 +00:00
unsigned char cfgOffset = pgm_read_byte ( & cfgArray [ rbit ] ) ; //read array byte flom flash
sendBit ( getFuseBit ( cfgAddr + cfgOffset ) , rbit = = rbitMax - 1 ? skipLastClk : 0 ) ;
2019-03-16 10:53:19 +00:00
}
strobe ( progtime ) ;
setPV ( 0 ) ;
2023-03-25 19:53:13 +00:00
// disable power-down if the APD flag is not set (only for ATF16V8C)
if ( skipLastClk & & ( flagBits & FLAG_BIT_APD ) = = 0 ) {
setPV ( 1 ) ;
strobeRow ( CFG_ROW_APD , BIT_ZERO ) ; // strobe row and send one bit with value 0
setPV ( 0 ) ;
}
2019-03-16 10:53:19 +00:00
}
// fuse-map writing function for V10 GAL chips
static void writeGalFuseMapV10 ( const unsigned char * cfgArray , char fillUesStart , char useSdin ) {
2023-11-22 00:31:08 +00:00
unsigned short cfgAddr = galinfo . cfgbase ;
2019-03-16 10:53:19 +00:00
unsigned char row , bit ;
unsigned short addr ;
2023-11-22 00:31:08 +00:00
unsigned short uesFill = galinfo . bits - galinfo . uesbytes * 8 ;
2019-03-16 10:53:19 +00:00
setRow ( 0 ) ; //RA0-5 low
// write fuse rows
2023-11-22 00:31:08 +00:00
for ( row = 0 ; row < galinfo . rows ; row + + ) {
for ( bit = 0 ; bit < galinfo . bits ; bit + + ) {
addr = galinfo . rows ;
2019-03-16 10:53:19 +00:00
addr * = bit ;
addr + = row ;
sendBit ( getFuseBit ( addr ) ) ;
}
sendAddress ( 6 , row ) ;
setPV ( 1 ) ;
strobe ( progtime ) ;
setPV ( 0 ) ;
}
// write UES
if ( fillUesStart ) {
2023-10-30 11:51:32 +00:00
sendBits ( uesFill , 1 ) ;
2019-03-16 10:53:19 +00:00
}
2023-11-22 00:31:08 +00:00
for ( bit = 0 ; bit < galinfo . uesbytes * 8 ; bit + + ) {
addr = galinfo . uesfuse ;
2019-03-16 10:53:19 +00:00
addr + = bit ;
sendBit ( getFuseBit ( addr ) ) ;
}
if ( ! fillUesStart ) {
2023-10-30 11:51:32 +00:00
sendBits ( uesFill , 1 ) ;
2019-03-16 10:53:19 +00:00
}
2023-11-22 00:31:08 +00:00
sendAddress ( 6 , galinfo . uesrow ) ;
2019-03-16 10:53:19 +00:00
setPV ( 1 ) ;
strobe ( progtime ) ;
setPV ( 0 ) ;
// write CFG
2023-11-22 00:31:08 +00:00
setRow ( galinfo . cfgrow ) ;
for ( bit = 0 ; bit < galinfo . cfgbits - useSdin ; bit + + ) {
2023-10-02 21:22:09 +00:00
unsigned char cfgOffset = pgm_read_byte ( & cfgArray [ bit ] ) ; //read array byte flom flash
sendBit ( getFuseBit ( cfgAddr + cfgOffset ) ) ;
2019-03-16 10:53:19 +00:00
}
if ( useSdin ) {
2023-10-02 21:22:09 +00:00
unsigned char cfgOffset = pgm_read_byte ( & cfgArray [ 19 ] ) ; //read array byte flom flash
setSDIN ( getFuseBit ( cfgAddr + cfgOffset ) ) ;
2019-03-16 10:53:19 +00:00
}
setPV ( 1 ) ;
strobe ( progtime ) ;
setPV ( 0 ) ;
2023-03-25 19:53:13 +00:00
if ( useSdin & & ( flagBits & FLAG_BIT_APD ) = = 0 ) {
2019-03-16 10:53:19 +00:00
// disable power-down feature (JEDEC bit #5892)
setRow ( 0 ) ;
2023-03-25 19:53:13 +00:00
sendAddress ( 6 , CFG_ROW_APD ) ;
2019-03-16 10:53:19 +00:00
setPV ( 1 ) ;
strobe ( progtime ) ;
setPV ( 0 ) ;
}
}
2023-12-09 10:56:24 +00:00
// fuse-map writing function for ATF750C chips
2024-02-02 08:58:48 +00:00
static void writeGalFuseMapV750 ( const unsigned char * cfgArray ) {
2023-12-09 10:56:24 +00:00
unsigned short cfgAddr = galinfo . cfgbase ;
unsigned char row , bit ;
unsigned short addr ;
2024-02-02 08:58:48 +00:00
unsigned short uesFill = galinfo . bits - ( galinfo . uesbytes * 8 ) - 1 ;
uint8_t cfgRowLen = 10 ; //ATF750C
uint8_t cfgStrobeRow = 96 ; //ATF750C
2023-12-09 10:56:24 +00:00
// write fuse rows
setRow ( 0 ) ; //RA0-5 low
delayMicroseconds ( 20 ) ;
for ( row = 0 ; row < galinfo . rows ; row + + ) {
for ( bit = 0 ; bit < galinfo . bits ; bit + + ) {
2024-02-02 08:58:48 +00:00
addr = galinfo . rows ;
addr * = bit ;
addr + = row ;
2023-12-09 10:56:24 +00:00
sendBit ( getFuseBit ( addr ) ) ;
}
sendAddress ( 7 , row ) ;
setPV ( 1 ) ;
delayMicroseconds ( 20 ) ;
strobe ( progtime ) ;
delayMicroseconds ( 100 ) ;
setPV ( 0 ) ;
delayMicroseconds ( 12 ) ;
}
2024-02-02 08:58:48 +00:00
setRow ( 0 ) ; //RA0-5 low
sendBits ( uesFill , 0 ) ; //send X number of 0 bits between fuse rows and UES data
2023-12-09 10:56:24 +00:00
2024-02-02 08:58:48 +00:00
//write UES
for ( bit = 0 ; bit < ( 8 * galinfo . uesbytes ) ; bit + + ) {
addr = galinfo . uesfuse ;
addr + = bit ;
sendBit ( getFuseBit ( addr ) ) ;
}
2023-12-09 10:56:24 +00:00
2024-02-02 08:58:48 +00:00
//set 1 bit after UES to 0
sendBits ( 1 , 0 ) ;
2023-12-09 10:56:24 +00:00
2024-02-02 08:58:48 +00:00
row = galinfo . uesrow ;
sendAddress ( 7 , row ) ;
setPV ( 1 ) ;
strobe ( progtime ) ;
setPV ( 0 ) ;
delay ( progtime ) ;
2023-12-09 10:56:24 +00:00
2024-02-02 08:58:48 +00:00
// write CFG
uint8_t cfgrowcount = ( galinfo . cfgbits + ( cfgRowLen - 1 ) ) / cfgRowLen ;
for ( uint8_t i = 0 ; i < cfgrowcount ; i + + ) {
setRow ( 0 ) ;
delayMicroseconds ( 10 ) ;
setRow ( galinfo . cfgrow ) ;
2023-12-09 10:56:24 +00:00
2024-02-02 08:58:48 +00:00
for ( bit = 0 ; bit < cfgRowLen ; bit + + ) {
uint8_t absBit = bit + ( i * cfgRowLen ) ;
//addr = galinfo.cfgbase - (galinfo[gal].bits * rangeStartRow) + cfgArray[absBit];
addr = galinfo . cfgbase + pgm_read_byte ( & cfgArray [ absBit ] ) ;
uint8_t v = getFuseBit ( addr ) ;
sendBit ( v ) ;
2023-12-09 10:56:24 +00:00
}
2024-02-02 08:58:48 +00:00
sendAddress ( 7 , i + cfgStrobeRow ) ;
delayMicroseconds ( 10 ) ;
setPV ( 1 ) ;
delayMicroseconds ( 18 ) ;
strobe ( progtime ) ; // 20ms
delayMicroseconds ( 32 ) ;
setPV ( 0 ) ;
delayMicroseconds ( 12 ) ;
setRow ( 0 ) ;
delayMicroseconds ( 12 ) ;
}
//TODO - read the power down fuse bit state from the fuse map and set it only if needed
if ( 1 ) {
// disable power-down feature (JEDEC bit #5892)
setRow ( 0 ) ;
sendAddress ( 7 , 125 ) ;
setPV ( 1 ) ;
strobe ( progtime ) ;
setPV ( 0 ) ;
delay ( progtime ) ;
}
2023-12-09 10:56:24 +00:00
}
2023-09-29 10:24:03 +00:00
// fuse-map writing function for 600x GAL chips
static void writeGalFuseMap600 ( const unsigned char * cfgArray ) {
2023-11-22 00:31:08 +00:00
unsigned short cfgAddr = galinfo . cfgbase ;
2023-09-29 10:24:03 +00:00
unsigned char row , bit ;
unsigned short addr ;
setRow ( 0 ) ;
for ( row = 0 ; row < 78 ; row + + )
{
sendBits ( 20 , 0 ) ;
for ( bit = 0 ; bit < 11 ; bit + + )
sendBit ( getFuseBit ( 7296 + 78 * bit + row ) ) ;
for ( bit = 0 ; bit < 64 ; bit + + )
sendBit ( getFuseBit ( 114 * bit + row ) ) ;
sendBit ( 1 ) ;
sendAddress ( 7 , row ) ;
sendBits ( 16 , 0 ) ;
setSDIN ( 0 ) ;
2023-10-01 16:04:13 +00:00
setPV ( 1 ) ;
2023-09-29 10:24:03 +00:00
strobe ( progtime ) ;
2023-10-01 16:04:13 +00:00
setPV ( 0 ) ;
2023-09-29 10:24:03 +00:00
}
for ( row = 0 ; row < 64 ; row + + )
{
for ( bit = 0 ; bit < 20 ; bit + + )
sendBit ( getFuseBit ( 78 + 114 * row + bit ) ) ;
sendBits ( 11 , 0 ) ;
for ( bit = 0 ; bit < 64 ; bit + + )
sendBit ( bit ! = row ) ;
sendBits ( 8 , 0 ) ;
for ( bit = 0 ; bit < 16 ; bit + + )
sendBit ( getFuseBit ( 98 + 114 * row + bit ) ) ;
setSDIN ( 0 ) ;
2023-10-01 16:04:13 +00:00
setPV ( 1 ) ;
2023-09-29 10:24:03 +00:00
strobe ( progtime ) ;
2023-10-01 16:04:13 +00:00
setPV ( 0 ) ;
2023-09-29 10:24:03 +00:00
}
// UES
sendBits ( 20 , 0 ) ;
2023-11-22 00:31:08 +00:00
addr = galinfo . uesfuse ;
2023-09-29 10:24:03 +00:00
for ( bit = 0 ; bit < 72 ; bit + + )
sendBit ( getFuseBit ( addr + bit ) ) ;
sendBits ( 3 , 0 ) ;
sendBit ( 1 ) ;
2023-11-22 00:31:08 +00:00
sendAddress ( 7 , galinfo . uesrow ) ;
2023-09-29 10:24:03 +00:00
sendBits ( 16 , 0 ) ;
setSDIN ( 0 ) ;
2023-10-01 16:04:13 +00:00
setPV ( 1 ) ;
2023-09-29 10:24:03 +00:00
strobe ( progtime ) ;
2023-10-01 16:04:13 +00:00
setPV ( 0 ) ;
2023-09-29 10:24:03 +00:00
// CFG
2023-11-22 00:31:08 +00:00
setRow ( galinfo . cfgrow ) ;
for ( bit = 0 ; bit < galinfo . cfgbits ; bit + + )
2023-09-29 10:24:03 +00:00
{
2023-10-02 21:22:09 +00:00
unsigned char cfgOffset = pgm_read_byte ( & cfgArray [ bit ] ) ; //read array byte flom flash
sendBit ( getFuseBit ( cfgAddr + cfgOffset ) ) ;
2023-09-29 10:24:03 +00:00
}
setSDIN ( 0 ) ;
2023-10-01 16:04:13 +00:00
setPV ( 1 ) ;
2023-09-29 10:24:03 +00:00
strobe ( progtime ) ;
2023-10-01 16:04:13 +00:00
setPV ( 0 ) ;
2023-09-29 10:24:03 +00:00
}
2019-03-16 10:53:19 +00:00
// main fuse-map writing function
static void writeGal ( )
{
unsigned short i ;
unsigned char * cfgArray = ( unsigned char * ) cfgV8 ;
turnOn ( WRITEGAL ) ;
switch ( gal )
{
case GAL16V8 :
case GAL20V8 :
if ( pes [ 2 ] = = 0x1A | | pes [ 2 ] = = 0x3A ) {
cfgArray = ( unsigned char * ) cfgV8AB ;
}
writeGalFuseMapV8 ( cfgArray ) ;
break ;
case ATF16V8B :
2023-10-30 14:13:25 +00:00
case ATF20V8B :
2020-05-25 06:34:24 +00:00
writeGalFuseMapV8 ( cfgV8AB ) ;
2019-03-16 10:53:19 +00:00
break ;
2023-09-29 10:24:03 +00:00
case GAL6001 :
case GAL6002 :
2023-11-22 03:48:09 +00:00
cfgArray = ( unsigned char * ) galinfo . cfg ;
writeGalFuseMap600 ( cfgArray ) ;
2023-09-29 10:24:03 +00:00
break ;
2023-09-17 04:55:40 +00:00
case GAL18V10 :
2023-11-22 03:48:09 +00:00
case GAL20RA10 :
case GAL20XV10 :
2023-10-30 13:10:28 +00:00
case GAL26CV12 :
case GAL26V12 :
2023-11-22 03:48:09 +00:00
cfgArray = ( unsigned char * ) galinfo . cfg ;
writeGalFuseMapV10 ( cfgArray , 0 , 0 ) ;
2023-09-17 04:55:40 +00:00
break ;
2019-03-16 10:53:19 +00:00
case GAL22V10 :
case ATF22V10B :
case ATF22V10C :
2023-09-17 04:55:40 +00:00
writeGalFuseMapV10 ( cfgV10 , ( gal = = GAL22V10 ) ? 0 : 1 , ( gal = = ATF22V10C ) ? 1 : 0 ) ;
2023-12-09 10:56:24 +00:00
break ;
case ATF750C :
2024-02-02 08:58:48 +00:00
writeGalFuseMapV750 ( cfgV750 ) ;
2019-03-16 10:53:19 +00:00
}
turnOff ( ) ;
}
// erases fuse-map in the GAL
2023-03-30 22:00:21 +00:00
static void eraseGAL ( char eraseAll )
2019-03-16 10:53:19 +00:00
{
turnOn ( ERASEGAL ) ;
setPV ( 1 ) ;
2023-11-22 00:31:08 +00:00
setRow ( eraseAll ? galinfo . eraseallrow : galinfo . eraserow ) ;
2019-03-16 10:53:19 +00:00
if ( gal = = GAL16V8 | | gal = = ATF16V8B | | gal = = GAL20V8 ) {
sendBit ( 1 ) ;
}
strobe ( erasetime ) ;
setPV ( 0 ) ;
turnOff ( ) ;
}
2023-03-25 19:40:03 +00:00
// sets security bit - disables fuse reading
static void secureGAL ( void )
{
turnOn ( WRITEGAL ) ;
setPV ( 1 ) ;
strobeRow ( 61 , BIT_ONE ) ; // strobe row and send one bit with value 1
setPV ( 0 ) ;
turnOff ( ) ;
}
2019-03-16 10:53:19 +00:00
static char checkGalTypeViaPes ( void )
{
char type = UNKNOWN ;
2019-04-09 18:56:49 +00:00
# ifdef DEBUG_PES
char i ;
Serial . println ( F ( " PES raw bytes: " ) ) ;
for ( i = 0 ; i < 10 ; i + + ) {
printFormatedNumberHex2 ( pes [ i ] ) ;
Serial . print ( F ( " " ) ) ;
}
Serial . println ( ) ;
# endif
2023-03-21 19:58:40 +00:00
setFlagBit ( FLAG_BIT_ATF16V8C , 0 ) ;
2022-03-26 08:06:51 +00:00
if ( pes [ 7 ] = = ' F ' & & pes [ 6 ] = = ' 2 ' & & pes [ 5 ] = = ' 2 ' & & ( pes [ 4 ] = = ' V ' | | pes [ 4 ] = = ' L ' ) & & pes [ 3 ] = = ' 1 ' & & pes [ 2 ] = = ' 0 ' ) {
2019-03-16 10:53:19 +00:00
if ( pes [ 1 ] = = ' B ' ) {
type = ATF22V10B ;
} else {
type = ATF22V10C ;
}
}
2023-11-04 14:14:46 +00:00
else if ( pes [ 6 ] = = ' F ' & & pes [ 5 ] = = ' 2 ' & & pes [ 4 ] = = ' 0 ' & & pes [ 3 ] = = ' V ' & & pes [ 2 ] = = ' 8 ' & & pes [ 1 ] = = ' B ' ) {
2023-10-30 14:13:25 +00:00
type = ATF20V8B ;
}
2019-03-16 10:53:19 +00:00
else if ( pes [ 6 ] = = ' F ' & & pes [ 5 ] = = ' 1 ' & & pes [ 4 ] = = ' 6 ' & & pes [ 3 ] = = ' V ' & & pes [ 2 ] = = ' 8 ' ) {
type = ATF16V8B ;
2023-03-28 20:30:15 +00:00
if ( pes [ 1 ] = = ' C ' | | pes [ 1 ] = = ' Z ' ) { // ATF16V8C, ATF16V8CZ
2023-03-21 19:58:40 +00:00
setFlagBit ( FLAG_BIT_ATF16V8C , 1 ) ;
2023-03-27 20:58:14 +00:00
}
2019-03-16 10:53:19 +00:00
}
2023-12-09 10:56:24 +00:00
else if ( pes [ 8 ] = = ' F ' & & pes [ 7 ] = = ' V ' & & pes [ 6 ] = = ' 7 ' & & pes [ 5 ] = = ' 5 ' & & pes [ 4 ] = = ' 0 ' & & pes [ 3 ] = = ' C ' ) {
// complete string at beginning of row 127: "300C057VF100"
type = ATF750C ;
}
2019-03-16 10:53:19 +00:00
else if ( pes [ 2 ] ! = 0x00 & & pes [ 2 ] ! = 0xFF ) {
2023-11-22 00:31:08 +00:00
for ( type = ( sizeof ( galInfoList ) / sizeof ( galinfo_t ) ) - 1 ; type ; type - - ) {
uint8_t id0 = pgm_read_byte ( & galInfoList [ type ] . id0 ) ;
uint8_t id1 = pgm_read_byte ( & galInfoList [ type ] . id1 ) ;
if ( pes [ 2 ] = = id0 | | pes [ 2 ] = = id1 ) break ;
2019-03-16 10:53:19 +00:00
}
2023-09-16 06:05:42 +00:00
} else if ( pes [ 3 ] = = SGSTHOMSON & & pes [ 2 ] = = 0x00 ) {
2023-09-16 12:39:02 +00:00
type = GAL16V8 ;
2019-03-16 10:53:19 +00:00
}
return type ;
}
// checks whether gal type corresponds to PES information on the IC
// note: PES must be read beforehand
static char testProperGAL ( void )
{
char type = checkGalTypeViaPes ( ) ;
if ( type = = 0 ) {
//Unknown or illegal PES,
goto error ;
}
else if ( type ! = gal ) {
//PES indicates a different GAL type than selected. Change to detected GAL type?
goto error ;
}
return 1 ;
error :
Serial . println ( F ( " ER unknown or wrong GAL type (check Power ON) " ) ) ;
return 0 ;
}
// prints a hexadecimal number - 2 digits with a leading zero
static void printFormatedNumberHex2 ( unsigned char num ) {
if ( num < 16 ) {
Serial . print ( F ( " 0 " ) ) ;
}
Serial . print ( num , HEX ) ;
}
// prints a hexadecimal number - 4 digits with a leading zero
static void printFormatedNumberHex4 ( unsigned short num ) {
if ( num < 0x10 ) {
Serial . print ( F ( " 000 " ) ) ;
} else
if ( num < 0x100 ) {
Serial . print ( F ( " 00 " ) ) ;
} else
if ( num < 0x1000 ) {
Serial . print ( F ( " 0 " ) ) ;
}
Serial . print ( num , HEX ) ;
}
// prints a decimal number - 4 digits with a leading zero
static void printFormatedNumberDec4 ( unsigned short num ) {
if ( num < 1 ) {
Serial . print ( F ( " 0000 " ) ) ;
return ;
}
if ( num < 10 ) {
Serial . print ( F ( " 000 " ) ) ;
} else
if ( num < 100 ) {
Serial . print ( F ( " 00 " ) ) ;
} else
if ( num < 1000 ) {
Serial . print ( F ( " 0 " ) ) ;
}
Serial . print ( num , DEC ) ;
}
// adds a formated decimal number with a leading zero to a line buffer at position 'i'
static unsigned char addFormatedNumberDec4 ( unsigned short num , unsigned char i ) {
char cnt = 3 ;
while ( cnt > = 0 ) {
line [ i + cnt ] = ' 0 ' + ( num % 10 ) ;
num / = 10 ;
cnt - - ;
}
return i + 4 ;
}
// calculates fuse-map checksum and returns it
static unsigned short checkSum ( unsigned short n )
{
unsigned short c , e , i ;
unsigned long a ;
c = e = 0 ;
a = 0 ;
for ( i = 0 ; i < n ; i + + ) {
e + + ;
if ( e = = 9 ) {
e = 1 ;
a + = c ;
c = 0 ;
}
c > > = 1 ;
if ( getFuseBit ( i ) ) {
c + = 0x80 ;
}
}
return ( unsigned short ) ( ( c > > ( 8 - e ) ) + a ) ;
}
2023-03-21 20:07:52 +00:00
static void printGalName ( ) {
switch ( gal ) {
case GAL16V8 : Serial . println ( F ( " GAL16V8 " ) ) ; break ;
2023-09-17 04:55:40 +00:00
case GAL18V10 : Serial . println ( F ( " GAL18V10 " ) ) ; break ;
2023-03-21 20:07:52 +00:00
case GAL20V8 : Serial . println ( F ( " GAL20V8 " ) ) ; break ;
2023-11-22 03:48:09 +00:00
case GAL20RA10 : Serial . println ( F ( " GAL20RA10 " ) ) ; break ;
2023-09-16 06:20:12 +00:00
case GAL20XV10 : Serial . println ( F ( " GAL20XV10 " ) ) ; break ;
2023-03-21 20:07:52 +00:00
case GAL22V10 : Serial . println ( F ( " GAL22V10 " ) ) ; break ;
2023-10-30 13:10:28 +00:00
case GAL26CV12 : Serial . println ( F ( " GAL26CV12 " ) ) ; break ;
case GAL26V12 : Serial . println ( F ( " GAL26V12 " ) ) ; break ;
2023-09-22 15:32:15 +00:00
case GAL6001 : Serial . println ( F ( " GAL6001 " ) ) ; break ;
case GAL6002 : Serial . println ( F ( " GAL6002 " ) ) ; break ;
2023-03-21 20:07:52 +00:00
case ATF16V8B :
if ( flagBits & FLAG_BIT_ATF16V8C ) {
Serial . println ( F ( " ATF16V8C " ) ) ;
} else {
Serial . println ( F ( " ATF16V8B " ) ) ;
}
break ;
2023-10-30 14:13:25 +00:00
case ATF20V8B : Serial . println ( F ( " ATF20V8B " ) ) ; break ;
2023-03-21 20:07:52 +00:00
case ATF22V10B : Serial . println ( F ( " ATF22V10B " ) ) ; break ;
case ATF22V10C : Serial . println ( F ( " ATF22V10C " ) ) ; break ;
2024-02-02 08:58:48 +00:00
case ATF750C : Serial . println ( F ( " ATF750C " ) ) ; break ;
2023-03-21 20:07:52 +00:00
default : Serial . println ( F ( " GAL " ) ) ; break ;
}
}
2019-03-16 10:53:19 +00:00
2023-09-25 04:18:49 +00:00
static unsigned printJedecBlock ( unsigned short k , unsigned short bits , unsigned short rows ) {
2023-10-03 11:45:38 +00:00
unsigned short i , j ;
2023-09-25 04:18:49 +00:00
unsigned char unused ;
for ( i = 0 ; i < bits ; i + + )
{
unused = 1 ;
2023-10-03 11:45:38 +00:00
for ( j = 0 ; j < rows ; j + + )
{
unused & = ! getFuseBit ( k + j ) ;
}
if ( unused ) {
k + = rows ;
continue ;
}
Serial . print ( ' L ' ) ;
printFormatedNumberDec4 ( k ) ;
Serial . print ( ' ' ) ;
2023-09-25 04:18:49 +00:00
for ( j = 0 ; j < rows ; j + + , k + + )
{
if ( getFuseBit ( k ) ) {
unused = 0 ;
2023-10-03 11:45:38 +00:00
Serial . print ( ' 1 ' ) ;
2023-09-25 04:18:49 +00:00
} else {
2023-10-03 11:45:38 +00:00
Serial . print ( ' 0 ' ) ;
2023-09-25 04:18:49 +00:00
}
}
2023-10-03 11:45:38 +00:00
Serial . println ( ' * ' ) ;
2023-09-25 04:18:49 +00:00
}
return k ;
}
2019-03-16 10:53:19 +00:00
// prints the contents of fuse-map array in the form of JEDEC text file
static void printJedec ( )
{
unsigned short i , j , k , n ;
unsigned char unused , start ;
2023-03-25 19:53:13 +00:00
uint8_t apdFuse = ( flagBits & FLAG_BIT_APD ) ? 1 : 0 ;
2019-03-16 10:53:19 +00:00
Serial . print ( F ( " JEDEC file for " ) ) ;
2023-03-21 20:07:52 +00:00
printGalName ( ) ;
2023-11-22 00:31:08 +00:00
Serial . print ( F ( " *QP " ) ) ; Serial . print ( galinfo . pins , DEC ) ;
Serial . print ( F ( " *QF " ) ) ; Serial . print ( galinfo . fuses + apdFuse , DEC ) ;
2019-03-16 10:53:19 +00:00
Serial . println ( F ( " *QV0*F0*G0*X0* " ) ) ;
2023-09-25 04:18:49 +00:00
k = 0 ;
2023-09-23 03:05:12 +00:00
if ( gal = = GAL6001 | | gal = = GAL6002 ) {
2023-09-25 04:18:49 +00:00
k = printJedecBlock ( k , 64 , 114 ) ;
k = printJedecBlock ( k , 11 , 78 ) ;
2023-09-23 03:05:12 +00:00
} else {
2023-11-22 00:31:08 +00:00
k = printJedecBlock ( k , galinfo . bits , galinfo . rows ) ;
2019-03-16 10:53:19 +00:00
}
2023-11-22 00:31:08 +00:00
if ( k < galinfo . uesfuse ) {
2023-10-03 12:02:43 +00:00
Serial . print ( ' L ' ) ;
printFormatedNumberDec4 ( k ) ;
Serial . print ( ' ' ) ;
2019-03-16 10:53:19 +00:00
2023-11-22 00:31:08 +00:00
while ( k < galinfo . uesfuse ) {
2019-03-16 10:53:19 +00:00
if ( getFuseBit ( k ) ) {
unused = 0 ;
2023-10-03 12:02:43 +00:00
Serial . print ( ' 1 ' ) ;
2019-03-16 10:53:19 +00:00
} else {
2023-10-03 12:02:43 +00:00
Serial . print ( ' 0 ' ) ;
2019-03-16 10:53:19 +00:00
}
k + + ;
}
2023-10-03 12:02:43 +00:00
Serial . println ( ' * ' ) ;
2019-03-16 10:53:19 +00:00
}
2023-03-25 19:53:13 +00:00
// UES in byte form
2019-03-16 10:53:19 +00:00
Serial . print ( F ( " N UES " ) ) ;
2023-11-22 00:31:08 +00:00
for ( j = 0 ; j < galinfo . uesbytes ; j + + ) {
2019-03-16 10:53:19 +00:00
n = 0 ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( getFuseBit ( k + 8 * j + i ) ) {
2023-12-09 10:56:24 +00:00
if ( gal = = ATF22V10C | | gal = = ATF750C ) {
2019-03-16 10:53:19 +00:00
n | = 1 < < ( 7 - i ) ; // big-endian
}
else {
n | = 1 < < i ; // little-endian
}
}
}
2023-10-07 11:33:21 +00:00
Serial . print ( ' ' ) ;
2019-03-16 10:53:19 +00:00
printFormatedNumberHex2 ( n ) ;
}
2023-10-07 11:33:21 +00:00
Serial . println ( ' * ' ) ;
2019-03-16 10:53:19 +00:00
2023-03-25 19:53:13 +00:00
// UES in bit form
2023-10-07 11:33:21 +00:00
Serial . print ( ' L ' ) ;
2019-03-16 10:53:19 +00:00
printFormatedNumberDec4 ( k ) ;
2023-10-07 11:33:21 +00:00
Serial . print ( ' ' ) ;
2023-09-16 12:34:47 +00:00
2023-11-22 00:31:08 +00:00
for ( j = 0 ; j < 8 * galinfo . uesbytes ; j + + ) {
2019-03-16 10:53:19 +00:00
if ( getFuseBit ( k + + ) ) {
2023-10-07 11:33:21 +00:00
Serial . print ( ' 1 ' ) ;
2019-03-16 10:53:19 +00:00
} else {
2023-10-07 11:33:21 +00:00
Serial . print ( ' 0 ' ) ;
2019-03-16 10:53:19 +00:00
}
}
2023-10-07 11:33:21 +00:00
Serial . println ( ' * ' ) ;
2019-03-16 10:53:19 +00:00
2023-03-25 19:53:13 +00:00
// CFG bits
2023-11-22 00:31:08 +00:00
if ( k < galinfo . fuses ) {
2023-10-07 11:33:21 +00:00
Serial . print ( ' L ' ) ;
2019-03-16 10:53:19 +00:00
printFormatedNumberDec4 ( k ) ;
2023-10-07 11:33:21 +00:00
Serial . print ( ' ' ) ;
2019-03-16 10:53:19 +00:00
2023-11-22 00:31:08 +00:00
while ( k < galinfo . fuses ) {
2019-03-16 10:53:19 +00:00
if ( getFuseBit ( k + + ) ) {
2023-10-07 11:33:21 +00:00
Serial . print ( ' 1 ' ) ;
2019-03-16 10:53:19 +00:00
} else {
2023-10-07 11:33:21 +00:00
Serial . print ( ' 0 ' ) ;
2019-03-16 10:53:19 +00:00
}
}
2023-03-25 19:53:13 +00:00
//ATF16V8C
if ( apdFuse ) {
2023-10-07 11:33:21 +00:00
Serial . print ( ' 1 ' ) ;
2023-03-25 19:53:13 +00:00
setFuseBit ( k ) ; // set for correct check-sum calculation
}
2023-10-07 11:33:21 +00:00
Serial . println ( ' * ' ) ;
2023-03-25 19:53:13 +00:00
} else if ( apdFuse ) { //ATF22V10C
2023-10-07 11:33:21 +00:00
Serial . print ( ' L ' ) ;
2023-03-25 19:53:13 +00:00
printFormatedNumberDec4 ( k ) ;
Serial . println ( F ( " 1* " ) ) ;
setFuseBit ( k ) ; // set for correct check-sum calculation
2019-03-16 10:53:19 +00:00
}
Serial . print ( F ( " N PES " ) ) ;
2023-11-22 00:31:08 +00:00
for ( i = 0 ; i < galinfo . pesbytes ; i + + ) {
2023-10-07 11:33:21 +00:00
Serial . print ( ' ' ) ;
2019-03-16 10:53:19 +00:00
printFormatedNumberHex2 ( pes [ i ] ) ;
}
2023-10-07 11:33:21 +00:00
Serial . println ( ' * ' ) ;
Serial . print ( ' C ' ) ;
2023-11-22 00:31:08 +00:00
printFormatedNumberHex4 ( checkSum ( galinfo . fuses + apdFuse ) ) ;
2019-03-16 10:53:19 +00:00
Serial . println ( ) ;
2023-10-07 11:33:21 +00:00
Serial . println ( ' * ' ) ;
2019-03-16 10:53:19 +00:00
}
// helper print function to save RAM space
static void printNoFusesError ( ) {
Serial . println ( F ( " ER fuse map not uploaded " ) ) ;
}
static void testVoltage ( int seconds ) {
int i ;
2023-01-24 20:17:49 +00:00
2023-03-27 20:58:14 +00:00
// New board design: set VPP to 16.5V and measure values
// on analogue pin A1
if ( varVppExists ) {
int16_t v ;
uint8_t okCnt = 0 ;
varVppSetMax ( ) ;
for ( i = 0 ; i < seconds ; i + + ) {
delay ( 1000 ) ;
v = varVppMeasureVpp ( 1 ) ; //measure and print
if ( v > = 1640 & & v < = 1664 ) {
okCnt + + ;
// stop early if the VPP is set correctly (still allow time for POT fine-tuning)
if ( okCnt > 3 ) {
Serial . println ( F ( " VPP OK " ) ) ;
i = seconds ;
}
} else {
okCnt = 0 ;
}
}
varVppSet ( VPP_5V0 ) ;
}
// Legacy board design: set the VPP_EN pin "On" and check
// with multimeter the desired VPP voltage specific for GAL chip.
else {
pinMode ( PIN_VPP , OUTPUT ) ;
setVPP ( 1 ) ;
for ( i = 0 ; i < seconds ; i + + ) {
delay ( 1000 ) ;
}
setVPP ( 0 ) ;
pinMode ( PIN_VPP , INPUT ) ;
2019-03-16 10:53:19 +00:00
}
}
2019-04-09 18:56:49 +00:00
// returns 1 if type check if OK, 0 if gal type does not match the type read from PES
static char doTypeCheck ( void ) {
2023-03-21 19:58:40 +00:00
if ( 0 = = flagBits & FLAG_BIT_TYPE_CHECK ) {
2023-03-30 21:58:51 +00:00
setGalDefaults ( ) ;
2019-04-09 18:56:49 +00:00
return 1 ; // no need to do type check
}
readPes ( ) ;
parsePes ( UNKNOWN ) ;
return testProperGAL ( ) ;
}
2023-03-27 20:58:14 +00:00
static void measureVpp ( uint8_t index ) {
varVppSet ( index ) ;
delay ( 150 ) ;
varVppMeasureVpp ( 1 ) ; //print measured value
delay ( 5000 ) ;
}
static void measureVppValues ( void ) {
if ( ! varVppExists ) {
Serial . println ( F ( " ER variable VPP not supported " ) ) ;
return ;
}
Serial . print ( F ( " VPP calib. offset: " ) ) ;
Serial . println ( calOffset ) ;
Serial . print ( F ( " VPP: 4.2 - 5.0V : " ) ) ;
measureVpp ( VPP_5V0 ) ;
Serial . print ( F ( " VPP: 9.0V : " ) ) ;
measureVpp ( VPP_9V0 ) ;
2024-02-02 21:38:50 +00:00
Serial . print ( F ( " VPP: 10.0V : " ) ) ;
measureVpp ( VPP_10V0 ) ;
2023-03-27 20:58:14 +00:00
Serial . print ( F ( " VPP: 12.0V : " ) ) ;
measureVpp ( VPP_12V0 ) ;
Serial . print ( F ( " VPP: 14.0V : " ) ) ;
measureVpp ( VPP_14V0 ) ;
Serial . print ( F ( " VPP: 16.0V : " ) ) ;
measureVpp ( VPP_16V0 ) ;
varVppSet ( VPP_5V0 ) ;
}
static void calibrateVpp ( void ) {
if ( ! varVppExists ) {
Serial . println ( F ( " ER variable VPP not supported " ) ) ;
return ;
}
if ( varVppCalibrate ( ) ) {
Serial . println ( F ( " Calibration OK " ) ) ;
}
}
2019-04-09 18:56:49 +00:00
// Arduino main loop
2019-03-16 10:53:19 +00:00
void loop ( ) {
// read a command from serial terminal or COMMAND_NONE if nothing is received from serial
char command = handleTerminalCommands ( ) ;
// any unexpected input when uploading fuse map terminates the upload process
if ( isUploading & & command ! = COMMAND_UTX & & command ! = COMMAND_NONE ) {
Serial . println ( F ( " ER upload aborted " ) ) ;
isUploading = 0 ;
lineIndex = 0 ;
}
// handle commands received from the serial terminal
switch ( command ) {
// print some help
case COMMAND_HELP : {
printHelp ( 1 ) ;
} break ;
case COMMAND_IDENTIFY_PROGRAMMER : {
printHelp ( 0 ) ;
} break ;
// verify fuse-map bits and bits read from the GAL chip
case COMMAND_VERIFY_FUSES : {
if ( mapUploaded ) {
2019-04-09 18:56:49 +00:00
if ( doTypeCheck ( ) ) {
readOrVerifyGal ( 1 ) ; //just verify, do not overwrite fusemap
}
2019-03-16 10:53:19 +00:00
} else {
printNoFusesError ( ) ;
}
} break ;
// handle upload command - start the download of fuse-map
case COMMAND_UPLOAD : {
short i ;
// clean fuses
for ( i = 0 ; i < MAXFUSES ; i + + ) {
fusemap [ i ] = 0 ;
}
2024-02-04 23:36:45 +00:00
sparseSetup ( 1 ) ;
2019-03-16 10:53:19 +00:00
isUploading = 1 ;
2019-04-09 18:56:49 +00:00
uploadError = 0 ;
2019-03-16 10:53:19 +00:00
} break ;
// command of the upload protocol
case COMMAND_UTX : {
parseUploadLine ( ) ;
} break ;
// read and print the PES
case COMMAND_READ_PES : {
char type ;
readPes ( ) ;
type = checkGalTypeViaPes ( ) ;
parsePes ( type ) ;
printPes ( type ) ;
} break ;
2023-03-30 22:00:21 +00:00
case COMMAND_WRITE_PES : {
char type ;
type = checkGalTypeViaPes ( ) ;
parsePes ( type ) ;
writePes ( ) ;
} break ;
2019-03-16 10:53:19 +00:00
// read fuse-map from the GAL and print it in the JEDEC form
case COMMAND_READ_FUSES : {
2019-04-09 18:56:49 +00:00
if ( doTypeCheck ( ) ) {
2019-03-16 10:53:19 +00:00
readOrVerifyGal ( 0 ) ; //just read, no verification
printJedec ( ) ;
}
} break ;
// write current fuse-map to the GAL chip
case COMMAND_WRITE_FUSES : {
if ( mapUploaded ) {
2019-04-09 18:56:49 +00:00
if ( doTypeCheck ( ) ) {
2019-03-16 10:53:19 +00:00
writeGal ( ) ;
2023-03-27 20:58:14 +00:00
//security is handled by COMMAND_ENABLE_SECURITY command
2019-03-16 10:53:19 +00:00
}
} else {
printNoFusesError ( ) ;
}
} break ;
// erases the fuse-map on the GAL chip
case COMMAND_ERASE_GAL : {
2019-04-09 18:56:49 +00:00
if ( doTypeCheck ( ) ) {
2023-03-30 22:00:21 +00:00
eraseGAL ( 0 ) ;
}
} break ;
// erases PES and the fuse-map on the GAL chip
case COMMAND_ERASE_GAL_ALL : {
if ( doTypeCheck ( ) ) {
eraseGAL ( 1 ) ;
2019-03-16 10:53:19 +00:00
}
} break ;
2023-03-25 19:40:03 +00:00
// sets the security bit
case COMMAND_ENABLE_SECURITY : {
if ( doTypeCheck ( ) ) {
secureGAL ( ) ;
}
} break ;
2023-03-25 19:53:13 +00:00
// keep atmel power-down feature enabled during write
case COMMAND_ENABLE_APD : {
setFlagBit ( FLAG_BIT_APD , 1 ) ;
Serial . println ( F ( " OK APD set " ) ) ;
} break ;
case COMMAND_DISABLE_APD : {
setFlagBit ( FLAG_BIT_APD , 0 ) ;
Serial . println ( F ( " OK APD cleared " ) ) ;
} break ;
2019-03-16 10:53:19 +00:00
// toggles terminal echo
case COMMAND_ECHO : {
echoEnabled = 1 - echoEnabled ;
} break ;
case COMMAND_TEST_VOLTAGE : {
testVoltage ( 20 ) ;
2019-04-09 18:56:49 +00:00
} break ;
case COMMAND_SET_GAL_TYPE : {
char type = line [ 1 ] - ' 0 ' ;
if ( type > = 1 & & type < LAST_GAL_TYPE ) {
gal = ( GALTYPE ) type ;
2023-11-22 00:31:08 +00:00
copyGalInfo ( ) ;
2023-03-21 19:58:40 +00:00
if ( 0 = = flagBits & FLAG_BIT_TYPE_CHECK ) { //no type check requested
setGalDefaults ( ) ;
2023-03-27 20:58:14 +00:00
}
2019-04-09 18:56:49 +00:00
} else {
2023-11-04 12:39:30 +00:00
Serial . print ( F ( " ER Unknown gal type " ) ) ;
Serial . println ( type , DEC ) ;
2019-04-09 18:56:49 +00:00
}
} break ;
case COMMAND_ENABLE_CHECK_TYPE : {
2023-03-21 19:58:40 +00:00
setFlagBit ( FLAG_BIT_TYPE_CHECK , 1 ) ;
2019-04-09 18:56:49 +00:00
} break ;
case COMMAND_DISABLE_CHECK_TYPE : {
2023-03-27 20:58:14 +00:00
int i = 0 ;
while ( i < 12 ) {
pes [ i + + ] = 0 ;
}
2023-03-21 19:58:40 +00:00
setFlagBit ( FLAG_BIT_TYPE_CHECK , 0 ) ;
2019-04-09 18:56:49 +00:00
} break ;
2023-03-27 20:58:14 +00:00
case COMMAND_MEASURE_VPP : {
measureVppValues ( ) ;
} break ;
// calibration offset helps to offset the resistor tolerances in voltage dividers and also
// small differences in analog ref which is ~3.3 V derived from LDO.
case COMMAND_CALIBRATION_OFFSET : {
int8_t offset = line [ 1 ] - ' 0 ' ;
2024-03-17 17:54:28 +00:00
if ( offset > = 0 & & offset < = 64 ) {
//0:-0.32V 1:-0.31V 2: -0.30V ... 32:0V 33:0.01V 34: 0.02V ... 64:0.32V
calOffset = offset - 32 ;
2023-03-27 20:58:14 +00:00
Serial . print ( F ( " Using cal offset: " ) ) ;
Serial . println ( calOffset ) ;
} else {
Serial . println ( F ( " ER: cal offset failed " ) ) ;
}
} break ;
case COMMAND_CALIBRATE_VPP : {
calibrateVpp ( ) ;
} break ;
2019-03-16 10:53:19 +00:00
default : {
if ( command ! = COMMAND_NONE ) {
Serial . print ( F ( " ER Unknown command: " ) ) ;
Serial . println ( line ) ;
}
}
}
// display prompt character - important for the PC program to check that Arduino
// finished the desired operation
if ( command ! = COMMAND_NONE ) {
Serial . println ( F ( " > " ) ) ;
}
// and that's it!
}