Hello,
I want to read data from an external flash via SPI in master mode without interrupts. I checked that my SPI implementation is capable of waking up the external flash, configuring its internal segmentation and it also succeeds in reading out the status register of the external flash.
However, when I want to receive data that is stored at the external flash I always receive only 0xFF. In the code this is function ext_flash_main_memory_page_read(..).
I use an Adesto AT45DB641E as the external flash and I know that it is working and that there is data stored because I can read the data via my SPI implementation that uses interrupts. However I cannot use interrupts in my bootloader and that is why I need the polling-based implementation of SPI, too.
The corresponding parts of my code are printed below.
Thank you very much for any help!!
Stefan
----->>> my code:
int main(void)
{
// stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
// clear interrupt registers that may not be cleared by a PUC
IFG2 = 0; // USCI, Basic Timer
SD16IV = 0; // ADC
DAC12_0CTL = 0; // DAC
TACTL = 0; // Timer_A
TACCTL0 = 0; // TIMER_A0
TACCTL1 = 0; // TIMER_A1-3
P1IFG = 0; // Port1
P2IFG = 0; // Port2
IFG1 = 0; // WDT
CACTL1 = 0; // Comparator_A
TBCTL = 0; // Timer_B
TBCCTL0 = 0; // TIMER_B0
TBCCTL1 = 0; // TIMER_B1-3
//set clock
SCFQCTL = 121; // DCOCLK = (121+1)*fcrystal = 122 * 32.768 kHZ = 4,0 MHz
SCFI0 = 0; //FLLDx=0x00; FN_x=0x0000 (0.65 to 6.1 MHz)
FLL_CTL1 = XT2OFF; // turn off xt2 oscillator
// configure input port on PC_CS, here used to enforce boot mode
P2DIR = 0;
P2OUT = 0;
// configure SPI
//P5
P5DIR = BIT3; // flash CS
P5SEL = 0x00;
P5OUT = BIT3; // set FLASH_CS inactive high
//P3
P3DIR = 0;
P3SEL = (BIT1 | BIT2 | BIT3); //SPI MOSI 1 MISO 2 SCK 3
LCDAPCTL0 = 0x00;
// application start ///////////////////
// allocate memory for a buffer that is used multiple times for SPI operation and configuration
uint8_t cmd_buf[4];
// init SPI machinery
spi_init();
// wakeup flash
cmd_buf[0] = EXT_FLASH_CMD_WAKEUP;
if (!spi_send_receive(cmd_buf, 1))
{
return UPDATE_FAILED_OLD_APPLICATION_USABLE;
}
// set flash page size to EXT_FLASH_PAGE_SIZE bytes
cmd_buf[0] = 0x3D;
cmd_buf[1] = 0x2A;
cmd_buf[2] = 0x80;
cmd_buf[3] = 0xA6; // 256 byte mode
// cmd_buf[3] = 0xA7; // 264 byte mode
if (!spi_send_receive(cmd_buf, 4))
{
// make external flash again sleep
cmd_buf[0] = EXT_FLASH_CMD_SLEEP;
spi_send_receive(cmd_buf, 1);
return UPDATE_FAILED_OLD_APPLICATION_USABLE;
}
// read status register
cmd_buf[0] = 0xD7;
if (!spi_send_receive(cmd_buf, 3))
{
return UPDATE_FAILED_OLD_APPLICATION_USABLE;
}
// size of the new program code (in bytes)
uint16_t program_code_size = 0;
// get size of the new program code
if (!ext_flash_main_memory_page_read(EXT_FLASH_APPLICATION_UPDATE_LENGTH, reinterpret_cast<uint8_t*>(&program_code_size), 2))
{
// make external flash again sleep
cmd_buf[0] = EXT_FLASH_CMD_SLEEP;
spi_send_receive(cmd_buf, 1);
// and return
return UPDATE_FAILED_OLD_APPLICATION_USABLE;
}
....
....
}
// inits the spi machinery WITHOUT interrupts
void spi_init()
{
// hold USCI logic in reset state
UCB0CTL1 = UCSWRST;
// master-mode und MSB first
UCB0CTL0 = UCMST | UCMSB;// | UCSYNC;
// select SPI mode
UCB0CTL0 &= ~(UCCKPH | UCCKPL); // SPI mode 0
// clock source: SMCLK = 4,0 MHz
UCB0CTL1 |= UCSSEL1;
// prescaler LB
UCB0BR0 = 0x00;
// prescaler HB
UCB0BR1 = 0x00;
// set USCI state machine in operation
UCB0CTL1 &= ~UCSWRST;
}
// sends bytes via SPI and receives new bytes within the same buffer (NO interrupts)
bool spi_send_receive(uint8_t* buf, uint8_t len)
{
EXT_FLASH_CS_LOW; // high to low starts an operation and selects the flash because also the accelerometer is connected to SPI
// loop over buffer
while (len--)
{
// reset timeout
uint8_t timeout = 50;
// wait until transmit buffer is ready
while (!(IFG2 & UCB0TXIFG));
// write byte to transmit buffer
UCB0TXBUF = *buf;
// wait for new byte to be received (polling)
while (!(IFG2 & UCB0RXIFG))
{
// if timeout counter is not zero yet
if (timeout--)
{
// wait
__delay_cycles(100);
}
else
{
EXT_FLASH_CS_HIGH; // stop oeration
// return false on timeout
return false;
}
}
// read received byte
*buf = UCB0RXBUF;
// increase buffer pointer
buf++;
}
// wait until SPI is no longer busy
while (UCBUSY & UCB0STAT);
// dummy read to empty any remaining data in the receive buffer
uint8_t dummy = UCB0RXBUF;
EXT_FLASH_CS_HIGH; // stop oeration
return true;
}
// reads bytes from flash
uint8_t ext_flash_main_memory_page_read(const uint32_t address, uint8_t* const buf, const uint16_t len)
{
uint8_t cmd[8];
cmd[0] = EXT_FLASH_CMD_MMP_READ; // direct memory read without buffers
cmd[1] = (uint8_t)((address>>16)&0xFF); // 24bit address on the flash
cmd[2] = (uint8_t)((address>> 8)&0xFF);
cmd[3] = (uint8_t)(address&0xFF);
cmd[4] = EXT_FLASH_CMD_DUMMY;
cmd[5] = EXT_FLASH_CMD_DUMMY;
cmd[6] = EXT_FLASH_CMD_DUMMY;
cmd[7] = EXT_FLASH_CMD_DUMMY;
// enter dummy data of the amount of bytes we want to read
for (uint16_t i = 0; i < len; i++)
{
buf[i] = EXT_FLASH_CMD_DUMMY;
}
EXT_FLASH_CS_LOW;
// send command and receive unused answer of same amount
if (!spi_send_receive(cmd, 8))
{
EXT_FLASH_CS_HIGH;
return 0;
}
// receive the answer by sending dummy data
if (!spi_send_receive(buf, len))
{
EXT_FLASH_CS_HIGH;
return 0;
}
EXT_FLASH_CS_HIGH;
return 1;
}