ATmega164PA Bootloader - SPMCSR Erase Bit hängt

OP #3513466
Lesenswert?

Moin,

ich arbeite gerade mit Codevision an einem Bootloader für den 
ATmega164PA.
Ich kann nicht zu 100% auf die gelieferten Beispiele zurückgreifen 
(Interface, Formatierung im System, etcpp.).

Ein Windows Programm liest ein hex-File, überprüft es, wandelt es in 
binär um und sendet Zeile für Zeile an den AVR, der jede empfangene und 
geschrieben Zeile quittiert, so dass die nächste gesendet wird.

Die folgenden Teile funktionieren:
- Datenübertragung per UART
- Flash auslesen
- Parser der Hex-Daten
- Page Buffer füllen

Jetzt die Probleme:
Nach jeder Erase oder Write Anweisung auf das SPMCSR Register bleibt das 
Erase-Bit gesetzt! Sogar wenn Write-Command vorher gesetzt wurde (0x05 
in SPMCSR schreiben).
Das hat zur Folge, dass genau eine Seite geschrieben wird, beim nächsten 
SPM_busy_wait() hängt's dann.
Löschen geht auch (übrigens nur der ganze Flash, nicht einzelne Seite), 
danach hängt das Erase-Bit auch noch.

Wahrscheinlich sehe ich den Wald vor lauter Bäumen nicht - vlt. seht ihr 
es ja?!

Zur Erläuterung:
Nach jeder empfangenen hex-File-Zeile wird bootload_ctl() aufgerufen.
bootload_ctl() prüft per ihex_line_parser() die Daten, wenn okay wird in 
ihex2flash() der Page Buffer gefüllt und wenn voll geschrieben.
1
/* ########################################################################## */
2
/* include */
3

4
#include "ATmega164PA_BtLdr.h"
5
#include "Bootloader.h"
6

7

8
/* ########################################################################## */
9
/* code constants */
10

11

12
/* ########################################################################## */
13
/* variables */
14

15
u16_t ihex_line_dest_addr = 0;
16
u8_t ihex_line_dat_len = 0;
17
u8_t ihex_line_dat_type = 0;
18
u8_t ihex_line_dat_buf[32];
19

20
u16_t flash_page_num = 0;
21
u16_t flash_page_addr = 0;
22
u16_t flash_cnt = 0;
23

24
u8_t SPM_timer = 0;
25

26
/* ########################################################################## */
27
/* local functions: */
28

29

30
/* ########################################################################## */
31
/* global functions */
32

33
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
34
/* bootloader control */
35
void bootload_ctl(void)
36
{
37
  u8_t parser_ret;
38
  u8_t write_ret;
39

40
  /* check line from hex file */
41
  parser_ret = ihex_line_parser();
42

43
  if( parser_ret == IHEX_LINE_OKAY )
44
  {
45
    /* write to flash */
46
    write_ret = ihex2flash(IHEX_RECTYP_DATA);
47

48
    TX1_byte(write_ret);
49
  }
50
  else if( parser_ret == IHEX_LINE_EOF )
51
  {
52
    /* write last data, fill rest with 0xFF */
53
    write_ret = ihex2flash(IHEX_LINE_EOF);
54
    /* send message we're done */
55
    TX1_byte(write_ret);
56
  }
57
  else TX1_byte(parser_ret);
58

59
  /* reset RX1 stuff */
60
  mem_set(RX1_buffer, 0x00, (u16_t)sizeof(RX1_buffer));
61
  RX1_timer = UART1_TIMEOUT_MAX;
62
  RX1_ihex_avl = 0;
63
}
64

65

