MLX90621 no Acknowlegde with the RAM - embedded

First off all I am a beginner regarding embedded programming.
For an application I do want to use the MLX90621 thermo pixel array togehter with an STM32G431KB. On the Melexis Website is an example Code with some sort off abstraction. I moddified the lowlevel part of the code to work with the HAL library of the MCU.
For some reason I can read the EEPROM and write to it, get an acknowledge... But when trying to read from the adress 0x60, the RAM, where the sensorvalues are stored i do not get an acknowledge. I do have checkt with an logic analyer and I am sending the correct messages. Just for refference I do have added the code part of the read function.
Has anybody an idea regarding some very dump timing error or something like that.
P.S. Allready tried an different sensor of my order with the exact same result.
int MLX90621_I2CRead(uint8_t slaveAddr,uint8_t command, uint8_t startAddress, uint8_t addressStep, uint8_t nMemAddressRead, uint16_t *data)
{
uint8_t sa = slaveAddr << 1;
int cnt = 0;
int i = 0;
uint8_t cmd[4] = {0,0,0,0};
uint8_t i2cData[132] = {0};
uint16_t *p;
p = data;
cmd[0] = command;
cmd[1] = startAddress;
cmd[2] = addressStep;
cmd[3] = nMemAddressRead;
if (HAL_I2C_Master_Transmit(&hi2c2, sa, cmd, 4, HAL_MAX_DELAY) != HAL_OK)
return -1;
HAL_Delay(1);
//sa = sa | 0x01;
//ack = i2c.read(sa, i2cData, 2*nMemAddressRead, 0);
if (HAL_I2C_Master_Receive(&hi2c2, sa, i2cData, 2*nMemAddressRead, HAL_MAX_DELAY) != HAL_OK)
return -1;
for (cnt = 0; cnt < nMemAddressRead; cnt++) {
i = cnt << 1;
*p++ = (uint16_t)i2cData[i+1]*256 + (uint16_t)i2cData[i];
}
return 0;
}

Related

STM32 Crash on Flash Sector Erase

I'm trying to write 4 uint32's of data into the flash memory of my STM32F767ZI so I've looked at some examples and in the reference manual but still I cannot do it. My goal is to write 4 uint32's into the flash and read them back and compare with the original data, and light different leds depending on the success of the comparison.
My code is as follows:
void flash_write(uint32_t offset, uint32_t *data, uint32_t size) {
FLASH_EraseInitTypeDef EraseInitStruct = {0};
uint32_t SectorError = 0;
HAL_FLASH_Unlock();
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FLASH_SECTOR_11;
EraseInitStruct.NbSectors = 1;
//EraseInitStruct.Banks = FLASH_BANK_1; // or FLASH_BANK_2 or FLASH_BANK_BOTH
st = HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError);
if (st == HAL_OK) {
for (int i = 0; i < size; i += 4) {
st = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_USER_START_ADDR + offset + i, *(data + i)); //This is what's giving me trouble
if (st != HAL_OK) {
// handle the error
break;
}
}
}else {
// handle the error
}
HAL_FLASH_Lock();
}
void flash_read(uint32_t offset, uint32_t *data, uint32_t size) {
for (int i = 0; i < size; i += 4) {
*(data + i) = *(__IO uint32_t*)(FLASH_USER_START_ADDR + offset + i);
}
}
int main(void) {
uint32_t data[] = {'a', 'b', 'c', 'd'};
uint32_t read_data[] = {0, 0, 0, 0};
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
flash_write(0, data, sizeof(data));
flash_read(0, read_data, sizeof(read_data));
if (compareArrays(data,read_data,4))
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7,SET);
}
else
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14,SET);
}
return 0;
}
The problem is that before writing data I must erase a sector, and when I do it with the HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError), function, the program always crashes, and sometimes even corrupts my codespace forcing me to update firmware.
I've selected the sector farthest from the code space but still it crashes when i try to erase it.
I've read in the reference manual that
Any attempt to read the Flash memory while it is being written or erased, causes the bus to
stall. Read operations are processed correctly once the program operation has completed.
This means that code or data fetches cannot be performed while a write/erase operation is
ongoing.
which I believe means the code should ideally be run from RAM while we operate on the flash, but I've seen other people online not have this issue so I'm wondering if that's the only problem I have. With that in mind I wanted to confirm if this is my only issue, or if I'm doing something wrong?
In your loop, you are adding multiples of 4 to i, but then you are adding i to data. When you add to a pointer it is automatically multiplied by the size of the pointed type, so you are adding multiples of 16 bytes and reading past the end of your input buffer.
Also, make sure you initialize all members of EraseInitStruct. Uncomment that line and set the correct value!

