cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L152 UART5 error.

kupchykdaniil
Associate III
Posted on July 28, 2014 at 14:07

Good afternoon, I am trying to init UART5 on STM32L152 and it is work wrong.

In the end of the

sw_uart5_init

function

0xAA (0b10101010) value issent to the UART5 data register. The transmission result, registred with osciloscope not same as value sent to the data register. Can you find a mistake in the code or give me some workaround how to solve this problem?

I'm really appreciate your help. PS. The same deal with DMA, corrupted data.

void
sw_uart5_init(
void
)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC|RCC_AHBPeriph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);
// Configure GPIO pin : PD0 -> WS-VEN; PD1 -> WS-FC
GPIO_InitTypeDef GPIO_InitStruct; 
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; 
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_400KHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);
//PC12 ------> UART5_TX
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12; 
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
//PD2 ------> UART5_RX
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; 
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStruct);
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = 1200;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No ;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(UART5, &USART_InitStruct);
USART_Cmd(UART5, ENABLE); 
while
(USART_GetFlagStatus(UART5, USART_FLAG_TC) == RESET);
USART_SendData(UART5,0xaa);
}

0690X00000602vmQAA.jpg #stm32l152 #uart
8 REPLIES 8
Posted on July 28, 2014 at 15:27

Doesn't look unreasonable, there is a START bit, and the data is sent LSB first.

You are measuring two bit times. If that's wrong review how you are clocking the device, the external crystal, and HSE_VALUE definition. You should wait on TXE

while
(USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kupchykdaniil
Associate III
Posted on July 29, 2014 at 12:33

Thank you for recomendation, yesterday I have changed baudrate to 115200 and detect something similar to start bit before data frame, you can see it on the pic. below.

0690X00000602sUQAQ.jpg

 

This effect connected with uart initialization procedure, if I make a delay between uart initialization and send command to data register effect position moves relative to data frame.

How to avoid uart tx pin state change during initialization process?

ivani
Associate II
Posted on July 29, 2014 at 14:10

Just move the I/O pin initialization lines after the UART initialization.
 While the UART is in reset it keeps its output signal in zero, so connecting the I/O MUX at this stage sends this zero to the output pin.

kupchykdaniil
Associate III
Posted on July 29, 2014 at 14:58 I have changed GPIO initialization code position, now it's under UART init. Problem is still here and more it seems like data frame twisting around fail start. Do anyone know how to deal with it, maybe something in the code is absent?

void
uart5_init(
void
)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC|RCC_AHBPeriph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
USART_InitTypeDef USART_InitStruct; 
USART_InitStruct.USART_BaudRate = 115200; 
USART_InitStruct.USART_WordLength = USART_WordLength_8b; 
USART_InitStruct.USART_StopBits = USART_StopBits_1; 
USART_InitStruct.USART_Parity = USART_Parity_No ; 
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 
USART_Init(UART5, &USART_InitStruct); 
USART_Cmd(UART5, ENABLE); 
GPIO_InitTypeDef GPIO_InitStruct; 
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; 
// PD0 -> WS-VEN; PD1 -> WS-FC
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_400KHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12; 
//PC12 ------> UART5_TX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; 
//PD2 ------> UART5_RX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);
while
(USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);
USART_SendData(UART5, 170 );
}

0690X00000602vwQAA.jpg 0690X00000602wkQAA.jpg
Posted on July 29, 2014 at 15:25

void uart5_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct; 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC|RCC_AHBPeriph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
USART_InitTypeDef USART_InitStruct; 
USART_InitStruct.USART_BaudRate = 115200; 
USART_InitStruct.USART_WordLength = USART_WordLength_8b; 
USART_InitStruct.USART_StopBits = USART_StopBits_1; 
USART_InitStruct.USART_Parity = USART_Parity_No ; 
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 
USART_Init(UART5, &USART_InitStruct); 
USART_Cmd(UART5, ENABLE); 
while (USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; // PD0 -> WS-VEN; PD1 -> WS-FC
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_400KHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; //PD2 ------> UART5_RX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12; //PC12 ------> UART5_TX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
while (USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);
USART_SendData(UART5, 170 );
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kupchykdaniil
Associate III
Posted on July 31, 2014 at 09:39

Thanks, fail start delay twisting less and the byte looks good by the oscilloscope.

The problem of receiving bytes on the receiver side was solved by changing HSE_VALUE variable in the ''stm32l1xx.h'' file, simply a real baudrate was wrong. By default it was 8MHz, now it fixed. I have initialized DMA on TX direction from memory to peripherial, and it works, but looks wrong - from array of 10 elements only 8 can be transferred. The last two bytes just lost. I can to create an array with size+2 and all good, but can it work normally? (I have to transfer 185 bytes, so to use interrupt routine is not a good way. )

#include ''stm32l1xx.h''
#include ''stm32l1xx_gpio.h''
#include ''stm32l1xx_rcc.h''
#include ''stm32l1xx_tim.h''
#include ''stm32l1xx_dma.h''
#include ''stm32l1xx_usart.h''
#define sw_wsBuff_Size 10
uint8_t sw_vsBuffer[sw_wsBuff_Size];
void
uart5_init(
void
)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC|RCC_AHBPeriph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = 9600;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No ;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(UART5, &USART_InitStruct);
USART_Cmd(UART5, ENABLE);
USART_DMACmd(UART5, USART_DMAReq_Tx, ENABLE);
while
(USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; 
// PD0 -> WS-VEN; PD1 -> WS-FC
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_400KHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; 
//PD2 ------> UART5_RX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12; 
//PC12 ------> UART5_TX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel1_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel2_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
DMA_InitTypeDef dma;
DMA_DeInit(DMA2_Channel1);
dma.DMA_PeripheralBaseAddr = (uint32_t)&UART5->DR;
dma.DMA_MemoryBaseAddr = (uint32_t)&sw_vsBuffer;
dma.DMA_DIR = DMA_DIR_PeripheralDST;
dma.DMA_BufferSize = 10;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dma.DMA_Mode = DMA_Mode_Normal;
dma.DMA_Priority = DMA_Priority_VeryHigh;
dma.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA2_Channel1, &dma);
// Enable DMA Stream Transfer Complete interrupt
DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, ENABLE);
// Enable the USART Tx DMA request
USART_DMACmd(UART5, USART_DMAReq_Tx, ENABLE);
// Enable the DMA RX Stream
DMA_Cmd(DMA2_Channel1, ENABLE);
}
void
DMA2_Channel1_IRQHandler(
void
)
{
if
(DMA_GetITStatus(DMA2_IT_TE1))
{
DMA_ClearITPendingBit( DMA2_IT_TE1 );
DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, DISABLE);
DMA_ITConfig(DMA2_Channel1, DMA_IT_HT, DISABLE);
DMA_ITConfig(DMA2_Channel1, DMA_IT_TE, DISABLE);
DMA_DeInit(DMA2_Channel1);
USART_DeInit(UART5);
}
if
(DMA_GetITStatus(DMA2_IT_TC1))
{
DMA_ClearITPendingBit( DMA2_IT_TC1);
DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, DISABLE);
DMA_ITConfig(DMA2_Channel1, DMA_IT_HT, DISABLE);
DMA_ITConfig(DMA2_Channel1, DMA_IT_TE, DISABLE);
DMA_DeInit(DMA2_Channel1);
USART_DeInit(UART5);
}
if
(DMA_GetITStatus(DMA2_IT_HT1))
{
DMA_ClearITPendingBit( DMA2_IT_HT1);
}
}

