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

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;
}

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!

MLX90621 no Acknowlegde with the RAM

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;
}

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 */
}

XMEGA-A3BU Xplained - Determine if pushbutton 1 is pressed by polling using DMA

The assignment requires us to toggle ON LEDs if SW1 is pressed by using polling. I believe I am setting the direction of each port and reading the register correctly. However nothing happens when I press SW1. There is no way to debug and breakpoint the code while the code is running to see whats in the registers.
[HWGuide] states: [HWGuide]:http://ww1.microchip.com/downloads/en/DeviceDoc/doc8394.pdf
//LED0 = PR0 (PORTR PIN 0)
//LED1 = PR1 (PORTR PIN 1)
//SW1 = PF1 (PORTF PIN 1)
[Datasheet] states: [Datasheet]:http://ww1.microchip.com/downloads/en/DeviceDoc/atmel-8362-8-and-16bit-avr-microcontroller-atxmega256a3bu_datasheet.pdf
//PORTR starts at address = 0x07E0
//PORTF starts at address = 0x06A0
[Manual] states: [Manual]: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8331-8-and-16-bit-AVR-Microcontroller-XMEGA-AU_Manual.pdf
//Data Input Value register on I/O = (Addr) + 0x08 = 0x06A8 (PORTF)
Code:
#define PORTR *((volatile unsigned char *)0x7E0) /* I/O Port Register */
#define PORTF *((volatile unsigned char *)0x6A0) /* I/O Port Register */
#define PORTF_IN *((volatile unsigned char *)0x6A8) //PORTF Input Value Reg
#define PORTR_OUTTGL *((volatile unsigned char *)0x7E7) //LED Toggle Reg
#define ReadReg(port) (port)
#define WriteReg(port, value) (port = value)
int main(void)
{
//set PORTR direction
WriteReg(PORTR, 0xFF);
//set PORTF direction
WriteReg(PORTF, 0x00);
while(1)
{
if((ReadReg(PORTF_IN) == 0xFD)) //if PF1 = 0
{
WriteReg(PORTR_OUTTGL, 0x3); //toggle LEDs
{
{
}
I expect the register to read either (0x02)0000 0010 or the inverse (0xFD)1111 1101 and LEDs to turn on or off if the button is pressed.
Used bit manipulation to isolate the bit I was trying to poll for. Had no idea what the other bits could have been set to.
int main(void)
{
//set PORTR direction
WriteReg(PORTR, 0xFF);
//set PORTF direction
WriteReg(PORTF, 0xF9);
while(1)
{
char statusPF1 = (ReadReg(PORTF_IN) & 0x02) >> 1;
char statusPF2 = (ReadReg(PORTF_IN) & 0x04) >> 2;
if((statusPF1 == 0)) //if PF1 = 0
{
WriteReg(PORTR_OUTTGL, 0x01); //toggle LED0
_delay_ms(1000);
}
if((statusPF2 == 0)) //if PF2 = 0
{
WriteReg(PORTR_OUTTGL, 0x02); //toggle LED1
_delay_ms(1000);
}
if ((statusPF1 != 0) && (statusPF2 != 0))
{
_blinkLEDs();
}
}
}

How to calculate CRC32 over blocks that are splitted and buffered of a large data?

Let's say I have a 1024kb data, which is 1kB buffered and transfered 1024 times from a transmitter to a receiver.
The last buffer contains a calculated CRC32 value as the last 4 bytes.
However, the receiver has to calculate the CRC32 buffer by buffer, because of the RAM constraints.
I wonder how to apply a linear distributed addition of CRC32 calculations to match the total CRC32 value.
I looked at CRC calculation and its distributive preference. The calculation and its linearity is not much clear to implement.
So, is there a mathematical expression for addition of calculated CRC32s over buffers to match with the CRC32 result which is calculated over total?
Such as:
int CRC32Total = 0;
int CRC32[1024];
for(int i = 0; i < 1024; i++){
CRC32Total = CRC32Total + CRC32[i];
}
Kind Regards
You did not provide any clues as to what implementation or even what language for which you "looked at CRC calculation". However every implementation I've seen is designed to compute CRCs piecemeal, exactly like you want.
For the crc32() routine provided in zlib, it is used thusly (in C):
crc = crc32(0, NULL, 0); // initialize CRC value
crc = crc32(crc, firstchunk, 1024); // update CRC value with first chunk
crc = crc32(crc, secondchunk, 1024); // update CRC with second chunk
...
crc = crc32(crc, lastchunk, 1024); // complete CRC with the last chunk
Then crc is the CRC of the concatenation of all of the chunks. You do not need a function to combine the CRCs of individual chunks.
If for some other reason you do want a function to combine CRCs, e.g. if you need to split the CRC calculation over multiple CPUs, then zlib provides the crc32_combine() function for that purpose.
When you start the transfer, reset the CrcChecksum to its initial value with the OnFirstBlock method. For every block received, call the OnBlockReceived to update the checksum. Note that the blocks must be processed in the correct order. When the final block has been processed, the final CRC is in the CrcChecksum variable.
// In crc32.c
uint32_t UpdateCrc(uint32_t crc, const void *data, size_t length)
const uint8_t *current = data;
while (length--)
crc = (crc >> 8) ^ Crc32Lookup[(crc & 0xFF) ^ *current++];
}
// In your block processing application
static uint32_t CrcChecksum;
void OnFirstBlock(void) {
CrcChecksum = 0;
}
void OnBlockReceived(const void *data, size_t length) {
CrcChecksum = UpdateCrc(CrcChecksum, data, length);
}
To complement my comment to your question, I have added code here that goes thru the whole process: data generation as a linear array, CRC32 added to the transmitted data, injection of errors, and reception in 'chunks' with computed CRC32 and detection of errors. You're probably only interested in the 'reception' part, but I think having a complete example makes it more clear for your comprehension.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
// ---------------------- buildCRC32table ------------------------------
static const uint32_t CRC32_POLY = 0xEDB88320;
static const uint32_t CRC32_XOR_MASK = 0xFFFFFFFF;
static uint32_t CRC32TABLE[256];
void buildCRC32table (void)
{
uint32_t crc32;
for (uint16_t byte = 0; byte < 256; byte++)
{
crc32 = byte;
// iterate thru all 8 bits
for (int i = 0; i < 8; i++)
{
uint8_t feedback = crc32 & 1;
crc32 = (crc32 >> 1);
if (feedback)
{
crc32 ^= CRC32_POLY;
}
}
CRC32TABLE[byte] = crc32;
}
}
// -------------------------- myCRC32 ----------------------------------
uint32_t myCRC32 (uint32_t previousCRC32, uint8_t *pData, int dataLen)
{
uint32_t newCRC32 = previousCRC32 ^ CRC32_XOR_MASK; // remove last XOR mask (or add first)
// add new data to CRC32
while (dataLen--)
{
uint32_t crc32Top24bits = newCRC32 >> 8;
uint8_t crc32Low8bits = newCRC32 & 0x000000FF;
uint8_t data = *pData++;
newCRC32 = crc32Top24bits ^ CRC32TABLE[crc32Low8bits ^ data];
}
newCRC32 ^= CRC32_XOR_MASK; // put XOR mask back
return newCRC32;
}
// ------------------------------ main ---------------------------------
int main()
{
// build CRC32 table
buildCRC32table();
uint32_t crc32;
// use a union so we can access the same data linearly (TX) or by chunks (RX)
union
{
uint8_t array[1024*1024];
uint8_t chunk[1024][1024];
} data;
// use time to seed randomizer so we have different data every run
srand((unsigned int)time(NULL));
/////////////////////////////////////////////////////////////////////////// Build data to be transmitted
////////////////////////////////////////////////////////////////////////////////////////////////////////
// populate array with random data sparing space for the CRC32 at the end
for (int i = 0; i < (sizeof(data.array) - sizeof(uint32_t)); i++)
{
data.array[i] = (uint8_t) (rand() & 0xFF);
}
// now compute array's CRC32
crc32 = myCRC32(0, data.array, sizeof(data.array) - sizeof(uint32_t));
printf ("array CRC32 = 0x%08X\n", crc32);
// to store the CRC32 into the array, we want to remove the XOR mask so we can compute the CRC32
// of all received data (including the CRC32 itself) and expect the same result all the time,
// regardless of the data, when no errors are present
crc32 ^= CRC32_XOR_MASK;
// load CRC32 at the very end of the array
data.array[sizeof(data.array) - 1] = (uint8_t)((crc32 >> 24) & 0xFF);
data.array[sizeof(data.array) - 2] = (uint8_t)((crc32 >> 16) & 0xFF);
data.array[sizeof(data.array) - 3] = (uint8_t)((crc32 >> 8) & 0xFF);
data.array[sizeof(data.array) - 4] = (uint8_t)((crc32 >> 0) & 0xFF);
/////////////////////////////////////////////// At this point, data is transmitted and errors may happen
////////////////////////////////////////////////////////////////////////////////////////////////////////
// to make things interesting, let's add one bit error with 1/8 probability
if ((rand() % 8) == 0)
{
uint32_t index = rand() % sizeof(data.array);
uint8_t errorBit = 1 << (rand() & 0x7);
// add error
data.array[index] ^= errorBit;
printf("Error injected on byte %u, bit mask = 0x%02X\n", index, errorBit);
}
else
{
printf("No error injected\n");
}
/////////////////////////////////////////////////////// Once received, the data is processed in 'chunks'
////////////////////////////////////////////////////////////////////////////////////////////////////////
// now we access the data and compute its CRC32 one chunk at a time
crc32 = 0; // initialize CRC32
for (int i = 0; i < 1024; i++)
{
crc32 = myCRC32(crc32, data.chunk[i], sizeof data.chunk[i]);
}
printf ("Final CRC32 = 0x%08X\n", crc32);
// because the CRC32 algorithm applies an XOR mask at the end, when we have no errors, the computed
// CRC32 will be the mask itself
if (crc32 == CRC32_XOR_MASK)
{
printf ("No errors detected!\n");
}
else
{
printf ("Errors detected!\n");
}
}