Forum: Mikrocontroller und Digitale Elektronik ATmega164PA Bootloader - SPMCSR Erase Bit hängt


von X- R. (x-rocka)


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
}

von X- R. (x-rocka)


Lesenswert?

Irgendjemand eine Idee?

von Oliver (Gast)


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

von X- R. (x-rocka)


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...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.