MAX5825 full scale on 8 bits - raspberry-pi

I am using a MAX5825 as an external DAC for RPi.
According to the datasheet, the resolution of this component is 12 bits.
As I read, I'm supposed to write the value I want to set in the CODEn (0x8n) register, n being the DAC channel I want to set, and then write anything in the LOADn (0x9n) register, or use the CODEn_LOADn (0xBn) register to do it in one step. See here the datasheet extract.
I'm using pigpio daemon library to interface I²C communication
void AnalogOutput::updateValue(int value) {
i2c_write_word_data(my_pi_device, my_handler, 0xB0, value << 4);
}
This is supposed to set my CODE0 register to the value parameter.
However, I had a strange behavior so I tried to read the data from CODEn (0x80) register to watch if my set attempt was correct.
i2c_read_word_data(my_pi_device, my_handler, 0x80);
I'm not sure I can read a value from a command register tho, but when my value exceed 0xFF, the return I get from I²C reading looks like value & 0xFF. (i.e. when I set the register to 0xFF I read 0xFF in the register, when I set the register to 0x100 I read 0x00)
Also, the output voltage of my DAC0 channel is at its maximum scale when CODEn register is set to 0xFF. I used 4.0V internal reference and when I set value to 0xFF, the output voltage is 4.0V-ish.
I don't understand why is 0xFF the maximum scale on a 12-bits resolution DAC ? Am I missing a way to configure the resolution or anything like that ?
What I've tried so far :
Remove the << 4 shifting on the set value : no change on the behavior
Invert the LSByte and MSByte written to the CODEn register (I've seen
on pigpiod API SMBus standard was supposed to send LSByte then MSByte
in a word writing procedure) : the reading of CODEn register was
jumping over 0x0FFF value. MAX5825 is supposed to be compatible with
SMBus standard tho.
Use i2c_write_block_data instead of
i2c_write_word_data function of pigpiod lib : no change on the
behavior.
Thanks for your time !
References :
MAX5825 datasheet : https://datasheets.maximintegrated.com/en/ds/MAX5823-MAX5825.pdf
pigpio API : https://abyz.me.uk/rpi/pigpio/pdif2.html

Ok I got it fixed using i2cget & i2cset, my supposition about LSByte & MSByte was right.
CODEn registers are filled with 12 MSB. That means a set value of 0x0ABC needs to be stored in CODEn register by : 0xABC0. pigpio following SMBus standard send I²C word message with LSByte first and then MSByte, so if I send 0x0ABC message through I²C it will actually send 0xBC0A. When I tried to invert LSByte and MSByte, I was sending through I²C the message 0xBC0A so what was stored inside MAX5825 was 0x0AB.
One functionnal workaround would be :
void AnalogOutput::updateValue(int value) {
int codeRegisterData = (value >> 4) + ((value & 0xF)<<12);
i2c_write_word_data(my_pi_device, my_handler, 0xB0, codeRegisterData);
}
If value = 0x0ABC, codeRegisterData would be = 0xC0AB so pigpio will write over the I²C bus into the CODEn register the message 0xABC0.

Related

16-bit addresses register in i2c stm32

i want to write in AT24C512 with stm32f103c8 i send my code.
HAL_I2C_Mem_Write(&hi2c1, 0XA0, 0X11FA,I2C_MEMADD_SIZE_16BIT , &write_data, 1, 100);
For example, I want to put the value of write_data on 0x11FA, and I specify the memory address as 16 bits, but it is always sent as 8 bits, and AT24C512 seems to receive only the first byte of 0x11FA It means AT24C512 receive just 0x11 and its not difference if i set mt address register to 0x1167 0x11FF 0x11A0 all these address is same for AT24C512.
what should I do?
Because I used the module, I am sure the hardware have no problem
i want to write and read correctly in AT24C512 with stm32f103c8.

Cannot init NRF24L01+ registers using SPI and STM32F303