I can't read keydatas (buttons' press values) with SPI between XMC4800 and STLED316

I use SPI communication between XMC4800 and STLED316 led controller. I can write datas to the display on STLED316.However, I can't read keydatas (by keyscan feature of STLED, it is written by STLED316 datasheet). I have some codes for write and read. I suppose command address or register address to send a byte to STLED is wrong. I couldn't figure out if they are the problem or something else. I simplified the codes. I used SPI_MASTER API for communication. write_7segg is working but can't use keydata's specific bits to use button press values (0,1). I need to use key press (keydata) values to change something on the display. If someone worked with STLED316 before, it maybe more understandable. Finally, STLED316 has a 5-digit display and 5 buttons with keyscan feature. read[0] = STLED316_DATA_RD = 0x40, read[1] = STLED316_READ_PAGE = 0x08, keydata[0] = STLED316_ADDR_KEY_DATA1 = 0x01. Here the codes are:
keydata = read_keyscan();
if ((((keydata) & 0x01) == 1) && (current_mode == 0)) {
write_7segg(4, arServo_Numbers[0]);
write_7segg(3, arServo_Numbers[0]);
write_7segg(2, arServo_Characters[23]);
write_7segg(1, arServo_Numbers[0]);
write_7segg(0, arServo_Characters[15]);
}
void write_7segg(unsigned char DisplayNumber, unsigned char Segments) {
// DIGITAL_IO_SetOutputLow(&DIGITAL_IO_0);
Buffer[0] = DisplayNumber;
Buffer[1] = Segments;
DIGITAL_IO_SetOutputLow(&DIGITAL_IO_8);
SPI_MASTER_Transmit(&SPI_MASTER_01,Buffer, 2);
DIGITAL_IO_SetOutputHigh(&DIGITAL_IO_8);
uint8_t readData(uint8_t address){
uint8_t sendByte = read[0]|read[1]|address;
uint8_t readByte = 0;
DIGITAL_IO_SetOutputLow(&DIGITAL_IO_8);
SPI_MASTER_Transfer(&SPI_MASTER_01,&sendByte, &readByte, 1);
DIGITAL_IO_SetOutputHigh(&DIGITAL_IO_8);
return readByte;
}
uint16_t read_keyscan(void){
uint16_t keyState = 0;
keyState = readData(keys[1]) << 8;
keyState = readData(keys[0]);
return keyState;
}

STM32F769NI USB CDC host problem sending simple data to the device

I am making HID for some data acquisition system. There are a lot of sensors who store test data and when I need I get to them and connect via USB and take it. USB host sent 3 bytes and USB device, if bytes are correct, sends its stored data. Sounds simple.
Previously it was implemented on PC, but now I try to implement it on STM32F769 Discovery and have some serious problems.
I am using ARM Keil 5.27, code generated with STM32CubeMX 5.3.0. I tried just to make a plain simple program, later to integrate with the entire touchscreen interface. I tried to implement this code in main:
if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
while (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
{
Transmission_function();
}
And the function itself:
#define DLE 0x10
#define STX 0x2
uint8_t tx_buf[]={DLE, STX, 120}, RX_FLAG;
uint32_t size_tx=sizeof(tx_buf);
void Transmission_function (void)
{
if (Appli_state == APPLICATION_READY)
{
i=0;
USBH_CDC_Transmit(&hUsbHostHS, tx_buf, size_tx);
HAL_Delay(50);
RX_FLAG=0;
}
}
It should send the message after I press the blue button on the Discovery board. All that I get is Hard Fault. While trying to debug, I tried manually to check after which action I get this error and it was functioning in stm32f7xx_ll_usb.c:
HAL_StatusTypeDef USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src,
uint8_t ch_ep_num, uint16_t len, uint8_t dma)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t *pSrc = (uint32_t *)src;
uint32_t count32b, i;
if (dma == 0U)
{
count32b = ((uint32_t)len + 3U) / 4U;
for (i = 0U; i < count32b; i++)
{
USBx_DFIFO((uint32_t)ch_ep_num) = *((__packed uint32_t *)pSrc);
pSrc++;
}
}
return HAL_OK;
}
But trying to scroll back in disassembly I notice, that just before Hard Fault program was in this function inside stm32f7xx_hal_hcd.c, in case GRXSTS_PKTSTS_IN:
static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd)
{
USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t pktsts;
uint32_t pktcnt;
uint32_t temp;
uint32_t tmpreg;
uint32_t ch_num;
temp = hhcd->Instance->GRXSTSP;
ch_num = temp & USB_OTG_GRXSTSP_EPNUM;
pktsts = (temp & USB_OTG_GRXSTSP_PKTSTS) >> 17;
pktcnt = (temp & USB_OTG_GRXSTSP_BCNT) >> 4;
switch (pktsts)
{
case GRXSTS_PKTSTS_IN:
/* Read the data into the host buffer. */
if ((pktcnt > 0U) && (hhcd->hc[ch_num].xfer_buff != (void *)0))
{
(void)USB_ReadPacket(hhcd->Instance, hhcd->hc[ch_num].xfer_buff, (uint16_t)pktcnt);
/*manage multiple Xfer */
hhcd->hc[ch_num].xfer_buff += pktcnt;
hhcd->hc[ch_num].xfer_count += pktcnt;
if ((USBx_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) > 0U)
{
/* re-activate the channel when more packets are expected */
tmpreg = USBx_HC(ch_num)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(ch_num)->HCCHAR = tmpreg;
hhcd->hc[ch_num].toggle_in ^= 1U;
}
}
break;
case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
break;
case GRXSTS_PKTSTS_IN_XFER_COMP:
case GRXSTS_PKTSTS_CH_HALTED:
default:
break;
}
}
Last few lines from Dissasembly shows this:
0x080018B4 E8BD81F0 POP {r4-r8,pc}
0x080018B8 0000 DCW 0x0000
0x080018BA 1FF8 DCW 0x1FF8
Why it fails? How could I fix it? I do not have much experience with USB protocol.
I will post my walkaround this, but I am not sure why it worked. Solution was to use EXTI0 interrupt instead of just detection if PA0 is high, as I showed I used here:
if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
while (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
Transmission_function();
I changed it to this:
void EXTI0_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_IRQn 0 */
if(Appli_state == APPLICATION_READY){
USBH_CDC_Transmit(&hUsbHostHS, Buffer, 3);
}
/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
/* USER CODE BEGIN EXTI0_IRQn 1 */
/* USER CODE END EXTI0_IRQn 1 */
}

