Quantcast
Viewing all articles
Browse latest Browse all 5139

General • Boot Stage 2 Code for Bare Metal Project

Pardon me if this is not the right place to ask someone to review my code. I have been trying to get this working for a week now but haven't figured out what the issue is, so I thought there is no better way than asking the experts for help.

Some background before we get to the actual problem. I have been learning bare metal programming on my own. As you expect, I am using Pi Pico for this purpose. So far I have been able to blink an LED from the boot2, setup XIP for standard (0x03) and quad output (0x6B) flash read accesses, jump to application code through vector table in flash. Following is the bootStage2 function I wrote that puts the flash into Quad-SPI mode and sets up XIP for Fast Read Quad Output (0x6B) instruction,

bootStage2.c

Code:

#include <stdint.h>#include <stdbool.h>// XIP#define XIP_BASE                    (0x10000000)// SSI#define SSI_BASE                    (0x18000000)#define SSI_CTRLR0                  (*(volatile uint32_t *) (SSI_BASE + 0x000))#define SSI_SSIENR                  (*(volatile uint32_t *) (SSI_BASE + 0x008))#define SSI_BAUDR                   (*(volatile uint32_t *) (SSI_BASE + 0x014))#define SSI_SR                      (*(volatile uint32_t *) (SSI_BASE + 0x028))#define SSI_DR0                     (*(volatile uint32_t *) (SSI_BASE + 0x060))#define SSI_SPI_CTRLR0              (*(volatile uint32_t *) (SSI_BASE + 0x0f4))// Boot stage 2 entry point__attribute__((section(".boot2"))) void bootStage2(void){    //  - Read 2 byte status register    SSI_SSIENR = 0; // Disable SSI to configure it    SSI_BAUDR = 4; // Set clock divider to 4    SSI_CTRLR0 = (7 << 16); // Set 8 clocks per data frame    SSI_SSIENR = 1; // Enable SSI    SSI_DR0 = 0x05; // Read Status Register 1    SSI_DR0 = 0x35; // Read Status Register 2    while ((SSI_SR & (1 << 2)) && (~SSI_SR & 1)); // Wait while Transmit FIFO becomes empty and SSI is not busy    uint8_t stReg1 = SSI_DR0; // Copy Status Register 1 value    uint8_t stReg2 = SSI_DR0; // Copy Status Register 2 value    //  - If QE bit is not set, then set QE bit    if (!(stReg2 & 1 << 1))    {        SSI_DR0 = 0x06; // Execute Write Enable Instruction        SSI_DR0 = 0x01; // Execute Write Status Register Instruction        SSI_DR0 = stReg1; // Write Status Register 1 value        SSI_DR0 = stReg2 | 1 << 1; // Status Register 2 value        SSI_DR0 = 0x04; // Execute Write Disable Instruction    }    //  - Configure SSI for Fast Read Quad Output Instruction (6Bh)    SSI_SSIENR = 0; // Disable SSI to configure it    SSI_CTRLR0 = (3 << 8) | (31 << 16) | (2 << 21); // Set SPI frame format to 0x2, EEPROM mode and 32 clocks per data frame    SSI_SPI_CTRLR0 = (6 << 2) | (2 << 8) | (0x6B << 24) | (8 << 11); // Set address length to 24-bits, instruction length to 8-bits, command to Read Data (6Bh) and set wait cycles to 8    SSI_SSIENR = 1; // Enable SSI        void (*main)(void) = (void (*)())0x10000101; // Note 0x10000100 + 0x1 (this forces the instructions to be interpreted as thumb)    main();    // Just to be safe if we come back here    while(true);}
I am having issue getting the Fast Read Quad IO (0xEB) instruction to work. The code given below is the implementation for it. The setup process is supposed to be relatively simple, 1. Put flash into Quad-SPI mode, 2. Send a dummy Read Quad IO (0xEB) with a 32-bit address containing mode continuation bits 0xA0 at [7:0], 3. Set up XIP to send only the address with mode continuation bits from the next time. I have spent hours checking my code and comparing it with assembly level implementation in pico-sdk: https://github.com/raspberrypi/pico-sdk ... _w25q080.S but I don't see the mistake I am making.

