I am having a problem when Sending char from STM32F411 to PC it reads into garbage, but when I do the opposite operation the MCU correctly reads char sent.
I perform following actions:
Enable GPIOA clock and configure pins 9 and 10 alternate function.
Enable USART1, leave default values for M (message length), stop bits, DMA
Set USARTDIV to result in 9600 baud at 16Mhz (HSI) *
Configure USART to send idle frame as first transmission
* I have also tried with 100Mhz APB2 bus frequency with the same result.
Configuring USART
// 1. Enable USART
SET_BIT(USART1->CR1, USART_CR1_UE);
// 5. Select the desired baud rate in BRR
SET_BIT(USART1->BRR, 0x683); // USARTDIV
// 6. Set TE in CR1 to send an idle frame as first transmission
SET_BIT(USART1->CR1, USART_CR1_TE);
After that I am trying to accept an a character with RealTerm2.0 with following configuration: 9600 8N1 None
Character is sent by following code:
void SendChar_USART(char pChar)
{
// Transmitter 7, 8
// 7. Write the data to send in the DR register (this clears TXE)
USART1->DR = pChar;
while(!READ_BIT(USART1->SR, USART_SR_TXE));
}
Update 1
Switching to USART2 with absolute same configuration solves the problem and it is possible to recover text from serial terminal, however this question unanswered "Why USART1 does not work as expected?"
There is a capacitor on the way to the PA9 pin of the extension connector filtering out the USART1 TX. Peter Harrison explains the issue very well, i think.
http://www.micromouseonline.com/2013/05/05/using-usart1-on-the-stm32f4discovery/
Related
The scenario: I have a STM32 MCU, which uses an UART in DMA Mode with Idle Interrupt for RS485 data transfer. The baud rate of the UART is set in CubeMX, in this case to 115200. My Code works fine, when the Host uses the correct baud rate, it is also "long time" stable, no issues or worries.
BUT: when I set the wrong baud rate at the host, e.g. 56700 instead of 115200, the UART stops receiving data, even if I later set the baud rate at the host to the same baud rate the Microcontroller uses, it won't work. The only way to solve this issue so far is: reset the MCU and connect again with the correct baud rate.
To give you some (Pseudo-)Code:
uint8_t UART_Buf[128];
HAL_UART_Receive_DMA(&huart2, UART_Buf, 128);
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
Or in Plain Words: there is a UART Buffer for DMA (UART_Buf[128]) and the UART is started with HAL_UART_Receive_DMA(...), DMA Rx is set to circular mode in CubeMX, also the Idle-Interrupt is activated, using the HAL Macro: __HAL_UART_ENABLE_IT(...); This code works fine so far.
Works fine means:
when I transmit data from my PC to the Micro, the (one) Idle Interrupt is triggered (correctly) by the MCU. In the ISR I set a flag, to start the data parsing afterwards. I receive exactly the number of bytes I have sent, and all is fine.
BUT: when I make the wrong setting in my Terminal Program and instead of the (correct) baud rate of 115200, the baud rate select menu is set to e.g. 57600, the trouble begins:
The idle interrupt will still trigger after each transmission.
But it triggers 2-4 times in a quick "burst" (depending on the baud rate) and the number of bytes received is 0. I'd expect at least some bs data, but there is exactly 0 data in the buffer - which I can check with the debugger. There is obviously received nothing. When I change the baud rate in my terminal program and restart it, there is still nothing received on the MCU.
I could live with 0 received bytes, if the baud rate of the host is incorrect, but it's pretty uncool that one incoming transmission of a host with the wrong baud rate disables the UART until a hardware reset is done.
My attempts to resolve this were so far:
count the "Idle Interrupt Bursts" in combination with 0 received bytes to trigger a "self reset" routine, that stops the UART and restarts it, using the MX_USART2_UART_Init(); Routine. With zero effect. I can see the Idle Interrupt is still triggered correctly, but the buffer remains empty and no data is transferred into the buffer. The UART remains in a non-receiving state.
The Question
Has anyone out there experienced similar issues, and if yes: how did you solve that?
Additional Info: this happens on a STM32F030 as well as on a STM32G03x
When you send to the UART at the wrong baud rate it will appear to the receiver as framing errors and/or noise errors. It could also appear as random characters being received correctly, but this is less likely so don't be surprised to have nothing in your buffer.
When you are receiving with DMA, it is normal to turn the error interrupt on or else poll the error bits. When an error is detected you would then re-initialize everything and restart the DMA. This sounds like what you are trying to do by counting the idle interrupts, but you are just not checking the right bits.
If you don't want to do that, it is not impossible to imagine that you have nothing to do at the driver level and want to try to do the resynchronisation at a higher level (eg: start reading again and discard everything until a newline character) but you will have to bear in mind at least two things:
First, make sure you clear the DDRE bit in the USART_CR3 register. The name "DMA Disable on Reception Error" speaks for itself.
Second, the UART peripheral is able to self resynchronize, as long as you have an idle gap between bytes. If you switch the transmitter to the correct baud rate but keep blasting out data then the receiver may never correctly identify which bit is a start bit.
After investigating this issue a little bit further, i found a solution.
Abstract:
When a host connects to the MCU to an UART with an other baud rate than the UART is set to, it will go into an error state and stop DMA transmission to the RX Buffer. You can check if there is an error with the HAL_UART_GetError(...) function. If there is an error, stop the UART/DMA and restart it.
The Details:
First of all, it was not the DDRE bit in the USART_CR2 register. This was set to 0 by CubeMX. But the hint of Tom V led me into the right direction.
I tried to recover the UART by playing around with the register bits. I read through the UART section of the reference manual multiple times and tried to figure out, which bits to set in which order, to resolve the error condition manually.
What I found out:
When a transmission with the wrong baud rate is received by the UART the following changes in the UART Registers occur (on an STM32F030):
Control register 1 (USART_CR1) - Bit 8 (PEIE) goes from 1 to 0. PEIE is the Parity Interrupt Enable Bit.
Control register 2 (USART_CR2) - remains unchanged
Control register 3 (USART_CR3) - changes from 0d16449 to 0d16384, which means
Bit 0 (EIE - Error Interrupt enable) goes from 1 to 0
Bit 6 (DMAR - DMA enable receiver) goes from 1 to 0
Bit 14 (DEM - Driver enable mode) remains unchanged at 1
USART_CR3.DEM makes sense. I am using the RS485-Functionality of the F030, so the UART handles the Driver-Enable GPIO by itself.
the transition from 1 to 0 at USART_CR3.EIE and USART_CR3.DMAR are most probably the reason why no more data are transfered to the DMA buffer.
Besides that, the error Flags in the Interrupt and status register (USART_ISR) for ORE and FE are set. ORE stands for Overrun Error and FE for Frame Error. Although these bit can be cleared by writing a 1 to the corresponding bit of the Interrupt flag clear register (USART_ICR), the ErrorCode in the hUART Struct remains at the intial error value.
At the end of my try&error process, I managed to have all registers at the same values they had during valid transmissions, but there were still no bytes received. Whatever i tried, id had no effect. The UART remained in a non receiving state. So i decided to use the "brute force" approach and use the HAL functions, which I know they work.
Finally the solution is pretty simple:
if an Idle Interrupt is detected, but the number of received bytes is 0
=> check the Error-Status of the UART with HAL_UART_GetError(...)
If there is an error, stop the UART with HAL_UART_DMAStop(...) and restart it with HAL_UART_Receive_DMA(...)
The code:
if(RxLen) {
// normal execution, number of received bytes > 0
if(UA_RXCallback[i]) (*UA_RXCallback[i])(hUA); // exec RX callback function
} else {
if(HAL_UART_GetError(&huart2)) {
HAL_UART_DMAStop(&huart2); // STOP Uart
MX_USART2_UART_Init(); // INIT Uart
HAL_UART_Receive_DMA(&huart2, UA2_Buf, UA2_BufSz); // START Uart DMA
__HAL_UART_CLEAR_IDLEFLAG(&huart2); // Clear Idle IT-Flag
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); // Enable Idle Interrupt
}
}
I had a similar issue. I'm using a DMA to receive data, and then periodically checking how many bytes were received. After a bit error, it would not recover. The solution for me was to first subscribe to ErrorCallback on the UART_HandleTypeDef.
In the error handler, I then call UART_Start_Receive_DMA(...) again. This seems to restart the UART and DMA without issue.
This seems to be a problem that is somewhat common, but I have been unsuccessful with any of the solutions I have found online. Specifically I am trying to transmit a 1024 byte buffer (full 128x64 px image) to a SSD1306 display via I2C/DMA and the HAL generated in cubeIDE. I am using a STML432 nucleo board. I have no problem transmitting the buffer without DMA using HAL_I2C_Mem_Write
Based on other questions I have seen, the problem lies in the fact that the DMA finishes while the I2C bus is still working on the transmit. I just don't know how to remedy this and the examples given usually don't use the HAL (unfortunately, despite my efforts I am not quite competent to correctly apply them to the HAL myself I guess). I have tried using the interrupts for I2c and DMA with no luck, only about the first 254 bytes get transferred (just shy of two rows showing on the screen).
Here is my code for sending the buffer:
static void ssd1306_WriteMData_DMA(const uint8_t *data, uint16_t size)
{
while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
HAL_I2C_Mem_Write_DMA(&hi2c1, I2C_ADDR, SSD1306_REG_MDAT, 1, (uint8_t*)data, size);
}
and the code for each interrupt handler:
void I2C1_EV_IRQHandler(void)
{
/* USER CODE BEGIN I2C1_EV_IRQn 0 */
if(I2C1->ISR & I2C_ISR_TCR){
I2C1->CR2 |= (I2C_CR2_STOP);// stop i2c
I2C1->ICR |= (I2C_ICR_STOPCF);// Reset the ICR flag.
// stop DMA
DMA1->IFCR |= DMA_IFCR_CTCIF6;
// clear flag
DMA1_Channel6->CCR &= ~DMA_CCR_EN;
}
/* USER CODE END I2C1_EV_IRQn 0 */
//HAL_I2C_EV_IRQHandler(&hi2c1);
/* USER CODE BEGIN I2C1_EV_IRQn 1 */
/* USER CODE END I2C1_EV_IRQn 1 */
}
void DMA1_Channel6_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel6_IRQn 0 */
// stop DMA
DMA1->IFCR |= DMA_IFCR_CTCIF6;
// clear flag
DMA1_Channel6->CCR &= ~DMA_CCR_EN;
/* USER CODE END DMA1_Channel6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_i2c1_tx);
/* USER CODE BEGIN DMA1_Channel6_IRQn 1 */
/* USER CODE END DMA1_Channel6_IRQn 1 */
}
I think that is all the pertinent code, let me know if there is something else I am missing. All of the initialization code for the peripherals was done through cubeMX, but I can post that if need be, or the settings. I feel like it is something really simple that I'm missing, but this is a bit over my head to be honest so I don't quite grasp exactly what's going on...
Thanks for any help!
Problem is in your custom DMA1_Channel6_IRQHandler and I2C1_EV_IRQHandler. Those functions will be called right after I2C transfers 255 bytes, which is MAX_NBYTE_SIZE for NBYTES. HAL already have all required interrupt routines inside stm32l4xx_hal_i2c.c:
Sets I2C transfer IRQ handler to I2C_Master_ISR_DMA;
Checks if data size is larger than 255 bytes and uses reload mode.
Sets I2C DMA complete callback to I2C_DMAMasterTransmitCplt;
Starts DMA using HAL_DMA_Start_IT()
Configures I2C registers using I2C_TransferConfig()
HAL driver will handle all I2C+DMA interrupts using I2C_Master_ISR_DMA and I2C_DMAMasterTransmitCplt:
I2C_DMAMasterTransmitCplt will restart DMA for each chunk of 255 (MAX_NBYTE_SIZE) or less bytes.
I2C_Master_ISR_DMA will reset RELOAD/NBYTES registers using I2C_TransferConfig.
For last block of data I2C_AUTOEND_MODE is used.
So all you need is
remove "user code" from DMA1_Channel6_IRQHandler and I2C1_EV_IRQHandler functions
enable I2C1 event interrupt in STM32 Device Configuration Tool
configure DMA with data width byte/byte
perform a single call of HAL_I2C_Mem_Write_DMA(...) to start transfer
check HAL_I2C_STATE_READY before next transfer
See HAL_I2C_Mem_Write_DMA, I2C_Master_ISR_DMA and I2C_DMAMasterTransmitCplt source code in stm32l4xx_hal_i2c.c to understand how it works.
About why DMA finishes while I2C is still working: HAL driver sends I2C data over DMA using 255 byte chunks, stops DMA, starts DMA, clears I2C_CR2 NBYTES/RELOAD, enables DMA. DMA may be run continuously using DMA_CIRCULAR mode, but currently it is not implemented in HAL I2C drivers. Here is example of using I2C with DMA_CIRCULAR mode:
// DMA enabled single time
hi2c1.hdmatx->XferCpltCallback = MY_I2C_DMAMasterTransmitCplt;
HAL_DMA_Start_IT(hi2c1.hdmatx, (uint32_t)&i2cBuffer, (uint32_t)&hi2c1.Instance->TXDR, I2C_BUFFER_SIZE);
MY_I2C_TransferConfig(&hi2c1, (uint16_t)DAC_ADDR, 254, I2C_RELOAD_MODE, I2C_GENERATE_START_WRITE); // in first call using I2C_GENERATE_START_WRITE
uint32_t tmpisr = I2C_IT_TCI;
__HAL_I2C_ENABLE_IT(&hi2c1, tmpisr);
hi2c1.Instance->CR1 |= I2C_CR1_TXDMAEN;
Still need to clear I2C_CR2 NBYTES/RELOAD using MY_I2C_TransferConfig each 254 bytes (I do not use 255 to align interrupt firing to even index in array):
static HAL_StatusTypeDef MY_I2C_Master_ISR_DMA(struct __I2C_HandleTypeDef *hi2c, uint32_t ITFlags, uint32_t ITSources)
{
if (__HAL_I2C_GET_FLAG(&hi2c1, I2C_FLAG_TCR) == SET)
{
MY_I2C_TransferConfig(&hi2c1, (uint16_t)DAC_ADDR, 254, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); // in repeated calls using I2C_NO_STARTSTOP
}
return HAL_OK;
}
With this approach DMA circular buffer size is not limited to 255 bytes:
#define I2C_BUFFER_SIZE 1024
uint8_t i2cBuffer[I2C_BUFFER_SIZE];
Main.c should have MY_I2C_TransferConfig() function, which is copy pasted version of private function HAL_I2C_TransferConfig() from stm32l4xx_hal_i2c.c. On earlier STM32 microcontrollers there is no NBYTES/RELOAD fields and I2C_CR2 does not need to be updated this way.
Using DMA in circular mode allows to achieve highest frame rate, you just need to fill DMA buffers in time using XferHalfCpltCallback and XferCpltCallback callbacks. Frames may be copied from larger buffer by using memcpy() or DMA MEMTOMEM transfer.
You haven't said which STM32 you are using. They have different bit definitions (because the I2C peripherals in the earlier released parts were rubbish) but it looks like you are using one of the later ones.
Basically you can find what you need in the bit definitions for the I2C registers in the reference manual. If you are setting stop before it has finished you need to look for a BUSY bit that gets cleared or BTF (byte transfer finished) bit that gets set when it is time for you to send stop.
I'm trying to toggle an LED at PC13 by toggling PC14, the problem is that the interrupt handler is kept being called without toggling PC14 and the the pending interrupt is not cleared using EXTI->PR register, nor cleared manually using the debugger. I tried also clearing it in NVIC->ICPR, I'm not sure why there are two registers for clearing the same interrupt.
here is my code
and you can find the header in
https://github.com/AymenSekhri/tinyHAL-STM32f103/tree/master/STM32F103-HAL/tinyHAL
/*
* Description:
* Toggle LED at C13 whenever C14 goes from HIGH to LOW.
*
*/
#include "tinyHAL/stm32f103_hal.h"
int main(){
//Enable AFIO clock from RCC
enablePeripheralClock(Peripheral_AFIO);
//Enable and configure C13 & C14
enablePeripheralClock(Peripheral_GPIOC);
configureGPIO(Peripheral_GPIOC, 13, GPIO_MODE_OUT_50MHZ, GPIO_CONF_OUT_PUSHPULL);
configureGPIO(Peripheral_GPIOC, 14, GPIO_MODE_IN, GPIO_CONF_IN_PUSHUP_PULLDOWN);
//Link EXTI14 to C14
AFIO->EXTICR[3] = (AFIO->EXTICR[3] & ~(0xF<<8)) | 2;
//Configure inturrput at EXTI14 falling edge
EXTI->FTSR |= 1<<14;
//Unmask interrupt 40 (EXTI10-15)
EXTI->IMR |= 1<<14;
//Set Priority to interrupt 40 (EXTI10-15)
NVIC->IP[40] |= 0x10;
//Enable interrupt 40 (EXTI10-15)
NVIC->ISER[40>>5] |= (1 << (40&0x1F));
while(1);
}
void EXTI15_10_IRQHandler(void){
toggleGPIOBit(Peripheral_GPIOC, 13);
if (EXTI->PR & (1 << 14)){
EXTI->PR |= (1 << 14);
}
//NVIC->ICPR[40>>5] |= (1 << (40&0x1F));
__COMPILER_BARRIER();
}
The best solution to get rid of the electronic noise at the pin that (over-)triggers your EXTI is to improve the hardware - but this is the software board, not the electronic one.
If you had a TIM channel connected to that pin, I would recommend to use it to filter the signal coming in. But I think that PC14 doesn't have a timer.
The second-best solution (and this is where workarounds have already started!) is to use a timer (the TIM, not its channel), either to establish a periodic time base to sample the pin (by DMA or by an ISR, and feed samples into a software-based filtering...) - or to deactivate the EXTI interrupt in the EXTI ISR, start the timer and re-activate the EXTI interrupt when the timer expired.
Both of these µC-based approaches are clumsy and clearly inferior to developing a good hardware. This doesn't say that with a "good" hardware you shouldn't add some debouncing or noise protection inside your software!
As #P__J__ suggest add some denouncing logic. There are two methods for de-bouncing like suing RC filter and using software de-bouncing logic.
Due to noise on the pins ISR is getting executed continously.
You can check one more thing.
Try pulling UP/Down the pin and observe the behaviour. ISR should not get executed if logic level doesn't change on Pin.
Maybe It's because of TAMPER/RTC second output redirected to PC13. I also faced the same problem before when using PC13 as EXTI. Set BKP_RTCCR->ASOE to 1 to force it as alarm output that will never triggered because i dont't set any rtc alarm.
I am using stm32 to read the ds18b20 with HAL library
I think the init is correct but the read and write is not
anyone can tell me why it is not right?
for the write,here is the code
if ((data & (1 << i)) != 0)
{
MX_GPIO_Set(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
delay_ms(1);
MX_GPIO_Set(0);
delay_ms(60);
}
else
{
MX_GPIO_Set(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
delay_ms(60);
MX_GPIO_Set(0);
}
it is write one bit data.
and for the read code
MX_GPIO_Set(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
delay_ms(2);
MX_GPIO_Set(0);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET)
{
value |= 1 << i;
}
delay_ms(60);
the MX_GPIO_Set(1) means set the GPIO output
where is wrong?
please do not tell me use library or code in github.I want to write code myself so I can understand the ds18b20.
The DS18B20 uses the One-Wire protocol.
https://en.wikipedia.org/wiki/1-Wire
Each bit takes about 60 microseconds to transmit.
1s are HIGH during most of the transmission and 0s are LOW during most of the transmission. The start of the next bit is indicated by a pulse.
One thing that stands out to me is that you're using delay_ms (milliseconds), when you likely want to be using delay_us (microseconds).
Also, you're relying on the bit's timing to be exact (which it probably won't be). Instead, base your timing on the pulse.
It's more complicated than that.
When reading, you need to be continually checking the pin's value and interpreting what it means rather than putting in delays and hoping that the timing matches up.
I have not tested this code and it's incomplete.
This is just to illustrate a technique.
To start off, we're going to set our output to LOW and wait
for the sensor to go LOW for at least 200us. (Ideally 500us. 200us is our minimum requirement.)
This is the "RESET" sequence that tells us that new data is about to start.
const int SleepIntervalMircoseconds = 5;
// Start off by setting our output to LOW (aka GPIO_PIN_RESET).
MX_GPIO_Set(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
// Switch back to reading mode.
MX_GPIO_Set(0);
const int ResetRequiredMiroseconds = 200;
int pinState = GPIO_PIN_SET;
int resetElapsedMicroseconds = 0;
while (pinState != GPIO_PIN_RESET || resetElapsedMicroseconds < ResetRequiredMiroseconds) {
pinState = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);
if (pinState != GPIO_PIN_RESET) {
resetElapsedMicroseconds = 0;
continue;
}
delay_us(SleepIntervalMircoseconds);
// Note that the elapsed microseconds is really an estimate here.
// The actual elapsed time will be 5us + the amount of time it took to execute the code.
resetElapsedMicroseconds += SleepIntervalMircoseconds;
}
This only gets us started.
After you've received the reset signal, you need to indicate to the other side that you've received it by setting your value HIGH for certain amount of time.
I'm unable to comment on your code, because important parts like the GPIO setup and the source for the functions called are missing. However, if the bit timing gives you trouble, you might try this.
Using a UART to Implement a 1-Wire Bus Master
then you don't have to deal with delays and timings other than calculating the UART baud rate.
All STM32 UARTs support one wire operation with an open drain GPIO pin. Connect the I/O pin of the device to an UART TX pin. Configure the pin as open-drain alternate function output, with the alternate function number for the UART if applicable. Enable the UART and set it to single wire operation in the control registers.
Set the UART baud rate to 7407, and send 0xF0, that's the reset pulse. Wait for RXNE and read the UART data register. If it's not 0xF0, then the device is answering with a presence pulse.
Set the UART baud rate to 133333, and you can start communicating. To send a 0 bit, write 0x00 to the UART data register. To send a 1 bit, write 0xFF to the UART data register. To receive a bit, write 0xFF, wait for RXNE, and read the data register. If the byte read is 0xFF, then it's a 1, otherwise (any other value read) it's a 0.
I'm trying to access the bootloader for a Nucleo L476RG "slave" board.
The "master" board is a Nucleo L496ZG board. In my program, I have a DigitalOut defined on the master board called extBoot0, extReset. These go off to the boot0 and NRST pins on the slave board. Additionally, I have a Serial instance called usart on the master, which is attached to UART2 on the slave board. Also, it appears that there BOOT1 is preset to run the bootloader, i.e. it's asserted low and cannot be changed to run whatever's in SRAM.
Currently, in resetToBootloader, I set BOOT0 high and drop NRST low for 0.1 seconds, and bring it back up high. I've observed that running this function indeed resets the device and prevents the program from running.
In initBootloader, I format the serial per AN2606: 8-bit, even parity, 1 stop bit. I then send 0x7F over that serial bus to the slave board. I'm not getting any response and using a logic analyzer, I've confirmed that the slave is getting it on the right pin and there is no changes in the slave's TX input. What else needs to be done to start the bootloader?
Here's my relevant code:
DigitalOut extBoot0(D7);
DigitalOut extBoot1(D6);
DigitalOut extReset(D5);
Serial usart(/* tx, rx */ D1, D0);
uint8_t rxBuffer[1];
event_callback_t serialEventCb;
void serialCb(int events) {
printf("something happened!\n");
}
void initBootloader() {
wait(5); // just in case?
// Once initialized the USART1 configuration is: 8-bits, even parity and 1 Stop bit
serialEventCb.attach(serialCb);
usart.format(8, SerialBase::Even, 1);
uint8_t buffer[1024];
// write 0x7F
buffer[0] = 0x7F;
usart.write(buffer, 1, 0, 0);
printf("sending cmd\n");
// should ack 0x79
usart.read(rxBuffer, 1, serialEventCb, SERIAL_EVENT_RX_ALL, 0x79);
}
If it helps at all, here's a picture of my board setup.
I believed I solved this by using USART1 instead of USART2. The documentation states that both USART1 and USART2 can be used, but I only receive a 0x79 from USART1.
Additionally, I had to switch from Serial to UARTSerial. The slave first sends an incorrect packet, 0xC0 with an incorrect parity bit. Not really sure why it does that, but it causes the regular Serial instance to not handle the proceeding byte.