On spi you read and write at the same time, the write function returns the data received while it was writing.
So to read a value you first write the address you want to read and then you write something (anything, it doesn't matter normally) that is the same length as the data you expect to get back. 0 is a nice safe value to write.
As for the actual syntax used, the |= is in there because the code is reading a value longer than 1 byte and needs to combine multiple reads into a single value.
value |= spi.write()
is shorthand for
value = value | spi.write()
every time that is called in the code it is guaranteed that the least significant 8 bits of value will be 0 which means it's effectively the same as saying
value = value + spi.write()
If you look at the code the line afterwards is normally
value = value << 8;
which then shifts value to the left 8 bits ensuring that the least significant 8 bits are again 0.
In terms of end result
value = 0;
value |= _spi.write(0x00);
value = value << 8;
value |= _spi.write(0x00);
value = value << 8;
value |= _spi.write(0x00);
Is identical to
value = 0;
value = value + _spi.write(0x00);
value = value * 256;
value = value + _spi.write(0x00);
value = value * 256;
value = value + _spi.write(0x00);
They both read 3 bytes and combine the result into a single number.
So why do it the first way?
Because bitwise operators like | and << are just about the fastest operations possible on a CPU. Additions and multiplies can be significantly slower.
Dear all,
I am trying to connect a Direct Digital Synthesizer via the SPI interface to the mbed controller. Since I never worked with electronic boards/ circuits and C it is a bit difficult for me to find the mistakes.
I found the code from Remy for the AD 9951 (http://mbed.org/forum/helloworld/topic/1664/?page=1#comment-8348) and modified it a bit. I use it in the form posted below.
The datasheet of the AD 9954 DDS is here http://www.analog.com/static/imported-files/data_sheets/AD9954.pdf I connected the pins as follows
I get no output on the oscilloscope and in the Tera Term it just reads out c2= 0 FTWO = 0
I really don't know what is going wrong. Maybe one of you can give me a tip?
####AD9954.h########ifndef AD9954_H #define AD9954_H #include "mbed.h" class AD9954 { protected: SPI _spi; DigitalOut _cs; DigitalOut _rst; public: AD9954(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName rst) : _spi(mosi, miso, sclk), _cs(cs), _rst(rst) { // see http://mbed.org/handbook/SPI and page 23 why format 0 _spi.format(8, 0); _spi.frequency(1000000); // master reset the device: _rst.write(1); wait(0.1); _rst.write(0); }; // Write a 32bit register at the specified address. void write_reg_4byte(uint32_t address, uint32_t value) { // Instruction byte: page 25 in datasheet, we want to write (0), so 0100 + internal adress of the register to be written in _spi.write(0x00 | (address & 0x1F)); _spi.write((value >> 24) & 0xFF); _spi.write((value >> 16) & 0xFF); _spi.write((value >> 8) & 0xFF); _spi.write((value >> 0) & 0xFF); } // Write a 24bit register at the specified address. void write_reg_3byte(uint32_t address, uint32_t value) { // Instruction byte: page 25 in datasheet, we want to write (0), so 0100 + internal adress of the register to be written in _spi.write(0x00 | (address & 0x1F)); _spi.write((value >> 16) & 0xFF); _spi.write((value >> 8) & 0xFF); _spi.write((value >> 0) & 0xFF); } // Read a 32bit register at the specified address. uint32_t read_reg_4byte(uint32_t address) { uint32_t value = 0x00000000; _spi.write(0x80 | (address & 0x1F)); // Instruction byte value |= _spi.write(0x00); value = value << 8; value |= _spi.write(0x00); value = value << 8; value |= _spi.write(0x00); value = value << 8; value |= _spi.write(0x00); return value; } uint32_t read_reg_3byte(uint32_t address) { uint32_t value = 0x000000; _spi.write(0x80 | (address & 0xF)); // Instruction byte value |= _spi.write(0x00); value = value << 8; value |= _spi.write(0x00); value = value << 8; value |= _spi.write(0x00); return value; } // Write void CFR1_write(uint32_t reg) { write_reg_4byte(0x00, reg); } void CFR2_write(uint32_t reg) { write_reg_3byte(0x01, reg); } void FTW0_write(uint32_t reg) { write_reg_4byte(0x04, reg); } // Read uint32_t CFR1_read(void) { return read_reg_4byte(0x0); } uint32_t CFR2_read(void) { return read_reg_3byte(0x1); } uint32_t FTWO_read(void) { return read_reg_4byte(0x4); } }; #endif##### main########include "mbed.h" #include "AD9954.h" Serial pc(USBTX, USBRX); DigitalOut myled(LED1); DigitalOut _fud(p10); AD9954 myDevice(p5, p6, p7, p8, p9); int main() { _fud.write(0); // in register 2: //bit3-bit7 contain the multiplication value for the clock. multiply the 10 MHz input by 10: [01010], the vco is then not in the upper range, therefore bit2=0, // from this follows bit7-bit0: 00 00 0101 0000 -> 00 00 50 myDevice.CFR2_write(000050); // now we have a 100 MHz clock, the frequency tuning word for around 6 MHz output is ((12.5:2)/100)*2^(32) =268435456 //= 10000000 myDevice.FTW0_write(0x10000000); // issue I/O update _fud.write(1); wait(0.1); _fud.write(0); uint32_t c2; c2 = myDevice.CFR2_read(); pc.printf("c2= %X\n", c2); uint32_t ftwo; ftwo = myDevice.FTWO_read(); pc.printf("FTWO = %X\n", ftwo); return 0; }