PIC32MZ UART RX Interrupt

Porting from PIC32MX to MZ (PIC32MZ2048EFG100) and am banging head against wall trying to generate a simple RX interrupt on UART3. Please see code below.
void main(void} {
__builtin_disable_interrupts();
//Ensuring all pins config as digital
ANSELA = 0x0000;
ANSELB = 0x0000;
ANSELC = 0x0000;
ANSELD = 0x0000;
ANSELE = 0x0000;
ANSELF = 0x0000;
ANSELG = 0x0000;
//Convenient macrso to do IOUNLOCK
#define PPSUnLock() {SYSKEY=0x0;SYSKEY=0xAA996655;SYSKEY=0x556699AA;CFGCONbits.IOLOCK=0;}
#define PPSLock() {SYSKEY=0x0;SYSKEY=0xAA996655;SYSKEY=0x556699AA;CFGCONbits.IOLOCK=1;}
//Peripheral Pin Select (PPS) Settings for UART3
PPSUnLock();
U3RXRbits.U3RXR = 0b1010;
RPA14Rbits.RPA14R = 0b0001;
PPSLock();
//Config UART3
U3MODEbits.UEN0 = 0; //no flow control
U3MODEbits.UEN1 = 0;
U3MODEbits.LPBACK = 0; // no loopback
U3MODEbits.ABAUD = 0; //no autobaud
U3MODEbits.BRGH = 0;
U3MODEbits.PDSEL0 = 0; //8 data bits, no parity
U3MODEbits.PDSEL1 = 0;
U3MODEbits.STSEL = 0; // 1 stop bit
U3STAbits.URXISEL0 = 0; //RX Interrupt on first byte in FIFO
U3STAbits.URXISEL1 = 0;
U3BRG = CLOSEST_UBRG_VALUE115200; //Macro defined elsewhere, but it works
//Int priorities
IPC39bits.U3EIP = 6;
IPC39bits.U3EIS = 3;
//Int flags
IFS4bits.U3RXIF = 0;
//Int enable/disable
IEC4bits.U3EIE = 0;
IEC4bits.U3TXIE = 0;
IEC4bits.U3RXIE = 1; //Enable int on RX
//Enable multi-vector interrupts
INTCONSET = _INTCON_MVEC_MASK;
__builtin_enable_interrupts();
//Turn on UART3
U3STAbits.URXEN = 1;
U3STAbits.UTXEN = 1;
U3MODEbits.ON = 1;
UART_txEXTCOMandWait('A'); //Function defined elsewhere - I get successful byte "A" sent to my terminal. So TX works.
while(1){Nop();}; //wait in endless loop for interrupt to occur on keystroke
}
Below is my ISR:
void __ISR_AT_VECTOR (_UART3_RX_VECTOR, IPL6SOFT) U3Interrupt(void) {
unsigned int test=0;
Nop(); //Setting a breakpoint here
}
I successfully see an "A" on my terminal screen when running the program, so settings are correct for TX. Typing in text in my terminal screen yields no interrupts. Have verified with scope that signal is making it to the PIC32.
What am I missing here? I'm burning a ton of time on something that should be trivial.
Thanks guys.
Figured it out... It should be:
//Int priorities
IPC39bits.U3EIP = 6;
IPC39bits.U3EIS = 3;
Interesting how this had been working in production on PIC32MX for years.

