STMF0 CRC Issue - c

I am using the STM32F0 using register level coding and am having problems with the CRC module.
Basically I cant get the results to agree with online calculators.
I've stripped it right back to as simple as possible.
If I just reset the CRC then read the Data Register out I get 0xFFFFFFFF which I would expect as that's the initial value.
Even if I write zero in though and get the result it does not agree with other tools.
The STM outputs 0xC704DD7B and the online tools give 0xF4DBDF21.
As far as I can see all the parameters are the same (I have not tried to hand calculate it!).
My bare bones code is (and I am reading the result in the debugger from the register)...
// Reset the CRC.
SET_BIT(CRC->CR, CRC_CR_RESET_Pos);
// Write 0.
CRC->DR, 0;

I am not really sure, but maybe this helps:
I once had the same problem and i tried to figure out how to get the "correct" CRC32. Unfortunately there is not "one" type how CRC32 could be calculated, but several of ways. See https://crccalc.com/
I allways leave the settings of the CRC peripheral on default:
Default Polynomial state -> Enable
Default Init Value State -> Enable
Enable Input Data Inversion Mode -> None
None Output Data Inversion Mode -> Disable
Except "Input Data Format", which I set to "Words".
When sending data to the peripheral, I revert the words "word-wise". The Result is reverted word-wise again. This leads to an CRC32 which can be verified as CRC32/MGPE2
I have a function, that tests, if If I have configured the CRC Peripheral correctly, so I get "the correct" CRC32/MPEG2:
uint8_t CRC32Test(void) {
// #brief test if CRC32 Module is configured correctly
// #params none, void
// #return u8 status: 1 = OK, 0 = NOK (not configured correctly)
// Test if CRC Module is configured correctly.
// If YES, these data must return the CRC32 0x07 D4 12 72 (Big Endian)
// or - 0x72 12 d4 07 (little Endian)
uint8_t retval = 0;
uint8_t testdata[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x00, 0x00};
uint32_t CRCdataU32[3] = {0,};
uint32_t* pCRCdata = (uint32_t*)testdata;
uint32_t dataSz = 3;
CRCdataU32[0] = __REV(*pCRCdata++);
CRCdataU32[1] = __REV(*pCRCdata++);
CRCdataU32[2] = __REV(*pCRCdata++);
uint32_t testCRC32 = HAL_CRC_Calculate(&hcrc, CRCdataU32, dataSz);
testCRC32 = __REV(testCRC32);
if(testCRC32 == 0x7212d407) retval = 1;
return(retval);
}
I verified this, using crccalc.com
This is most probably not the most elegant code, but it works for me. I use it for data transfer between the MCU and a PC over RS232/RS485. I don't care much which special CRC32 I use. I just need both to create the same results on the receiver and the sender. And I archieve that with that code.

Related

CRC 8 value on STM doesnt match online calculators

So I've been trying to learn CRC and tried to implement the same on my STM32G070 nucleo board. After setting up all the required configuration I'm returned an unexpected value. The website I used to verify my values http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
My initial configuration was
Poly:0x31
Init:0xff
XOR: 00
no reflect on input and output
My configuration on the stm board are as per below
uint32_t crcCheck(uint32_t data)
{
RCC->AHB1ENR |= (RCC_AHB1ENR_CRCEN);
//RESET
CRC->CR |= (CRC_CR_RESET);
//8 BIT POLYNOMIAL
CRC->CR |= (CRC_CR_POLYSIZE_1);
CRC->POL = (0x31);
CRC->INIT = (0xFF);
CRC->DR = data;
return CRC->DR;
}
for trial I provided 0x32 as input and got 0x0B from online calculator and 0x70 from my program which does not matches. However I noted something strange that when I keep the inital poly as 0X00, both of them gave me 0xA7 as an output. I've tried for a while but could not arrive on a conclusion for this behavior.

Why does sending CMD58 over SPI to my Class 10 SD return 0x01 instead of 0x00?

