Something I’ve never really been strong in…bit shifting.
Taking this statement from a data sheet on the Atmell AT45DB04 spi flash it says to read from a buffer
Data can be read from either one of the two buffers, using different opcodes to specify which
buffer to read from. An opcode of 54H or D4H is used to read data from buffer 1, and an opcode
of 56H or D6H is used to read data from buffer 2. To perform a Buffer Read, the eight bits of the
opcode must be followed by 15 don’t care bits, nine address bits, and eight don’t care bits.
How the heck do you translate that to C lol
A rough stab at it:
//32 total bits
/* 15 “Don’t care” bits /
spi_transfer(0x00); // 8 bits
/ Rest of the “don’t care” bits + 9 address bits /
spi_transfer((uint8_t)(offset >> 7)); // uuuhhhh im stuck here
spi_transfer((uint8_t)(offset ??? ));
/ + 8 dont care bits */
spi_transfer(0x00);
Fortunately, that adds up to a whole multiple of bytes.
I’d start by putting your data into a buffer, for example:
unsigned char stuff[5];
stuff[0] = 0x5d; /* 8 bit command /
stuff[1] = 0; / 8 of the don’t care bits /
stuff[2] = (address & 0x100) >> 8; / 7 of the don’t care bits, plus one of address */
Finish that progression and then send the buffer out. Some of this is intentionally left as an exercise for the reader.
If you have trouble visualizing where each bit goes, I find it easiest to resort to sketching it out on paper. Your example is no so difficult as you are not combining parts of two different values into one byte.
Thanks. I’m familiar with the operators. Its the visualization I need to tinker with. I haven’t had much need for bit shifting in my development career (web, database, etc). I know how bit shifting works and what it’s doing but in terms of transforming datasheet “protocols” into the shifting techniques that I see in someone else’s code, and the examples here is the form of the art, that’s where I’m sketchy on.
Ok just to close the topic, I have figured out a way to explain this logic to myself so that I can grasp it, thanks to the input of everyone here. Specifically drawing it out helped a lot.
So here is what I came up with.
My original problem came from attempting to adapt some code that was written for the 16 megabit atmel dataflash to the 4 megabit version of the same chip. Their are subtle differences in the SPI communications for each size dataflash.
The function I was working with is shown below:
/**
* Main Memory Page Read.
* A main memory page read allows the user to read data directly from
* any one of the 4096 pages in the main memory, bypassing both of the
* data buffers and leaving the contents of the buffers unchanged.
*
* @param page Page of the main memory to read
* @param offset Starting byte address within the page
**/
void ATD45DB161D::ReadMainMemoryPage(uint16_t page, uint16_t offset)
{
DF_CS_inactive; /* Make sure to toggle CS signal in order */
DF_CS_active; /* to reset Dataflash command decoder */
/* Send opcode */
spi_transfer(AT45DB161D_PAGE_READ);
/* Address (page | offset) */
spi_transfer((uint8_t)(page >> 6));
spi_transfer((uint8_t)((page << 2) | (offset >> 8)));
spi_transfer((uint8_t)(offset & 0xff));
/* 4 "don't care" bytes */
spi_transfer(0x00);
spi_transfer(0x00);
spi_transfer(0x00);
spi_transfer(0x00);
}
It turns out it was quite a simple task of changing:
But I wanted to understand the syntax therefore I posed the query here.
The gist of it is, that the shifting of the bits aligns them in such a way that in the space of three bytes we have all the expected data the chip needs to understand the command we’re giving it.
A long form way of approaching this is with a struct as proposed earlier. But this is rarely seen in the wild. Most C developers use the shorthand bit shift above. It’s elegant in its simplicity as long as you grasp whats happening.