OS: Linux
I'm writing a spidev application in userspace to read EEPROM id. I have my device tree entry as following:
spi0: spi#ffda4000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xffda4000 0x100>;
interrupt-parent = <&intc>;
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
num-cs = <2>;
cs-gpios = <&porta 7 GPIO_ACTIVE_HIGH>, <&porta 0 GPIO_ACTIVE_HIGH>;
bus-num = <0>;
tx-dma-channel = <&pdma 16>;
rx-dma-channel = <&pdma 17>;
clocks = <&spi_m_clk>;
status = "disabled";
};
and then:
&spi0 {
status = "okay";
m25p10_spi#0 {
compatible = "m25p10";
reg = <0>; /* chip select */
spi-max-frequency = <20000000>;
/* m25p,fast-read; */
enable-dma = <0>;
};
spidev#0 {
compatible = "rohm,dh2228fv";
reg = <0>; /* chip select */
spi-max-frequency = <20000000>;
enable-dma = <0>;
};
};
Idea is to have spidev at same node as m25p10 so that when user space application open handle to "/dev/spidev0.0", it is actually talking to m25p10. But I can't get linux boot up. Is there anything wrong with this approach?
This will not work. One device - one definition in DT.
Also, why do you need to have spidev device? You already have m25p10_spi, which should show up as MTD device (something like /dev/mtd0), and there should be no problems accessing it from user space.
UPDATE:
It looks like OP wants to keep MTD and read device unique ID via RDID command, which is not supported by current m25p10 driver.
I might be wrong, but for me the easiest solution would be to extend the driver to create sysfs entry with RDID data, that is read during probing.
Some valuable resources:
LDD3
Linux kernel documentation
Related
I am a newbie to the embedded linux and device-tree world. I am trying to modify the device tree of ethernet phy from TI. I am interested to know what values the following variables <DP83867_RGMIIDCTL_2_25_NS>, <DP83867_RGMIIDCTL_2_75_NS> and <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB> correspond to. It appears to be delay values, but I searched through the datasheet (https://www.ti.com/lit/ds/symlink/dp83867ir.pdf?HQS=dis-mous-null-mousermode-dsf-pf-null-wwe&DCM=yes&ref_url=https%3A%2F%2Fwww.mouser.co.uk%2F&distId=26) and couldn't find any reference to such variable.
Can someone with some experience in device-tree explain where these variable are coming from and how to change/configure such register values.
&gem3 { /* required by spec */
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gem3_default>;
phy-handle = <&phy0>;
phy-mode = "rgmii-id";
mdio: mdio {
#address-cells = <1>;
#size-cells = <0>;
reset-gpios = <&gpio 38 GPIO_ACTIVE_LOW>;
reset-delay-us = <2>;
phy0: ethernet-phy#1 {
#phy-cells = <1>;
reg = <1>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>;
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
ti,dp83867-rxctrl-strap-quirk;
};
};
};
What does the variable and value of DP83867_RGMIIDCTL_2_25_NS in device tree correspond to?
From https://elixir.bootlin.com/linux/latest/A/ident/DP83867_RGMIIDCTL_2_25_NS it corresponds to a macro with the value 0x8.
#define DP83867_RGMIIDCTL_2_25_NS 0x8
I'm working on imx8mm and testing GPIO with Linux kernel v4.14.98.
Device tree node is:
&iomuxc {
pinctrl-names = "default";
...
imx8mm-evk {
pinctrl_gpio_plural: gpiopluralgrp {
fsl,pins = <
MX8MM_IOMUXC_GPIO1_IO11_GPIO1_IO11 0x41
>;
};
};
};
...
plural {
compatible = "gpio-plural";
/* pinctrl-names = "default"; */
pinctrl-0 = <&pinctrl_gpio_plural>;
reset-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
};
and I wrote a driver to testing this
static int gpio_plural_probe(struct platform_device *pdev)
{
struct gpio_plural_data *drvdata;
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (drvdata == NULL)
return -ENOMEM;
drvdata->reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(drvdata->reset)) {
printk("Error: reset not found\n");
return -EINVAL;
}
gpiod_set_value(drvdata->reset, 0);
mdelay(100);
gpiod_set_value(drvdata->reset, 1);
mdelay(100);
gpiod_set_value(drvdata->reset, 0);
mdelay(100);
gpiod_set_value(drvdata->reset, 1);
return 0;
}
However, I can't control GPIO pin when I comment pinctrl-names as device tree shown above. The GPIO pin always remains high.
In devicetree.c, the statename would be replaced to propname suffix, which in here is "0". But it just a constant name which could be any string. So my question is why I can't control GPIO pin without setting pinctrl-names?
It can't be any name, most of the node will have pinctrl-names = "default"; because this make pinctrl-0 the default state for the pins of the device.
This is actually quite important because the device core will use that to retrieve and set the proper state before probing the device, see pinctrl_bind_pins. It does:
dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_DEFAULT);
where PINCTRL_STATE_DEFAULT is "default".
Then, it selects the state with:
ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
If you don't want to use the default name, then, you'll have to select the proper state in your driver.
Other generic state names are:
#define PINCTRL_STATE_DEFAULT "default"
#define PINCTRL_STATE_INIT "init"
#define PINCTRL_STATE_IDLE "idle"
#define PINCTRL_STATE_SLEEP "sleep"
I'm very new to both C code, and the STM platform; Im using it for a school project.
I have two card communication via USART (Specifically USART3). The Sensor card (Slave)'s job is to only send their current distance measurement. I have managed to set this up.
Via Scope, using RS232/UART communication mode, I can see the hexe's being sent is "STX M 2 3 ETX"
Where the M is code for what kind of package it is, and the 2 and 3 is the hex 0x23 = 35 (cm). It sends a new measurement every 15ms.
Now to my problem. I cant seem to configure the Master's USART3 to recieve these packages.
This is my current code:
void USARTInit(void)
{
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
GPIO_InitTypeDef GPIO_InitStructure_UART,GPIO_InitStructure_UART_PD9;
//RCC_APB1Periph_AFIO;
//UART3 for communication with other STM (Master -> Slave / Master <- Slave)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
USART_ClockStructInit(&USART_ClockInitStructure);
USART_ClockInit(USART3, &USART_ClockInitStructure);
USART_InitStructure.USART_BaudRate = 9600; //115200; //19200;//57600;//19200; //9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //Word lenght, 8b = 8bit = 1byte
USART_InitStructure.USART_StopBits = USART_StopBits_1; //Num stoppbits
USART_InitStructure.USART_Parity = USART_Parity_No ; //USART_Parity_Odd;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //Full duplex mode
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART3, &USART_InitStructure);
//GPIO pins configuration
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE); //UART3 + TIM4
GPIO_InitStructure_UART.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure_UART.GPIO_Mode = GPIO_Mode_AF; //Alternative func, here UART
GPIO_InitStructure_UART.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_InitStructure_UART.GPIO_OType = GPIO_OType_PP; //PushPull
GPIO_Init(GPIOD, &GPIO_InitStructure_UART); //Tx - Transmit
GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_7); //GPIO_AF_7 -> U(S)ART mode
GPIO_InitStructure_UART.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure_UART.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure_UART.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStructure_UART); //Rx - Recieve
GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_7);
USART_Cmd(USART3, ENABLE);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitTypeDef nvicStructure; //Create a "extern" interupt base
nvicStructure.NVIC_IRQChannel = USART3_IRQn; //Link it to the global interupt of usart3
nvicStructure.NVIC_IRQChannelPreemptionPriority = 0; //Unsure
nvicStructure.NVIC_IRQChannelSubPriority = 0; //The priority of this interupt if you have other external interupts
nvicStructure.NVIC_IRQChannelCmd = ENABLE; //enables it
NVIC_Init(&nvicStructure); //Sends it to the Interupt handler
}
And my Handler code is :
void USART3_IRQHandler(void)
{
volatile uint16_t temp;
if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
temp = USART_ReceiveData(USART3) & 0xff; //0xFF ??? From datasheet
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
}
**CODE TO COUNT BINARY USING 7 DIODEs**
}
The problem seems to be the USART_ReceiveData(USART3), if I remove is I see that all the diodes are on constantly meaning something must must be going through this code over and over very quickly , but if I leave like it is, the first light turns on (ie first iteration) then nothing happens. Using my computer and adding a breakporints in the handler shows the temp variable always being empty. It only runs once then nothing. I suspect that a flag isnt being propely handled so Ive tried... some solutions.
//USART_ClearITPendingBit(USART3,USART_IT_ORE);
//USART_ClearITPendingBit(USART3, USART_IT_LBD);
//USART_ClearITPendingBit(USART3, USART_IT_CTS);
//USART_ClearITPendingBit(USART3, USART_IT_TC);
I had this code earlier but it made no difference.
Ive been trying now for 2 days to figure out whats wrong, but Im no closer than I was at the start.
Ive tried googling it and have countless of different answers, but I cant ssem to find any that fixes my issue. Im sorry if the solution super obvious...
I want to define a SPI device with usermode access, as explained for example in http://linux-sunxi.org/SPIdev
Following these examples, I added in the devicetree this :
&ecspi1 {
.... other stuff ...
mydev#0 {
compatible = "spidev";
spi-max-frequency = <5000000>;
reg = <2>; /*chipselect*/
};
};
The platform is i.MX6. ecspi1 seems to be their SPI controller.
Then I indeed get /dev/spi0.2 and /sys/class/spidev/spidev0.2
But in kernel trace there's a WARNING saying this:
spidev spi0.2: buggy DT: spidev listed directly in DT
So how else the spidev should be described? What is the right syntax?
spidev: why it shouldn't be directly in devicetree?
The Device Tree should describe the board's hardware, but
spidev does not describe/identify any hardware.
Mark Brown wrote:
Since spidev is a detail of how Linux controls a device rather than a
description of the hardware in the system we should never have a node
described as "spidev" in DT, any SPI device could be a spidev so this
is just not a useful description.
The rationale and workaround for this kernel patch is https://patchwork.kernel.org/patch/6113191/
So how else the spidev should be described? What is the right syntax?
Instead of explicit use of spidev in your Device Tree source, you instead need to identify the actual device that you're controlling, e.g.
mydev#0 {
- compatible = "spidev";
+ compatible = "my_spi_device";
spi-max-frequency = <5000000>;
Then (as Geert Uytterhoeven explains), modify drivers/spi/spidev.c in the kernel source code by adding the compatible value for your device to the spidev_dt_ids[] array
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "rohm,dh2228fv" },
{ .compatible = "lineartechnology,ltc2488" },
{ .compatible = "ge,achc" },
{ .compatible = "semtech,sx1301" },
+ { .compatible = "my_spi_device" },
{},
}
An alternate solution, which involves a quick-n-dirty change to just the Device Tree, is suggested by this article.
Simply replace the "spidev" compatible string with a proper string that already does exist:
mydev#0 {
- compatible = "spidev";
+ compatible = "rohm,dh2228fv"; /* actually spidev for my_spi_dev */
spi-max-frequency = <5000000>;
Since "rohm,dh2228fv" is already in the spidev_dt_ids[] list, no edit to drivers/spi/spidev.c is needed.
To avoid this issue just use linux,spidev instead of spidev:
&spi0 {
mydev#0 {
compatible = "linux,spidev";
};
};
I am communicating 2 uC (an arduino display as MASTER and STM32F429 as slave).Its communication consists of 10 bytes in full duplex through SPI using DMA, every 150ms.
During some minutes the communication goes very good, both uC are sending their 10 bytes properly. During this time, I have noted that "HAL_SPI_ErrorCallback" function is called becasue I have added a counter within and it is increased little by little, but the comminication still goes well.
My first question is: Is it normal that sometimes ErrorCallback function is called randomly? due to noise or whatever the communication has an instantaneous error... I guess..
Here are a capture of the MISO signal in green, CLK in whie and CS in yellow
On the other hand, after a while (randomly 10 min, 1h ...) the communication is corrupted just in the MISO signal , the STM32 sends the 10 bytes frame but instead of sending Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9 Byte10, (LSB first)
it sends:
Byte10 Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9, IT IS MOVED TO RIGTH 1 byte!?!?
Attached you can see the capture "Working.jpg" with byte0 = 0x02 and the rest of the bytes = 0. In the other capture "NOT_working.jpg" is a capture with the problem. Both uC were working properly for a while and suddenly the STM32 uC started to send this frame all the time (the communication frame is byte = 0x02 and the rest of the bytes = 0 in order to see easily this error).
Working.jpg - which is MISO signal sending the frame properly
NOT_working.jpg - which is MISO signal sending the frame incorrectly
I have tried the communication in:
"Init.Mode = DMA_NORMAL" and "DMA_CIRCULAR", and both configuration have the same behaviour.
I have creaged the 2 variables in order to find out the problem:
DMA_counter_RX = __HAL_DMA_GET_COUNTER(&hdma_spi6_rx);
DMA_counter_TX = __HAL_DMA_GET_COUNTER(&hdma_spi6_tx);
And the the comunications goes well, DMA_counter_RX = 10 BUT DMA_counter_TX = 9. This values are normal. But as soon as the shift error occurs, both DMA counters are = 10.
Also this problem always happens in debug mode when I click on "suspend" (pause) and "resume"(play) as soon as I click on "resume" and the processor continues with the program, the MISO signal is shifted forever.
Additionally I am using TIM1, TIM5, TIM2, TIM3 and TIM4 for other things like PWM and interruptions but not related to SPI...
I have tried to solve this problem modifying all the NVIC priorities for all interruptions and so on but the problem get worst.
I am using System Workbench for STM32 latest version.
Any help is appreciate! Thanks in advance and best regards.
Alejandro
Sorry for long question... :(
Bellow you can see my configuration for SPI and DMA if it can help you:
void MX_DMA_Init(void)
{
__HAL_RCC_DMA2_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
}
void MX_SPI6_Init(void)
{
hspi6.Instance = SPI6;
hspi6.Init.Mode = SPI_MODE_SLAVE;
hspi6.Init.Direction = SPI_DIRECTION_2LINES;
hspi6.Init.DataSize = SPI_DATASIZE_8BIT;
hspi6.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi6.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi6.Init.NSS = SPI_NSS_HARD_INPUT;
hspi6.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi6.Init.TIMode = SPI_TIMODE_DISABLE;
hspi6.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi6.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi6) != HAL_OK)
{
Error_Handler();
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hspi->Instance==SPI6)
{
__HAL_RCC_SPI6_CLK_ENABLE();
/**SPI6 GPIO Configuration
PG8 ------> SPI6_NSS
PG12 ------> SPI6_MISO
PG13 ------> SPI6_SCK
PG14 ------> SPI6_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI6;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
hdma_spi6_rx.Instance = DMA2_Stream6;
hdma_spi6_rx.Init.Channel = DMA_CHANNEL_1;
hdma_spi6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi6_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi6_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi6_rx.Init.Mode = DMA_NORMAL;
hdma_spi6_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_spi6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi6_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmarx,hdma_spi6_rx);
hdma_spi6_tx.Instance = DMA2_Stream5;
hdma_spi6_tx.Init.Channel = DMA_CHANNEL_1;
hdma_spi6_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi6_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi6_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi6_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi6_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi6_tx.Init.Mode = DMA_NORMAL;
hdma_spi6_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_spi6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi6_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmatx,hdma_spi6_tx);
/* Peripheral interrupt init */
HAL_NVIC_SetPriority(SPI6_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(SPI6_IRQn);
}
}
During initialization code, I configure SPI6 and DMA as it is described before, just after that I enable communication using:
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);
Also it were added the following 2 functions related to SPI communication:
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);
}
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data,10);
}
}
STM cube mx automatically created:
void DMA2_Stream5_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream5_IRQn 0 */
/* USER CODE END DMA2_Stream5_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi6_tx);
/* USER CODE BEGIN DMA2_Stream5_IRQn 1 */
/* USER CODE END DMA2_Stream5_IRQn 1 */
}
/**
* #brief This function handles DMA2 stream6 global interrupt.
*/
void DMA2_Stream6_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream6_IRQn 0 */
/* USER CODE END DMA2_Stream6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi6_rx);
/* USER CODE BEGIN DMA2_Stream6_IRQn 1 */
/* USER CODE END DMA2_Stream6_IRQn 1 */
}
void SPI6_IRQHandler(void)
{
/* USER CODE BEGIN SPI6_IRQn 0 */
/* USER CODE END SPI6_IRQn 0 */
HAL_SPI_IRQHandler(&hspi6);
/* USER CODE BEGIN SPI6_IRQn 1 */
/* USER CODE END SPI6_IRQn 1 */
}
------------------------------EDITED----------------------------
I add 2 captures of the SPI register
SPI registers WORKING
SPI registers ERROR
I finally got the solution, I found what the problem was!
Usually, the CS signal goes from 1 to 0, then MISO and MOSI communicates, and once the communication finishes CS signal goes from 0 to 1, and the STM32F429 continues with the rest of the tasks...
This was happening every 150 ms, that's the period of thime both uC are communicating. But the STM32 uC has another tasks with more priority than SPI communication.
When one of this higher priority starts during SPI communication, and once this higher priority is done then the uC continues with the task was doing ( it was SPI), obviouslythis frame is lost and "HAL_SPI_ErrorCallback" is executed, and then SPI is restarted.If SPI is restarted when CS signal is 1, (spi idle), then there is no problem, SPI is restarted properly and the next frame will be received without problem. BUT if SPI is restarted when CS signal is 0 (STM32 SPI is selected and ready to communicate) then the STM32 is waiting to send and receive an amount of bytes but it will receives less, so an a mismatch of communication bytes is the key of the PROBLEM.
I have solved this issue just adding:
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
while(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_8) != GPIO_PIN_SET) // CS signal
{
}
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data,10);
}
}
I have to modify "WHILE" in order to not stop the processor , but it is the first approximation.
Now the communication is working all the time, but some times a frame is lost (and " HAL_SPI_ErrorCallback" is called) due to higher priority task. But it is normal, a CRC is implemented to note that.
Thanks for helping me and support the support.
I hope this helps to other people.
Best regards.
Alejandro.