-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathicsp.cpp
157 lines (137 loc) · 4.62 KB
/
icsp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include "icsp.hpp"
#include <hardware/gpio.h>
#include <hardware/spi.h>
#include <pico/time.h>
static int dataOutPin = PICO_DEFAULT_SPI_TX_PIN, dataInPin = PICO_DEFAULT_SPI_RX_PIN, clockPin = PICO_DEFAULT_SPI_SCK_PIN, mclrPin = PICO_DEFAULT_SPI_TX_PIN + 1;
static spi_inst_t *spi;
void icsp_init(spi_inst_t *spi_, int pin_mclr, int pin_dat, int pin_clk, int pin_dat_in) {
gpio_init(pin_mclr);
gpio_init(pin_dat);
gpio_init(pin_clk);
gpio_set_function(pin_mclr, GPIO_FUNC_SIO);
gpio_set_function(pin_dat, GPIO_FUNC_SPI);
gpio_set_function(pin_clk, GPIO_FUNC_SPI);
gpio_set_dir(pin_mclr, GPIO_OUT);
gpio_set_dir(pin_dat, GPIO_OUT);
gpio_set_dir(pin_clk, GPIO_OUT);
if (pin_dat_in != -1) {
gpio_init(pin_dat_in);
gpio_set_function(pin_dat_in, GPIO_FUNC_NULL);
gpio_set_dir(pin_dat_in, GPIO_IN);
}
gpio_put(pin_mclr, true);
spi_init(spi_, 5'000'000); // 100 ns high + 100 ns low pulse width = 5 MHz
spi_set_slave(spi_, false);
spi_set_format(spi_, 8, SPI_CPOL_0, SPI_CPHA_1, SPI_MSB_FIRST);
dataOutPin = pin_dat;
dataInPin = pin_dat_in;
clockPin = pin_clk;
mclrPin = pin_mclr;
spi = spi_;
}
void icsp_enter_lvp() {
gpio_put(mclrPin, 0);
sleep_ms(5);
spi_write_blocking(spi, (const uint8_t*)"MCHP", 4);
sleep_ms(5);
}
void icsp_exit_lvp() {
gpio_put(mclrPin, 1);
sleep_ms(5);
}
void icsp_send_command(uint8_t cmd, int payload) __attribute__((optimize("O0")));
void icsp_send_command(uint8_t cmd, int payload) {
spi_write_blocking(spi, &cmd, 1);
if (payload >= 0) {
uint8_t pl[3] = {(payload >> 15) & 0xFF, (payload >> 7) & 0xFF, (payload << 1) & 0xFF};
spi_write_blocking(spi, pl, 3);
}
}
void icsp_cmd_loadpc(int pc) {
icsp_send_command(ICSP_COMMAND_LOAD_PC, pc);
}
void icsp_cmd_erase(int regions) {
icsp_send_command(ICSP_COMMAND_BULK_ERASE, regions);
sleep_ms(11);
}
void icsp_cmd_erase_page() {
icsp_send_command(ICSP_COMMAND_PAGE_ERASE, -1);
sleep_ms(11);
}
uint16_t icsp_cmd_read_data(bool increment_pc) {
if (dataInPin == -1) return 0xFFFF;
uint8_t cmd = (increment_pc ? ICSP_COMMAND_READ_DATA_INCPC : ICSP_COMMAND_READ_DATA);
spi_write_blocking(spi, &cmd, 1);
gpio_set_function(dataOutPin, GPIO_FUNC_NULL);
gpio_set_function(dataInPin, GPIO_FUNC_SPI);
uint8_t data[3];
spi_read_blocking(spi, 0, data, 3);
gpio_set_function(dataInPin, GPIO_FUNC_NULL);
gpio_set_function(dataOutPin, GPIO_FUNC_SPI);
return (data[0] << 15) | (data[1] << 7) | (data[2] >> 1);
}
void icsp_cmd_increment_pc() {
icsp_send_command(ICSP_COMMAND_INCREMENT_ADDRESS, -1);
}
void icsp_cmd_write_data(uint16_t value, bool increment_pc) {
icsp_send_command(increment_pc ? ICSP_COMMAND_PROGRAM_DATA_INCPC : ICSP_COMMAND_PROGRAM_DATA, value);
sleep_us(75);
}
uint16_t icsp_get_device_id() {
icsp_cmd_loadpc(0x3FFFFE);
sleep_us(1);
return icsp_cmd_read_data(false);
}
uint16_t icsp_get_revision_id() {
icsp_cmd_loadpc(0x3FFFFC);
sleep_us(1);
return icsp_cmd_read_data(false);
}
void icsp_write_data(int addr, const uint16_t * data, size_t size) {
icsp_cmd_loadpc(addr);
for (int i = 0; i < size; i++) icsp_cmd_write_data(data[i], true);
}
void icsp_write_data_8bit(int addr, const uint8_t * data, size_t size) {
icsp_cmd_loadpc(addr);
for (int i = 0; i < size; i++) {
icsp_cmd_write_data(data[i], true);
sleep_ms(11);
}
}
void icsp_read_data(int addr, uint16_t * data, size_t size) {
icsp_cmd_loadpc(addr);
for (int i = 0; i < size; i++) data[i] = icsp_cmd_read_data(true);
}
void icsp_read_data_8bit(int addr, uint8_t * data, size_t size) {
icsp_cmd_loadpc(addr);
for (int i = 0; i < size; i++) data[i] = icsp_cmd_read_data(true) & 0xFF;
}
void icsp_erase_page(int addr) {
icsp_cmd_loadpc(addr);
icsp_cmd_erase_page();
}
size_t icsp_program_page(int addr, uint16_t * data, size_t size, bool erase) {
icsp_cmd_loadpc(addr);
if (erase) icsp_cmd_erase_page();
for (int i = 0; i < size; i++) {
icsp_cmd_write_data(data[i], false);
if (dataInPin != -1) {
uint16_t word = icsp_cmd_read_data(true);
if (word != data[i]) return i;
}
}
return size;
}
size_t icsp_program_page_8bit(int addr, uint8_t * data, size_t size, bool erase) {
icsp_cmd_loadpc(addr);
if (erase) icsp_cmd_erase_page();
for (int i = 0; i < size; i++) {
icsp_cmd_write_data(data[i], false);
sleep_ms(11);
if (dataInPin != -1) {
uint8_t byte = icsp_cmd_read_data(true) & 0xFF;
if (byte != data[i]) return i;
}
}
return size;
}