What does PKCS5_PBKDF2_HMAC_SHA1 return value mean?

I'm attempting to use OpenSSL's PKCS5_PBKDF2_HMAC_SHA1 method. I gather that it returns 0 if it succeeds, and some other value otherwise. My question is, what does a non-zero return value mean? Memory error? Usage error? How should my program handle it (retry, quit?)?
Edit: A corollary question is, is there any way to figure this out besides reverse-engineering the method itself?
is there any way to figure this out besides reverse-engineering the method itself?
PKCS5_PBKDF2_HMAC_SHA1 looks like one of those undocumented functions because I can't find it in the OpenSSL docs. OpenSSL has a lot of them, so you should be prepared to study the sources if you are going to use the library.
I gather that it returns 0 if it succeeds, and some other value otherwise.
Actually, its reversed. Here's how I know...
$ grep -R PKCS5_PBKDF2_HMAC_SHA1 *
crypto/evp/evp.h:int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
crypto/evp/p5_crpt2.c:int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
...
So, you find the function's implementation in crypto/evp/p5_crpt2.c:
int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
const unsigned char *salt, int saltlen, int iter,
int keylen, unsigned char *out)
{
return PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter,
EVP_sha1(), keylen, out);
}
Following PKCS5_PBKDF2_HMAC:
$ grep -R PKCS5_PBKDF2_HMAC *
...
crypto/evp/evp.h:int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
crypto/evp/p5_crpt2.c:int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
...
And again, from crypto/evp/p5_crpt2.c:
int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
const unsigned char *salt, int saltlen, int iter,
const EVP_MD *digest,
int keylen, unsigned char *out)
{
unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
int cplen, j, k, tkeylen, mdlen;
unsigned long i = 1;
HMAC_CTX hctx_tpl, hctx;
mdlen = EVP_MD_size(digest);
if (mdlen < 0)
return 0;
HMAC_CTX_init(&hctx_tpl);
p = out;
tkeylen = keylen;
if(!pass)
passlen = 0;
else if(passlen == -1)
passlen = strlen(pass);
if (!HMAC_Init_ex(&hctx_tpl, pass, passlen, digest, NULL))
{
HMAC_CTX_cleanup(&hctx_tpl);
return 0;
}
while(tkeylen)
{
if(tkeylen > mdlen)
cplen = mdlen;
else
cplen = tkeylen;
/* We are unlikely to ever use more than 256 blocks (5120 bits!)
* but just in case...
*/
itmp[0] = (unsigned char)((i >> 24) & 0xff);
itmp[1] = (unsigned char)((i >> 16) & 0xff);
itmp[2] = (unsigned char)((i >> 8) & 0xff);
itmp[3] = (unsigned char)(i & 0xff);
if (!HMAC_CTX_copy(&hctx, &hctx_tpl))
{
HMAC_CTX_cleanup(&hctx_tpl);
return 0;
}
if (!HMAC_Update(&hctx, salt, saltlen)
|| !HMAC_Update(&hctx, itmp, 4)
|| !HMAC_Final(&hctx, digtmp, NULL))
{
HMAC_CTX_cleanup(&hctx_tpl);
HMAC_CTX_cleanup(&hctx);
return 0;
}
HMAC_CTX_cleanup(&hctx);
memcpy(p, digtmp, cplen);
for(j = 1; j < iter; j++)
{
if (!HMAC_CTX_copy(&hctx, &hctx_tpl))
{
HMAC_CTX_cleanup(&hctx_tpl);
return 0;
}
if (!HMAC_Update(&hctx, digtmp, mdlen)
|| !HMAC_Final(&hctx, digtmp, NULL))
{
HMAC_CTX_cleanup(&hctx_tpl);
HMAC_CTX_cleanup(&hctx);
return 0;
}
HMAC_CTX_cleanup(&hctx);
for(k = 0; k < cplen; k++)
p[k] ^= digtmp[k];
}
tkeylen-= cplen;
i++;
p+= cplen;
}
HMAC_CTX_cleanup(&hctx_tpl);
return 1;
}
So it looks like 0 on failure, and 1 on success. You should not see other values. And if you get a 0, then all the OUT parameters are junk.
Memory error? Usage error?
Well, sometimes you can call ERR_get_error. If you call it and it makes sense, then the error code is good. If the error code makes no sense, then its probably not good.
Sadly, that's the way I handle it because the library is not consistent with setting error codes. For example, here's the library code to load the RDRAND engine.
Notice the code clears the error code on failure if its a 3rd generation Ivy Bridge (that's the capability being tested), and does not clear or set an error otherwise!!!
void ENGINE_load_rdrand (void)
{
extern unsigned int OPENSSL_ia32cap_P[];
if (OPENSSL_ia32cap_P[1] & (1<<(62-32)))
{
ENGINE *toadd = ENGINE_rdrand();
if(!toadd) return;
ENGINE_add(toadd);
ENGINE_free(toadd);
ERR_clear_error();
}
}
How should my program handle it (retry, quit?)?
It looks like a hard failure.
Finally, that's exactly how I navigate the sources in this situation. If you don't like grep you can try ctags or another source code browser.