bootStage2QuadIO.c

Code:

#include <stdint.h>#include <stdbool.h>// XIP#define XIP_BASE                    (0x10000000)// SSI#define SSI_BASE                    (0x18000000)#define SSI_CTRLR0                  (*(volatile uint32_t *) (SSI_BASE + 0x000))#define SSI_SSIENR                  (*(volatile uint32_t *) (SSI_BASE + 0x008))#define SSI_BAUDR                   (*(volatile uint32_t *) (SSI_BASE + 0x014))#define SSI_SR                      (*(volatile uint32_t *) (SSI_BASE + 0x028))#define SSI_DR0                     (*(volatile uint32_t *) (SSI_BASE + 0x060))#define SSI_SPI_CTRLR0              (*(volatile uint32_t *) (SSI_BASE + 0x0f4))// Boot stage 2 entry point__attribute__((section(".boot2"))) void bootStage2(void){    //  - Read 2 byte status register    SSI_SSIENR = 0; // Disable SSI to configure it    SSI_BAUDR = 4; // Set clock divider to 4    SSI_CTRLR0 = (7 << 16); // Set 8 clocks per data frame    SSI_SSIENR = 1; // Enable SSI    SSI_DR0 = 0x05; // Read Status Register 1    SSI_DR0 = 0x35; // Read Status Register 2    while ((SSI_SR & (1 << 2)) && (~SSI_SR & 1)); // Wait while Transmit FIFO becomes empty and SSI is not busy    uint8_t stReg1 = SSI_DR0; // Copy Status Register 1 value    uint8_t stReg2 = SSI_DR0; // Copy Status Register 2 value    //  - If QE bit is not set, then set QE bit    if (!(stReg2 & 1 << 1))    {        SSI_DR0 = 0x06; // Execute Write Enable Instruction        SSI_DR0 = 0x01; // Execute Write Status Register Instruction        SSI_DR0 = stReg1; // Write Status Register 1 value        SSI_DR0 = stReg2 | 1 << 1; // Status Register 2 value        SSI_DR0 = 0x04; // Execute Write Disable Instruction    }    //  - Configure SSI for Fast Read Quad IO Instruction (EBh)    SSI_SSIENR = 0; // Disable SSI to configure it    SSI_CTRLR0 = (3 << 8) | (31 << 16) | (2 << 21); // Set SPI frame format to 0x2, EEPROM mode and 32 clocks per data frame    SSI_SPI_CTRLR0 = (8 << 2) | (2 << 8) | (4 << 11) | (0x1 << 0); // Set address length to 32-bits (Address + Mode), instruction length to 8-bits, set wait cycles to 4, and  Command in standard SPI and address in format specified by FRF    SSI_SSIENR = 1; // Enable SSI    //  - Perform a dummy read with mode bits set to 0xa0 to avoid sending the instruction again    SSI_DR0 = 0xeb; // Send Fast Read Quad I/O Instruction    SSI_DR0 = 0xa0; // Send address (0x0) + mode (0xa0) = 0b00000000000000000000000010100000    while ((SSI_SR & (1 << 2)) && (~SSI_SR & 1)); // Wait while Transmit FIFO becomes empty and SSI is not busy    //  - Configure SSI for sending the address and mode bits only    SSI_SSIENR = 0; // Disable SSI to configure it    SSI_SPI_CTRLR0 = (8 << 2) | (0 << 8) | (0xa0 << 24) | (4 << 11) | (0x2 << 0); // Set address length to 32-bits (Address + Mode), mode bits to append to address (0xa0), set wait cycles to 4, and  Command and address in format specified by FRF    SSI_SSIENR = 1; // Enable SSI        void (*main)(void) = (void (*)())0x10000101; // Note 0x10000100 + 0x1 (this forces the instructions to be interpreted as thumb)    main();    // Just to be safe if we come back here    while(true);}
It'd be great if someone here with fresh eyes and enough knowledge on the topic can help me find the problem. Thanks in advance.

Statistics: Posted by vxj9800 — Sun Oct 20, 2024 12:39 am



Viewing all articles
Browse latest Browse all 5139

Trending Articles