kupchykdaniil
Associate III
Posted on July 31, 2014 at 10:22

Now all works good. All bytes is sent propertly. The mistake was in UART5 deinitialization from interrupt, it can stop UART before last data sent .

#include ''stm32l1xx.h''
#include ''stm32l1xx_gpio.h''
#include ''stm32l1xx_rcc.h''
#include ''stm32l1xx_tim.h''
#include ''stm32l1xx_dma.h''
#include ''stm32l1xx_usart.h''
#define UART5_BAUDRATE 9600
#define UART5_DR_ADDRESS ((uint32_t)0x40005004)
#define sw_wsBytesToSend 8
#define sw_wsBuff_Size sw_wsBytesToSend+2
uint8_t sw_vsBuffer[sw_wsBuff_Size];
void
uart5_init(
void
)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC|RCC_AHBPeriph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = UART5_BAUDRATE;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No ;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(UART5, &USART_InitStruct);
USART_Cmd(UART5, ENABLE);
USART_DMACmd(UART5, USART_DMAReq_Tx, ENABLE);
while
(USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; 
// PD0 -> WS-VEN; PD1 -> WS-FC
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_400KHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; 
//PD2 ------> UART5_RX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12; 
//PC12 ------> UART5_TX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel1_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel2_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
DMA_InitTypeDef dma;
DMA_DeInit(DMA2_Channel1);
dma.DMA_PeripheralBaseAddr = (uint32_t)&UART5->DR;
dma.DMA_MemoryBaseAddr = (uint32_t)&sw_vsBuffer;
dma.DMA_DIR = DMA_DIR_PeripheralDST;
dma.DMA_BufferSize = sw_wsBuff_Size;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dma.DMA_Mode = DMA_Mode_Normal;
dma.DMA_Priority = DMA_Priority_VeryHigh;
dma.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA2_Channel1, &dma);
// Enable DMA Stream Transfer Complete interrupt
DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, ENABLE);
// Enable the USART Tx DMA request
USART_DMACmd(UART5, USART_DMAReq_Tx, ENABLE);
// Enable the DMA RX Stream
DMA_Cmd(DMA2_Channel1, ENABLE);
}
void
DMA2_Channel1_IRQHandler(
void
)
{
if
(DMA_GetITStatus(DMA2_IT_TE1))
{
DMA_ClearITPendingBit( DMA2_IT_TE1 );
DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, DISABLE);
DMA_ITConfig(DMA2_Channel1, DMA_IT_HT, DISABLE);
DMA_ITConfig(DMA2_Channel1, DMA_IT_TE, DISABLE);
DMA_DeInit(DMA2_Channel1);
}
if
(DMA_GetITStatus(DMA2_IT_TC1))
{
DMA_ClearITPendingBit( DMA2_IT_TC1);
DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, DISABLE);
DMA_ITConfig(DMA2_Channel1, DMA_IT_HT, DISABLE);
DMA_ITConfig(DMA2_Channel1, DMA_IT_TE, DISABLE);
DMA_DeInit(DMA2_Channel1);
}
if
(DMA_GetITStatus(DMA2_IT_HT1))
{
DMA_ClearITPendingBit( DMA2_IT_HT1);
}
}

Posted on July 31, 2014 at 18:37

Now all works good. All bytes is sent propertly. The mistake was in UART5 deinitialization from interrupt, it can stop UART before last data sent.

Glad you got it all figured out.

Yes, TC on the DMA says it gave last byte to UART, you'd need to wait for TC on the UART to know when the last bit hit the wire.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..