66
/* check received line, length, CRC, data type - no ASCII !!! */
67
u8_t ihex_line_parser(void)
68
{
69
  u8_t i;
70
  u16_t crc_sum = 0;
71

72
  /* check start code and length */
73
  if( RX1_buffer[0] != ':' || RX1_counter < IHEX_LINE_OVERHEAD_BIN ) return IHEX_ERROR_STRT_LEN;
74

75
  /* get data length in line */
76
  ihex_line_dat_len = RX1_buffer[1];
77

78
  /* get flash address */
79
  ihex_line_dest_addr = (u16_t)RX1_buffer[2] << 8;
80
  ihex_line_dest_addr += (u16_t)RX1_buffer[3];
81

82
  /* get data type */
83
  ihex_line_dat_type = RX1_buffer[4];
84

85
  /* CRC check, add all execept ':', incl CRC byte, lower byte sum must be 0 */
86
  for( i = 1; i < RX1_counter; i++ ) crc_sum += (u16_t)RX1_buffer[i];
87
  crc_sum &= 0x00FF;
88
  if( crc_sum != 0 ) return IHEX_ERROR_CRC;
89

90
  /* get data and copy to buffer */
91
  if( ihex_line_dat_type == IHEX_RECTYP_DATA && ihex_line_dat_len != 0 )
92
  {
93
    for( i = 0; i < ihex_line_dat_len; i++ )
94
    {
95
      ihex_line_dat_buf[i] = RX1_buffer[i + 5];
96
    }
97
  }
98
  /* extended address for > 64kB? */
99
  else if( ihex_line_dat_type == IHEX_RECTYP_XSADR )
100
  {
101
    /* for now just return error code */
102
    return IHEX_ERROR_EXTADDR;
103
  }
104
  /* EOF? */
105
  else if( ihex_line_dat_type == IHEX_RECTYP_EOF &&
106
    RX1_counter == IHEX_LINE_OVERHEAD_BIN )
107
  {
108
    return IHEX_LINE_EOF;
109
  }
110
  else return IHEX_FLASH_FT_ERROR;
111

112
  return IHEX_LINE_OKAY;
113
}
114

115

116
/* write line from hex file to flash page buffer */
117
u8_t ihex2flash(u8_t dat_type)
118
{
119
  u8_t ret_val;
120
  u8_t i;
121
  u16_t page_addr_b;
122

123
/* - writing flash page by page
124
 * - a complete page must be written
125
 * - data must be collected until page is full
126
 *
127
 *  1) fill page buffer
128
 *  2) erase page
129
 *  3) write page
130
 *
131
 */
132

133
/* end of hex file, write current page buffer to flash */
134
  if( dat_type == IHEX_LINE_EOF )
135
  {
136
    if( flash_cnt != 0 )
137
    {
138
      eeprom_busy_wait();
139

140
      /* erase page */
141
    //  SPM_processing((void flash *)flash_page_num, SPM_CMND_ERASE_PAGE);
142
    //  SPM_processing(flash_page_num, SPM_CMND_ERASE_PAGE);
143
    //  boot_spm_busy_wait();
144

145
      /* write page */
146
      SPM_processing((void flash *)flash_page_num, SPM_CMND_WRITE_PAGE);
147
      if( boot_spm_busy_wait() ) ret_val = IHEX_FLASH_EOF_TO;
148
      SPM_R0_to_SPM(0, SPM_CMND_ENABLE_RWW);
149

150
      /* reset stuff */
151
      flash_page_num = 0;
152
      flash_cnt = 0;
153
      flash_page_addr = 0;
154
    }
155
    ret_val = IHEX_FLASH_WR_END;
156
  }
157
/* copy data from new line to page buffer, erase & write page */
158
  else
159
  {
160
    for( i = 0; i < ihex_line_dat_len; i += 2 )
161
    {
162
      flash_page_addr = flash_page_num + flash_cnt;
163
      page_addr_b = flash_page_addr;// << 1;
164

165
      SPM_fill_page_buffer((void flash *)page_addr_b, ihex_line_dat_buf[i+1], ihex_line_dat_buf[i], SPM_CMND_FILL_PAGE_BUF);
166
/* hängt hier nach erstem page write */
167
LED2_GREEN;
168
      if( boot_spm_busy_wait() ) ret_val = IHEX_FLASH_FILL_TO;
169
LED2_OFF;
170

171
      flash_cnt += 2;
172

173
      /* page buffer full => erase page => write page! */
174
      if( flash_cnt == SPM_PAGE_SIZE )
175
      {
176
        eeprom_busy_wait();
177

178
        /* erase page */
179
      //  SPM_processing((void flash *)flash_page_num, SPM_CMND_ERASE_PAGE);
180
      //  SPM_processing(flash_page_num, SPM_CMND_ERASE_PAGE);
181
      //  boot_spm_busy_wait();
182

183
        /* write page */
184
        SPM_processing((void flash *)flash_page_num, SPM_CMND_WRITE_PAGE);
185
LED2_RED;
186
/* hier hängt's nach 1. page write! */
187
        if( boot_spm_busy_wait() ) ret_val = IHEX_FLASH_WR_TO;
188
LED2_OFF;
189
        SPM_R0_to_SPM(0, SPM_CMND_ENABLE_RWW);
190

191
        /* new page */
192
        page_addr_b = flash_page_num;
193
        flash_page_num = ihex_line_dest_addr - (ihex_line_dest_addr % SPM_PAGE_SIZE);
194
        if( flash_page_num == page_addr_b ) flash_page_num += SPM_PAGE_SIZE;
195
        flash_cnt = 0;
196
      }
197
    }
198
    ret_val = IHEX_FLASH_LINE_WR;
199
  }
200

201
LED2_OFF;
202

203
  return ret_val;
204
}
205