I am trying to initialize an SD card using an SPI bus and STM32F4 Discovery Board. I am mainly relying on Elm Chan's implementation of the disk_initialize function in the example code to base my own implementation. Unfortunately, I have run into an issue where sending CMD58 to the SD card during the initialization process return a result of 0x01, which implies that the SD card is idle. However, I am still seeing the next four bytes from the SD card as 0x00, 0xFF, 0x80, 0x00 which is in the right format for an R3 response. However, I am not sure if I can trust these four bytes as my OCR.
As of now, I have tried ignoring that the SD card is idling and simply tried to use the next four bytes as the OCR but the code seems to fail at other points during the mounting process with respect to the type of the card being assumed from the OCR.
if (Timer1 && SD_SendCmd(CMD58, 0) == 0) {
for (n = 0; n < 4; n++) {
ocr[n] = SPI_RxByte();
}
type = (ocr[0] & 0x40) ? 6 : 2;
}
The code segment above is where I am first seeing the idle response. SD_SendCmd is where I send CMD58 to the SD card and where I am receiving 0x01 as the leftmost byte of the five byte response. Because I am not receiving 0x00, which signals that the SD card has no issues with the command passed to it, the code breaks out of the initialization process and returns an error. I would greatly appreciate any help with this matter as I have been stumped by this 0x01 return value for quite some time now. Thank you!
So I was able to figure out the issue. It turns out that the card I was using was an SDHC card, where HC stands for high capacity. According to the simplified SD card specification, the CRC, which is sent at the end of the transmission of a command has to have the least significant bit set to 1. So, ORing the CRC with 0x01 before any of the transmissions let me initialize and use any type of SD card. So the issue I was having was not from CMD58, but how I was dealing with the CRC in general. Interestingly enough, not ORing the CRC seems to work fine with non high-capacity SD cards. But ORing the CRC with 0x01 seems to work with all cards (at least as far as I have tested).
With regard to ORing the CRC with 0x01, this is not the CRC, but the STOP-BIT, the CRC is of type CRC7 and is at bits 1:7 of byte #6 in the command. According to the specification, even if the CRC is not required, the stop bit must always be 1.

ESP32 connecting to a separate IC using SPI

I am taking a shot at writing a wrapper for the S1V30120 dectalk text synthesis IC in C language using the ESP IDF. I am running into a problem in the following code.
printf("Hello world!\n");
esp_err_t ret;
spi_device_handle_t spi;
spi_bus_config_t buscfg={
.miso_io_num=PIN_NUM_MISO,
.mosi_io_num=PIN_NUM_MOSI,
.sclk_io_num=PIN_NUM_CLK,
.quadhd_io_num=-1,
.quadwp_io_num=-1
};
spi_device_interface_config_t devcfg={
.clock_speed_hz=750000,
.mode=0,
.spics_io_num=PIN_NUM_CS,
.queue_size=7
};
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
assert(ret==ESP_OK);
ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
uint8_t rec[20];
assert(ret==ESP_OK);
uint8_t cmd[] = {0xAA, 0x04, 0x00, 0x05, 0x00}; // get information command
printf("waiting for rdy");
while (gpio_get_level(PIN_NUM_RDY) == 0){};
//create 2 transactions 1 for transmitting the GET INFORMATION command
//and 1 for getting the data back from the ic
spi_transaction_t t;
spi_transaction_t r;
memset(&t, 0, sizeof(t));
t.length=5*8;
t.tx_buffer=&cmd;
r.length=20*8;
r.rx_buffer=&rec;
ret = spi_device_transmit(spi, &t);
assert( ret == ESP_OK);
ret = spi_device_transmit(spi, &r);
assert(ret == ESP_OK);
printf((char*)r.rx_data);
/* Print chip information */
printf("Restarting now.\n");
I'm pretty sure connection should be in full duplex mode and I believe that is set up correctly. the information coming back should be 20 bytes but I am getting the error
rxdata transfer > 32 bits without configured DMA
at the moment I am following 2 pieces of code that may help.
an example of using SPI in the esp idf:
https://github.com/espressif/esp-idf/blob/3276a1316f66a923ee2e75b9bd5c7f1006d160f5/examples/peripherals/spi_master/main/spi_master_example_main.c
an example of using the dectalk ic in Arduino ide:
https://electronza.com/arduino-due-s1v30120-text-speech-code/2/
the dectalk ic protocol sheet:
https://github.com/MikroElektronika/Click_TextToSpeech_S1V30120/blob/master/datasheet/S1V30120%20Protocol%20Specification.pdf
and the SPI documentation for the esp idf:
https://gitdemo.readthedocs.io/en/latest/api/peripherals/spi_master.html
the protocol sheet also says something about sending 16 bytes of 0x00 after a transaction I've never seen that before though.
I hope I was thorough enough with all this information and I thank anyone in advance who can help!
You have used "1" for DMA in the line
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
But as mentioned in the docs, the DMA needs to be configured.
For external PSRAM available on these boards that means something like
pvPortMallocCaps(20, MALLOC_CAP_DMA)
Without DMA only 32 bits data are possible per transaction.

