/*! * Read SPI device ID. * * \param id Three byte character array, which receives * the CPU ID. */ void SpiFlashId(u_char * id) { u_char i; for (i = 0; i < 3; i++) { SpiByte(0x30); SpiByte(0x00); SpiByte(i); id[i] = SpiByte(0x00); } }
/*! * \brief Read memory chip status. */ static uint8_t SpiMemStatus(uint8_t cs) { uint8_t rc; if (cs == SPIMEM_CS_BIT) { sbi(SPIMEM_CS_PORT, cs); } else { cbi(SPIMEM_CS_PORT, cs); } SpiByte(0x57); rc = SpiByte(0); if (cs == SPIMEM_CS_BIT) { cbi(SPIMEM_CS_PORT, cs); } else { sbi(SPIMEM_CS_PORT, cs); } return rc; }
/*! * \brief Write byte to the target's flash memory. * * The target must have been erased by a previous call * to SpiFlashErase(). * * \param high Must be 0 to write the low byte or 8 to * write the high byte. * \param addr Word address to write to. * \param data Byte value to write. * * \return 0 on success, -1 otherwise. */ int SpiFlashWriteByte(u_char high, u_short addr, u_char data) { u_char d; if (data != 0xff) { SpiByte(0x40 | high); SpiByte(addr >> 8); SpiByte(addr & 0xFF); SpiByte(data); /* * During programming a value of 0x7F appears at the memory location. * If we are programming this value, we delay execution by 10 ms. * Otherwise we poll the memory location until we read back the * programmed value. */ if (data == 0x7f) NutDelay(10); else { for (d = 0; d < 255; d++) { /* * Read program flash byte. */ SpiByte(0x20 | high); SpiByte(addr >> 8); SpiByte(addr & 0xFF); if (SpiByte(0xFF) == data) break; } if (d == 255) return -1; } }
/*! * \brief Enable SPI device flash programming. * * \return 0 if device could be located, -1 otherwise. */ int SpiFlashEnable(void) { u_char i; u_char rc; /* * PB0(O): SS * PB1(O): SCK * PB2(O): MOSI * PB3(I): MISO * * PB4(O): Reset target * PB5(-): Unused * PB6(-): Unused * PB7(-): Unused */ /* * SCK and MOSI outputs need configuration, * even if SPI mode is enabled. */ cbi(PORTB, 1); sbi(DDRB, 1); cbi(PORTB, 2); sbi(DDRB, 2); /* * Enable pull-up on MISO. */ sbi(PORTB, 3); for (i = 0; i < 32; i++) { /* * Set reset low. */ cbi(PORTB, 4); sbi(DDRB, 4); /* * Set slave select pin to output. Otherwise a low signal * on this pin might force us to SPI slave mode. */ sbi(DDRB, 0); outp(BV(MSTR) | BV(SPE) | BV(SPR0), SPCR); /* * Try to enable programming. */ SpiByte(0xAC); SpiByte(0x53); rc = SpiByte(0xFF); SpiByte(0xff); if (rc == 0x53) return 0; /* * Programming enable failed. This may be because the * target is not synchronized. A positive pulse on the * clock line should help. */ outp(0, SPCR); sbi(PORTB, 1); cbi(PORTB, 1); } return -1; }