Am trying to initialize the NRF24L01+ registers using SPI but they always return 0x00.
According to the datasheet, Table 20 on page 51, all write commands will have a pattern of b001x xxxx, which i understood as having a 0x2x pattern.
In my snapshot below, i send the register value, for example register 0x00 will be sent as 0x20 indicating a write command to that register and then i send the value to be written on that register.
As you see on the MISO line, the value is 0x00 even when am trying to write a 0x08 which should be the default value according to page 57 of the datasheet.
I still dont know why its returning 0x00 even when i independently try to read the contents of that register later on without writing to it. I still get 0x00. The same applies to all other registers that am trying to re-init.
Anyone who has experienced this behaviour elsewhere or is it me that is having something wrong?
The NRF24 am trying to program here is this type from sparkfun
You are close. The datasheet shows write register as 001A AAAA and read as 000A AAAA, where the 5 A's represent the register you want to write to. The spec states that while the command is being sent (read, write, read payload, write payload, flush, activate, and so on), the device will return the status register. In your data, the device is responding with 0x0E, which is correct; decoded is is saying no errors and no data received or pending to transmit. If you want to see if the command you send was accepted, you need to first write the data and then read the data. For example, let's say we want to write the config register to enable the device as a receiver, 2 byte CRC with Rx interrupts enabled.
First, you would send 0b00100000 (0x20), 0b00111111 (0x3F). The device will respond with 0b00001110 (0x0e), 0b00000000 (0x00). This is what you are seeing. If you want to verify the configuration register, you need to then send 0b00000000 (0x00),which is the command to read the config register, then 0b00000000 (0x00), which is a dummy byte to clock out the data. The device will respond with 0x0e, which is the status, and then 0x3F assuming you configured as I did above.
Note that there are more commands than just reading and writing the registers, there are specific commands to fill and read the pipeline data.
Hope this helps.

STM32 - I2C - Write Sequential Data

I'm using AT24C512 EEPROM which is 512KB along with my STM32
I'm able to write 128bytes of data at once using
HAL_I2C_Mem_Write(&_EEPROM24XX_I2C,0xa0,Address,I2C_MEMADD_SIZE_16BIT,(uint8_t*)data,size_of_data,100)
but the issue is that i want to write more data after the data that was just wrote, but the EEPROM will replace the data as the Address is the same
so how can i skip the written address ?
This answer is not about using HAL with I2C, but hope it will point you
Just check datasheet (I looking into STM32F0) and you can see that the limit is 255 bytes (register CR2:NBYTES), I'm not sure if there is another limitation in HAL, but using direct access to registers you can sent 255 bytes at once or fragment it and sent how much you want.
For fragmenting there is bit CR2:RELOAD, if you set this, then at the end will be not transfer stopped, and you can update next NBYTES, .. when you will set last block of bytes (which will fit into NBYTES) then clear bit CR2:RELOAD.
This has one disadvantage, that every 255 bytes, you will be interrupted.
i think you should check the AT24C512 datasheet page 7.
If more
than 128 data words are transmitted to the EEPROM, the
data word address will
“
roll over
”
and previous data will be
overwritten. The address
“
roll over
”
during write is from the
last byte of the current page to the first byte of the same
page.

I2C: Raspberry Pi (Master) read Arduino (Slave)