What is IOSET and how works the simple buzzer (BUZZER_PIN)?

I have the c code for the micro-controller with buzzer. It works, but I wonder how it works.
In wh.h/.cpp I have the function:
void setBuzzer(tBool on)
{
if (TRUE == on)
IOCLR = BUZZER_PIN;
else
IOSET = BUZZER_PIN;
}
That can enable and disable the buzzer. I don't know what it really makes and what BUZZER_PIN, IOCLR and IOSET are?
The BUZZER_PIN occurs only once more in the code, in:
void immediateIoInit(void)
{
tU8 initCommand[] = {0x12, 0x97, 0x80, 0x00, 0x40, 0x00, 0x14, 0x00, 0x00};
// 04 = LCD_RST# low
// 10 = BT_RST# low
//make all key signals as inputs
IODIR &= ~(KEYPIN_CENTER | KEYPIN_UP | KEYPIN_DOWN | KEYPIN_LEFT | KEYPIN_RIGHT);
IODIR |= BUZZER_PIN;
IOSET = BUZZER_PIN;
IODIR |= BACKLIGHT_PIN;
IOSET = BACKLIGHT_PIN;
It looks strange to me, because the IOSET value is changing just after setting it to BUZZER_PIN. So, what it can that way does?
One more question: can I do something more with buzzer? E.g. change to volume? Of course, the duration of sound can be adjusted with setBuzzer(1) than pause(time) and setBuzzer(0).
Somewhere you will find an include file that contains the #define for IOSET IOCLR etc.
Usually, they map to GPIO register addresses, eg:
#define FIO0DIR (*(volatile unsigned long *)0x3FFFC000)
IOSET is usually a writeable address that is hardware-capable of setting to 1 all bits written to it that are 1, while leaving the remainder of the GPIO bits in their previous state. This eliminates the need for a read/modify/write operation and so is much more interrupt/thread friendly. It normally has a similar 'IOCLR' partner that can clear the bits on the GPIO port that are set in its argument without affecting the state of others.
The port register itself is probabaly called' IOPIN', or something like that. Modifying one or subsets of bits directly using IOPIN requires a read/modify/write :(
It appears that the buzzer is connected to one GPIO pin, so you can only turn it on and off - no finer control is possible.

How does the following code make PC beeps?

void Sound(int f)
{
USHORT B=1193180/f;
UCHAR temp = In_8(0x61);
temp = temp | 3;
Out_8(0x61,temp);
Out_8(0x43,0xB6);
Out_8(0x42,B&0xF);
Out_8(0x42,(B>>8)&0xF);
}
In_8/Out_8 reads/writes 8 bit to/from a specified port(implementation details omitted).
How does it make PC beep?
UPDATE
Why &0xF is used here? Shouldn't it be 0xFF?
The PC has a 8255 timer chip, which is controlled using the ports 0x61, 0x43 and 0x42.
When port 0x61 bit 0 is set to 1, this means "turn on the timer that is connected to the speaker".
When port 0x61 bit 1 is set to 1, this means "turn on the speaker".
This is done in the first paragraph of your code.
The second part puts the "magic value" 0xB6 on port 0x43, which means that the following two bytes arriving at port 0x42 will be interpreted as the divisor for the timer frequency. The division's resulting frequency (1193180 / divisor) will then be sent to the speaker.
http://gd.tuwien.ac.at/languages/c/programming-bbrown/advcw3.htm#sound

Resources