I'm implementing serial communication with a device in a firmware wrote from another person.
The MCU is STM32F411VET and I've data loss in communication.
To try to understand the problem, I wrote a little firmware that manage only usart2 and with it I haven't data loss, infact in this case, the usart2 works very fine at 115200 and don't loss a single byte.
Then, I've compared the code of this test software with code of software I'm working on and they are identical.
So I checked if there is another part of code that can conflict with USART2 and I have not found anything.
I searched instruction that disable interrupts, but there is one not used in my case.
The loop time is less then one milliseconds then I think that this not a problem.
What else could I check?
I finished ideas 😞
The init code of USART2 is:
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
GPIO_InitStruct.Pin = TX_Pin | RX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);{
HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Uart2_Ready = false;
}
The Rx callback is:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
RxBuffer[BufferIndex++] = c;
HAL_UART_Receive_IT(huart, (uint8_t *)&c, 1);
if (BufferIndex == BUFFER_LENGHT)
{
memcpy(&Rx_Packet, RxBuffer, BUFFER_LENGHT);
PacketReady = true;
BufferIndex = 0;
}
}
Many thanks for help.
Solved, I found a function with problems.
Related
I'm trying to use the DIO SPI mode on the ESP32 with the espidf (version 4.4).
But I encountered problems.
I have a ram device (ref 23LC1024) than can be accessed with several modes (single, dual, quad).
The single mode works perfectly (can write and read back)
The dual mode creates problems.
Here is how I configure the SPI bus (same setup for single or dual mode)
memset(&config, 0, sizeof(spi_bus_config_t));
config.mosi_io_num = MOSI_PIN;
config.miso_io_num = MISO_PIN;
config.sclk_io_num = SCLK_PIN;
config.quadwp_io_num = -1; // -1 not used
config.quadhd_io_num = -1; // -1 not used
config.flags = SPICOMMON_BUSFLAG_DUAL | SPICOMMON_BUSFLAG_MASTER;
spi_bus_initialize(VSPI_HOST, &config, SPI_DMA_DISABLED); // 0 DMA not used
Now the setup for the device (same setup for single mode or dual):
spi_device_interface_config_t devcfg = {
.clock_speed_hz = freq,
.command_bits = 8,
.address_bits = 24,
.dummy_bits = 8,
.mode = 0, // SPI MODE 0
.flags = 0,
.spics_io_num = _cs,
.queue_size = 1,
.pre_cb = NULL,
.post_cb = NULL};
ESP_ERROR_CHECK(spi_bus_add_device(VSPI_HOST, &devcfg, &data_Ram));
Now the setup for the transaction:
spi_transaction_t t;
memset(&t, 0, sizeof(t)); // Zero out the transaction
t.cmd = WRITE;
t.tx_buffer = data;
t.rx_buffer = NULL;
t.addr = address;
t.length = size * 8;
if (USE_DIO) // configure these flags in case of DIO
t.flags = SPI_TRANS_MODE_DIO | SPI_TRANS_MULTILINE_ADDR | SPI_TRANS_MULTILINE_CMD;
ESP_ERROR_CHECK(spi_device_transmit(data_Ram, &t)); // Transmit!
It works nicely in the single mode but with the dual mode I got the error:
E (1618) spi_master: check_trans_valid(699): Incompatible when setting to both multi-line mode and half duplex mode
Does it mean I cannot use DIO in half duplex mode with the SPI master library?
Is there something I should change in my setup ?
I tried to specify the SPI_DEVICE_HALFDUPLEX flag in the spi_device_interface_config_t. Does not help.
Unfortunately I did not find any example on internet.
Thanks for your heads up!
E (1618) spi_master: check_trans_valid(699): Incompatible when setting to both multi-line mode and half duplex mode means that you cannot use MISO and MOSI for transfering (multiline) AND use them at the same time (full duplex).
Set your device to half duplex to fix the problem:
spi_device_interface_config_t devcfg = {
.flags = SPI_DEVICE_HALFDUPLEX,
...
};
In my experience, SPI_TRANS_MULTILINE_ADDR doesn't work, at least with spi_device_transmit.
If your ram device allows it, try without the "multilined" address and command.
I want to know the implementation sequence of the function FltGetVolumeGuidName(), I basically want to get the Guid of all volumes from my system ?
Below is the code, which I tried, any help will be greatly appreciated , thanks in advance.
volumeContext->GUIDinfo.Buffer = NULL; //kernel crash here <<<<======
volumeContext->GUIDinfo.Length = 0;
volumeContext->GUIDinfo.MaximumLength = 0;
//fetching correct size
(void) FltGetVolumeGuidName(pVolumeList, &volumeContext->GUIDinfo, &BufferSizeNeeded);
//Allocating space
if (NULL == volumeContext->GUIDinfo.Buffer) {
status = STATUS_INSUFFICIENT_RESOURCES;
DbgPrint("\n STATUS_INSUFFICIENT_RESOURCES");
break;
}
//Memory allocation
volumeContext->GUIDinfo.Buffer = (PWCHAR)ExAllocatePoolWithTag(PagedPool, BufferSizeNeeded, MEMTAG_VOL_GUID);
volumeContext->GUIDinfo.Length = 0;
ASSERT(BufferSizeNeeded <= UNICODE_STRING_MAX_BYTES);
volumeContext->GUIDinfo.MaximumLength = (ULONG)BufferSizeNeeded;
ntStatus = FltGetVolumeGuidName(pVolumeList, &volumeContext->GUIDinfo, &BufferSizeNeeded);
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
DbgPrint("\n STATUS_BUFFER_TOO_SMALL");
}
Eryk, thank you very much. Agreed that each of the PFLT_VOLUME I get a valid pointer. Now when I call FltGetVolumeGuidName(PFLT_VOLUME (pVolumeList) &volumeContext->GUIDinfo, BufferSizeNeeded) as mentioned above and print the values in the &volumeContext->GUIDinfo = (Null) and BufferSizeNeeded = 96.
With the literature around on FltGetVolumeGuidName, I understand 1st call FltGetVolumeGuidName to get the BufferSizeNeeded and use this size and allocate memory and call again FltGetVolumeGuidName to fetch Guid.
I have a problem (kernel panic) when I initialize as below
volumeContext->GUIDinfo.Buffer = NULL; //kernel crash here <<<<======
volumeContext->GUIDinfo.Length = 0;
volumeContext->GUIDinfo.MaximumLength = 0;
I am writing an I2C slave routine for PIC18F25K80 and I am stuck on a weird problem.
This is my routine:
void interrupt interruption_handler() {
PIE1bits.SSPIE = 0; // Disable Master Synchronous Serial Port Interrupt
if (PIR1bits.SSPIF != 1) {
//This is not I2C interruption;
PIE1bits.SSPIE = 1; // Enable Master Synchronous Serial Port Interrupt
return;
}
//Treat overflow
if ((SSPCON1bits.SSPOV) || (SSPCON1bits.WCOL)) {
dummy = SSPBUF; // Read the previous value to clear the buffer
SSPCON1bits.SSPOV = 0; // Clear the overflow flag
SSPCON1bits.WCOL = 0; // Clear the collision bit
SSPCON1bits.CKP = 1;
board_state = BOARD_STATE_ERROR;
} else {
if (!SSPSTATbits.D_NOT_A) {
//Slave address
debug(0, ON);
//Read address
address = SSPBUF; //Clear BF
while(BF); //Wait until completion
if (SSPSTATbits.R_NOT_W) {
SSPCON1bits.WCOL = 0;
unsigned char a = 0x01;
SSPBUF = a;//0x01 works //Deliver first byte
asm("nop");
}
} else {
if (SSPSTATbits.BF) {
dummy = SSPBUF; // Clear BF (just in case)
while(BF);
}
if (SSPSTATbits.R_NOT_W) {
//Multi-byte read
debug(1, ON);
SSPCON1bits.WCOL = 0;
SSPBUF = 0x02; //Deliver second byte
asm("nop");
} else {
//WRITE
debug(2, ON);
}
}
transmitted = TRUE;
SSPCON1bits.CKP = 1;
PIR1bits.SSPIF = 0;
PIE1bits.SSPIE = 1; // Enable Master Synchronous Serial Port Interrupt
}
}
It works like a charm if I set constant values on SSPBUF. For example, if you do:
SSPBUF = 0x01;
(...)
SSPBUF = 0x02;
I get the two bytes on the master. I can even see the wave forms of the bytes being transmitted on the oscilloscope. Quite fun!
But when I try to set SSPBUF using a variable like:
unsigned char a = 0x01;
SSPBUF = a;
I get zero on the master.
It is driving me crazy.
Some hypothesis I've discarded:
Watchdog timer is messing up interrupting in the middle of the protocol: It is not. It is disabled and the problem happens in both SSPBUF assignments
I need to wait until BF goes low to continue: I don't. AFAIK, you setup the SSPBUF, clear SSPIF, set CKP and return from interruption to take care of life in 4Mhz while the hardware send data in few Khz. It will interrupt you again when it finishes.
It makes no sense to me. How good it is if you cannot define an arbitrary value using a variable?
Please gurus out there, enlighten this poor programmer.
Thanks in advance.
It has something to do with how the compiler generates the code and some undocumented/unknown PIC restriction around SSPBUF (it is an special register anyway).
I found out that it works when the compiler uses movwf and does not work when the compiler uses movff.
I moved the question to another forum because I realized the audience there is more adequate.
You will find more details here:
https://electronics.stackexchange.com/questions/251763/writing-sspbuf-from-variable-in-i2c-slave-protocol-in-pic18/251771#251771
Try move declaration : "unsigned char a = 0x01;"
to the beginning of the function or try define it as volatile global variable.
take into accunte that SSPBUF is both read and write buffer.check if there are conditions that may cause I2C module to reset this buffer.
I use the new 3D reconstruction API's (MIRA release). I have a problem when a call the Tango3DR_update function. It returns TANGO_3DR_INVALID code when I set the parameters associated with an image camera (const Tango3DR_ImageBuffer * image * const Tango3DR_Pose image_pose, Tango3DR_CameraCalibration const * calibration). I have checked my parameters, they seem to be correct. When I call this function without image parameters, this to work properly ... Is this a known bug?
thank you in advance for your answers.
TLDR; The support library ImageBufferManager has a bug with strides. Do color_image.stride = image_buffer->width; when creating your Tango3DR_ImageBuffer.
I think there are two things :
Image Format
First, you have to make sure to use the TANGO_HAL_PIXEL_FORMAT_YCrCb_420_SP. You can do that by using the ImageBufferManager from the support library.
ImageBufferManager and strides
Second, there is a catch if you use the support library ImageBufferManager though. TangoSupport_getLatestImageBuffer seems to fail to initialize the stride of the returned image (I got 0 and some other very large values) which the 3DR library doesn't like. The original TangoImageBuffer from OnColorAvailable has stride=1280 (=image_width) and forcing that value on the TangoImageBuffer returned
from the ImageBufferManager seems to fix the issue. I believe this is a bug in ImageBufferManager.
This means doing
color_image.stride = image_buffer->width;
instead of
color_image.stride = image_buffer->stride
when creating the Tango3DR_ImageBuffer.
Full code example
I got it working with the following code in my Render method :
TangoImageBuffer* image_buffer;
ret = TangoSupport_getLatestImageBuffer(
image_buffer_manager_, &image_buffer);
if (ret != TANGO_SUCCESS) {
LOG(ERROR) << "Error in TangoSupport_getLatestImageBuffer";
}
...
Tango3DR_ImageBuffer color_image;
color_image.width = image_buffer->width;
color_image.height = image_buffer->height;
// VERY Important - The support library ImageBufferManager seems to have
// a bug where it will always put the stride of the returned buffer
// at 0, which causes 3DR to fail
color_image.stride = image_buffer->width;
color_image.timestamp = image_buffer->timestamp;
color_image.format = (Tango3DR_ImageFormatType)image_buffer->format;
color_image.data = image_buffer->data;
ret = Tango3DR_update(
tango_3dr_context_,
&cloud,
&depth_pose_3dr,
&color_image,
&color_pose_3dr,
&tango_3dr_calibration_,
&updated_indices);
I am using the ImageManager from the support library. So my OnColorAvailable looks like that
void SynchronizationApplication::OnColorAvailable(
const TangoImageBuffer* buffer) {
if (tango_3dr_enabled_ && tango_3dr_use_color_) {
TangoErrorType ret = TangoSupport_updateImageBuffer(
image_buffer_manager_, buffer);
if (ret != TANGO_SUCCESS) {
LOG(ERROR) << "Error in TangoSupport_updatePointCloud";
}
}
}
And the image_buffer_manager_ is initialized as follow (the pixel format might be important).
TangoSupport_createImageBufferManager(
TANGO_HAL_PIXEL_FORMAT_YCrCb_420_SP,
image_width_,
image_height_,
&image_buffer_manager_
);
I am copying the calibration as follow :
void CopyCalibrationTangoTo3DR(const TangoCameraIntrinsics& tango,
Tango3DR_CameraCalibration* out) {
out->calibration_type =
(Tango3DR_TangoCalibrationType)tango.calibration_type;
out->cx = tango.cx;
out->cy = tango.cy;
memcpy(out->distortion, tango.distortion, sizeof(double) * 5);
out->fx = tango.fx;
out->fy = tango.fy;
out->height = tango.height;
out->width = tango.width;
}
Here is the COM port opening part:
portHandle=CreateFileA(portName, GENERIC_READ|GENERIC_WRITE,0, NULL, OPEN_EXISTING, 0, NULL);
if (portHandle == INVALID_HANDLE_VALUE)
{
return -1;
}
COMMCONFIG Win_CommConfig;
COMMTIMEOUTS Win_CommTimeouts;
unsigned long confSize = sizeof(COMMCONFIG);
Win_CommConfig.dwSize = confSize;
GetCommConfig(portHandle, &Win_CommConfig, &confSize);
Win_CommConfig.dcb.Parity = 0;
Win_CommConfig.dcb.fRtsControl = RTS_CONTROL_DISABLE;
Win_CommConfig.dcb.fOutxCtsFlow = FALSE;
Win_CommConfig.dcb.fOutxDsrFlow = FALSE;
Win_CommConfig.dcb.fDtrControl = DTR_CONTROL_DISABLE;
Win_CommConfig.dcb.fDsrSensitivity = FALSE;
Win_CommConfig.dcb.fNull=FALSE;
Win_CommConfig.dcb.fTXContinueOnXoff = FALSE;
Win_CommConfig.dcb.fInX=FALSE;
Win_CommConfig.dcb.fOutX=FALSE;
Win_CommConfig.dcb.fBinary=TRUE;
Win_CommConfig.dcb.DCBlength = sizeof(DCB);
if (baudrate != -1)
{
Win_CommConfig.dcb.BaudRate = baudrate;
}
Win_CommConfig.dcb.ByteSize = 8;
Win_CommTimeouts.ReadIntervalTimeout = 50;
Win_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
Win_CommTimeouts.ReadTotalTimeoutConstant = 110;
Win_CommTimeouts.WriteTotalTimeoutMultiplier = 0;
Win_CommTimeouts.WriteTotalTimeoutConstant = 110;
SetCommConfig(portHandle, &Win_CommConfig, sizeof(COMMCONFIG));
SetCommTimeouts(portHandle,&Win_CommTimeouts);
return 0;
It connects OK, I manage to issue some AT comamnds and read back OK\n> responses, even one of the upper level protocol (OBD2: the command is 0100\r) gets a proper answer. But when I attempt other commands such as scanning of supported pids (e.g 0000\n, 0101\n, 0202\n etc) the whole thing either echoes back whatever I write to it or just times out. Issuing the same sequence of commands from a hyperterminal works properly. These serial ports are virtual simulated ports should it matter - http://com0com.sourceforge.net/.
What am I missing ? Perhaps some reading / setting / resetting of someof the pins ? It has been a while since I last mingled with RS232... Thanks!
EDIT: just tried the scantool at https://www.scantool.net/downloads/diagnostic-software/ and it worked ok too.
e.g 0000\n, 0101\n, 0202\n
This was the issue. It should have been \r at the end, not \n. Hyperterminal worked because the key would insert a \r here on Windows. Probablysome validation of the input was done by the device connected and so it got to work even with the wrong terminator character fed in.