I would like to read a block of data from my Arduino Mega (and also from an Arduino Micro in another project) with my Raspberry Pi via I2C. The code has to be in Perl because it's sort of a plug-in for my Home-Automation-Server.
I'm using the Device::SMBus interface and the connection works, I'm able to write and read single Bytes. I can even use writeBlockData with register address 0x00. I randomly discovererd that this address works.
But when I want to readBlockData, no register-address seems to work.
Does anyone know the correct register-address, or is that not even the problem that causes errors?
Thanks in advance
First off, which register(s) are you wanting to read? Here's an example using my RPi::I2C software (it should be exceptionally similar with the distribution you're using), along with a sketch that has a bunch of pseudo-registers configured for reading/writing.
First, the Perl code. It reads two bytes (the output of an analogRead() of pin A0 which is set up as register 80), then bit-shifts the two bytes into a 16-bit integer to get the full 0-1023 value of the pin:
use warnings;
use strict;
use RPi::I2C;
my $arduino_addr = 0x04;
my $arduino = RPi::I2C->new($arduino_addr);
my #bytes = $arduino->read_block(2, 80);
my $a0_value = ($bytes[0] << 8) | $bytes[1];
print "$a0_value\n";
Here's a full-blown Arduino sketch you can review that sets up a half dozen or so pseudo-registers, and when each register is specified, the Arduino writes or reads the appropriate data. If no register is specified, it operates on 0x00 register.
The I2C on the Arduino always does an onReceive() call before it does the onRequest() (when using Wire), so I set up a global variable reg to hold the register value, which I populate in the onReceive() interrupt, which is then used in the onRequest() call to send you the data at the pseudo-register you've specified.
The sketch itself doesn't really do anything useful, I just presented it as an example. It's actually part of my automated unit test platform for my RPi::WiringPi distribution.

STM32F072RB does not receive/send data over SPI in slave mode

I am using the
STM32F072RB
uC to receive and transmit data over SPI2 in slave mode with the following configuration:
CR1 = 0x0078
CR2 = 0x0700
AFRH = 0x55353500
MODER = 0xa2a0556a
The register APB1ENR is also properly configured.
The current program just checks the RXNE flag, reads the received data from DR and sends a random value writing to DR.
The status register when I receive data has the following value:
SR = 0x1403
The master sends data properly and I checked the signals at the slave pins (clock phase and polarity are identical on both sides and the NSS signal is cleared before sending SCK and data over MOSI).
I even configured the pins as inputs and I know I could read any digital signal the master could send.
With the current configuration it seems the slave receives something because the RXNE is set when the master sends data but the read value is always 0x00.
I have tried different configurations (software/hardware NSS, different data sizes, etc.) but I always get 0x00.
Moreover, the random value I send after reading DR is not sent to the outputs.
This is my current function, which is called continuously:
unsigned char spi_rx_slave(unsigned char spiPort, unsigned char *receiveBuffer)
{
uint8_t temp;
static unsigned long sr;
if (!spi_isOpen(spiPort))
{
sendDebug("%s() Error: spiPort not in use!\r\n",__func__);
return false;
}
if (spiDescriptor[spiPort]->powerdown == true)
{
sendDebug("%s() Error: spiPort in powerdown!\r\n",__func__);
return false;
}
/* wait till spi is not busy anymore */
while((spiDescriptor[spiPort]->spiBase->SR) & SPI_SR_BSY)
{
sendDebug("SPI is busy(1)\r\n");
vTaskDelay(2);
}
sendDebug("CR1 = 0x%04x, ", spiDescriptor[spiPort]->spiBase->CR1);
sendDebug("CR2 = 0x%04x, ", spiDescriptor[spiPort]->spiBase->CR2);
sendDebug("AFRH address = 0x%08x, AFRH value = %08x, ", (unsigned long*)(GPIOB_BASE+0x24), *(unsigned long*)(GPIOB_BASE+0x24));
sendDebug("MODER address = 0x%08x, MODER value = %08x\r\n", (unsigned long*)(GPIOB_BASE), *(unsigned long*)(GPIOB_BASE));
sr = spiDescriptor[spiPort]->spiBase->SR;
while(sr & SPI_SR_RXNE)
{
/* get RX byte */
temp = *(uint8_t *)&(spiDescriptor[spiPort]->spiBase->DR);
spiDescriptor[spiPort]->spiBase->DR = 0x53;
sendDebug("-------->DR address = 0x%08x, data received: 0x%02x\r\n", &spiDescriptor[spiPort]->spiBase->DR, temp);
sendDebug("SR = 0x%04x\r\n", sr);
vTaskDelay(1);
sr = spiDescriptor[spiPort]->spiBase->SR;
}
while((spiDescriptor[spiPort]->spiBase->SR) & SPI_SR_BSY)
{
sendDebug("SPI is busy(2)\r\n");
vTaskDelay(2);
}
return true;
}
What am I doing wrong?
Is there anything I did not configure properly?
Thanks in advance.
Regards,
Javier
Edit:
I switched to software NSS and copied the register values from a STM32CubeMX example I found online. I cannot use those libraries for this project but I would like to have the same behaviour.
The new values are:
CR1 = 0x0278
which means
fPCLK/256 (the proper one for the communication speed),
SPI enabled and
SSM = 1 (software NSS).
CR2 = 0x1700
which means
8-bit data and
RXNE event is generated if the FIFO level is greater than or equal to 1/4 (8-bit).
AFRH = 0x55303500
MODER = 0xa8a1556a
which means
MISO, MOSI and SCK alternate function 5 (SPI2)
NSS is not configured because now it is in software mode (slave is always selected).
I am still getting the same results and the eval kit with those libraries works fine using SPI1 instead.
Therefore there must be another issue that has nothing to do with the register values.
Might there be any clock issue e.g. the pins need to get some clock?
Thanks!
The question points to a couple of mistakes which may explain why no receive has been observed:
GPIO configuration points to some wrong Alternate Functions / Modes:
The question didn't state it precisely, but I assume that
AFRH = 0x55303500
MODER = 0xa8a1556a
refers to GPIOB (otherwise, it wouldn't make sense with SPI2).
This corresponds to the following pin configuration (see the
Reference Manual,
sec. 8.4.1, 8.4.10 and the
Datasheet,
Table 16):
PB15 - Alternate Function - AF5 = [INVALID]
PB14 - Alternate Function - AF5 = [I2C2_SDA]
PB13 - Alternate Function - AF3 = [TSC_G6_IO3]
PB12 - GP Input (reset state)
PB11 - Alternate Function - AF3 = [TIM_CH4]
PB10 - Alternate Function - AF5 = [SPI2_SCK / I2S2_CK]
PB09 - GP Input (reset state)
PB08 - GP Output
PB07 - Alternate Function - (unknown which, see register AFRL)
PB06 - GP Output
PB05 - Alternate Function - (unknown which, see register AFRL)
PB04 - GP Output
PB03 - GP Output
PB02 - Alternate Function - (unknown which, see register AFRL)
PB01 - Alternate Function - (unknown which, see register AFRL)
PB00 - Alternate Function - (unknown which, see register AFRL)
This is obviously not what the software is required to do.
Solution: Make sure to configure PB15=>AF0, PB14=>AF0, either PB13=>AF0 or PB10=>AF0, depending on your hardware.
In order to avoid mistakes in doing so, you should follow the hint of #P__J__ and use speaking macros for constants assigned to MODER, AFRH etc.
Using the HAL library provided by ST is a truly controversial subject among SO users, but one should really consider to use at least a header like stm32f072xb.h with macros like GPIO_AFRH_AFSEL15.
If one represents all configuration register values as (bitwise) ORs of such macros, it is easier to re-check configuration against datasheets, and the famous
rubber duck
will directly know what an unhappy developer is talking about.
Other clock activations might be missing:
The question confirms that
The register APB1ENR is also properly configured.
This is correct (as long as bit 14 is set).
Additionally, GPIOB must be powered, i. e., bit 18 of RCC_AHBENR must be set.
See again the
Reference Manual,
sec. 6.4.8 and 6.4.6.
GPIO pins may be in wrong mode during debugging:
I even configured the pins as inputs and I know I could read any digital signal the master could send. With the current configuration it seems the slave receives something because the RXNE is set when the master sends data but the read value is always 0x00.
Please note that for every GPIO pin, a unique mode is selected through the MODER register. If this is set to "Input" (0b00), the Alternate Function is disconnected and won't work with external signals.