206

207
#pragma warn-
208
/* call: SPM_fill_page_buffer((void flash *)addr, ... */
209
/* fill buffer */
210
void SPM_fill_page_buffer(void flash *addr, u8_t dat_hi, u8_t dat_lo, u8_t cmnd)
211
{
212
#asm
213
  cli
214
  ldd    r30,y+3
215
  ldd    r31,y+4
216
  ldd    r0,y+1
217
  ldd    r1,y+2
218
  ld     r22,y
219
  WR_SPMCR_REG_R22
220
  spm
221
  sei
222
#endasm
223
}
224

225

226
/* call: SPM_processing((void flash *)addr, ... */
227
/* erase page (cmnd = 0x03) / write buffer to page (cmnd = 0x05) */
228
void SPM_processing(void flash *addr, u8_t cmnd)
229
{
230
#asm
231
  cli
232
  ldd    r30,y+1
233
  ldd    r31,y+2
234
  ld     r22,y
235
  WR_SPMCR_REG_R22
236
  spm
237
  sei
238
#endasm
239
}
240

241

242
/* ??? */
243
void SPM_R0_to_SPM(u8_t data, u8_t cmnd)
244
{
245
#asm
246
  cli
247
  ldd    r0,y+1
248
  ld     r22,y
249
  WR_SPMCR_REG_R22
250
  spm
251
  sei
252
#endasm
253
}
254
#pragma warn+
255

256

257
/* read flash */
258
void SPM_read_flash(u16_t addr, u16_t len)
259
{
260
  u8_t byte;
261

262
  do
263
  {
264
  #if(0)
265
  /* ASCII, takes too much prog space */
266
    if( (len % 16) == 0 ) TX1_byte('\n');
267
    TX1_byte('0');
268
    TX1_byte('x');
269
    byte = (u8_t)*((u8_t flash *)addr);
270
    TX1_byte(hex_char[(byte & 0xF0) >> 4]);
271
    TX1_byte(hex_char[ byte & 0x0F]);
272
    TX1_byte(' ');
273
  #endif
274

275
    byte = (u8_t)*((u8_t flash *)addr);
276
    TX1_byte(byte);
277
    addr++;
278
    len--;
279
  } while( len );
280
}
281

282

283
u8_t boot_spm_busy_wait(void)
284
{
285
LED1_RED;
286
  SPM_timer = 10;      /* *100 ms */
287
  while( SPMCSR )//& (1<<SPMEN) )
288
  {
289
    if( SPM_timer == 0 ) return 1;
290
  };
291
LED1_GREEN;
292
  return 0;
293
}
294

295

296
void eeprom_busy_wait(void)
297
{
298
  while( EECR & (u8_t)(1<<EEPE) );
299
}
300

301

302
void mem_set(u8_t *buf, u8_t val, u16_t len)
303
{
304
  u16_t i = 0;
305

306
  for( i = 0; i < len; i++ ) buf[i] = val;
307
}
Gast #3516744
Lesenswert?

Hm. Schwer zu sagen. Dein COde macht es einem nicht gerade einfach, 
schnell die wesentlichen Dinge zu finden.

Wie auch immer, SPEM sollte immer irgendwann zurückgesetzt werden. 
Sicher, daß dein Timeout-Timer richtig taktet?

Oliver
OP #3516766
Lesenswert?

Nachfragen hilft einem immer, die Fehler dann selbst zu finden...
Ich hatte das SPMCSR per UART falsch ausgelesen (bit inversion...), es 
hing das RWWSB bit.
Also boot_spm_busy_wait() wieder nur auf SPMEN geändert, und noch ein 
boot_spm_busy_wait() hinter das re-enable des RWW-Bereichs, jetzt 
geht's.
Aua...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren