I am trying to create a simple program that reads RTC clock value and prints it to serial monitor. USART is working fine, but i can't figure out what's wrong with RTC. It is giving me all the time same value that was set in setuRTC(). Also the second interrupt is not working either. Edit: I am using STM32f1 development board, same as this
Here is my RTC setup:
void setupRTC(void){
RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); //Enable the power and backup interface clocks by setting the PWREN and BKPEN bitsin the RCC_APB1ENR register
PWR->CR |= PWR_CR_DBP; //Enable access to the backup registers and the RTC.
RCC->BDCR |= RCC_BDCR_LSEON; //External Low Speed oscillator enable
while((RCC->BDCR & RCC_BDCR_LSERDY) == 0); //Wait until external oscillisator is stabilised
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE;
sendstr(textlse);
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE; //Select Source (LSE oscillator clock used as RTC clock )
RCC->BDCR &= ~((1 << 8) | (1 << 9)); //Unusable clock source, here to prevent warnings, turn off clock sources to RTC.
RCC->BDCR = RCC_BDCR_RTCEN; //RTC clock enable
RTC->CRL &= ~RTC_CRL_RSF; //Clear registers Synchronized Flag
while(!(RTC->CRL & RTC_CRL_RSF)); //Wait for the RSF bit in RTC_CRL to be set by hardware
while((RTC->CRL & RTC_CRL_RTOFF) == 0); //Wait for RTOFF It is not possible to write to the RTC_CR register while the peripheral is completing a previous write operation
RTC->CRL |= RTC_CRL_CNF; //Set the CNF bit to enter configuration mode
/* Set RTC COUNTER MSB word */
RTC->CNTH = (12*3600 + 40*60 + 00) >> 16; //Random time
/* Set RTC COUNTER LSB word */
RTC->CNTL = ((12*3600 + 40*60 + 00)& 0x0000FFFF);
RTC->CRH |= RTC_CRH_SECIE; //Second Interrupt Enable
RTC->CRL &= ~RTC_CRL_CNF; //Exit configuration mode
while((RTC->CRL & RTC_CRL_RTOFF) == 0); //Wait for RTOFF
sendstr(textconf);
}
Here is the whole program:
#include "stm32f10x.h"
#include <stdio.h>
uint8_t text[] = {"\nSTM32 USART test ä ö \n"};
uint8_t textlse[] = {"LSE ready\n"};
uint8_t textconf[] = {"Configuration complete\n"};
char str[32]; // buffer for text
uint8_t RxBuffer[1024];
int rxcount = 0;
// Private function prototypes
void sendstr(uint8_t * str);
void sendChar(uint8_t ch);
void sendTime(uint32_t ch);
void setupRTC(void);
void setupUSART(void);
u32 rtc_get_counter_val(void);
void setupRTC(void){
RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); //Enable the power and backup interface clocks by setting the PWREN and BKPEN bitsin the RCC_APB1ENR register
PWR->CR |= PWR_CR_DBP; //Enable access to the backup registers and the RTC.
RCC->BDCR |= RCC_BDCR_LSEON; //External Low Speed oscillator enable
while((RCC->BDCR & RCC_BDCR_LSERDY) == 0); //Wait until external oscillisator is stabilised
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE;
sendstr(textlse);
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE; //Select Source (LSE oscillator clock used as RTC clock )
RCC->BDCR &= ~((1 << 8) | (1 << 9)); //Unusable clock source, here to prevent warnings, turn off clock sources to RTC.
RCC->BDCR = RCC_BDCR_RTCEN; //RTC clock enable
RTC->CRL &= ~RTC_CRL_RSF; //Clear registers Synchronized Flag
while(!(RTC->CRL & RTC_CRL_RSF)); //Wait for the RSF bit in RTC_CRL to be set by hardware
while((RTC->CRL & RTC_CRL_RTOFF) == 0); //Wait for RTOFF It is not possible to write to the RTC_CR register while the peripheral is completing a previous write operation
RTC->CRL |= RTC_CRL_CNF; //Set the CNF bit to enter configuration mode
/* Set RTC COUNTER MSB word */
RTC->CNTH = (12*3600 + 40*60 + 00) >> 16; //Random time
/* Set RTC COUNTER LSB word */
RTC->CNTL = ((12*3600 + 40*60 + 00)& 0x0000FFFF);
RTC->CRH |= RTC_CRH_SECIE; //Second Interrupt Enable
RTC->CRL &= ~RTC_CRL_CNF; //Exit configuration mode
while((RTC->CRL & RTC_CRL_RTOFF) == 0); //Wait for RTOFF
sendstr(textconf);
}
void setupUSART(void){
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN;
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
USART1->BRR = (SystemCoreClock / 115200);
GPIOA->CRH &= 0xFFFFF00F; //Set RX(PA10) and TX(PA9) pins
GPIOA->CRH |= 0x000008A0; //In TTL communication, TX pin must be conficured as pushpull
NVIC_EnableIRQ(USART1_IRQn);
USART1->CR1 |= USART_CR1_RXNEIE; //Enable USART interrupt
}
int main(void)
{
vu32 dly;
uint32_t time;
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //Enable clock for PC pins
GPIOC->CRL &= 0x00FFFFFF; //Setup PC6 and PC6 leds
GPIOC->CRL |= 0x33000000;
setupUSART();
setupRTC();
sendstr(text);
while (1)
{
time = rtc_get_counter_val();
sprintf(str, "%10d\n", time);
sendstr(str);
for(dly = 0; dly < 1000000; dly++);
}
}
void sendChar(uint8_t ch){
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = ch;
}
void sendTime(uint32_t ch){
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = ch;
}
void sendstr(uint8_t * str){
while(*str != 0){
sendChar(*str);
str++;
}
}
void USART1_IRQHandler(void){
if(USART1->SR & 0x0020){ //content of the shift register is transferred to the RDR RXNE bit.
GPIOC->BSRR = (1 << 7);
RxBuffer[rxcount++] = (uint8_t)(USART1->DR & (uint8_t)USART_DR_DR);
USART1->SR = (uint16_t)~0x0020;
sendstr(RxBuffer);
}
}
void RTC_IRQHandler(void){
if(RTC->CRL & RTC_CRL_SECF){
GPIOC->BSRR = (1 << 7);
RTC->CRL &= ~RTC_CRL_SECF;
}
}
u32 rtc_get_counter_val(void)
{
return (RTC->CNTH << 16) | RTC->CNTL;
}
Mayby too late but the problem is that you do not set any clock source to the RTC.
The following lines need to be swapped, from:
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE;
RCC->BDCR &= ~((1 << 8) | (1 << 9));
to:
RCC->BDCR &= ~((1 << 8) | (1 << 9));
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE;
The way it was before you first set correctly the clock source, and then cleared again the bits, leaving the RTC without clocking.
Related
I am using an ATMega2560 with a resistance touch screen (uses the ADC with analogRead commands) – I also use other ADC pins with analogRead (NTC temp sensor). This all works fine.
I have recently added a function that requires me to get ADC readings at known intervals and decided that using the automatic sampling was best – I found the code to do this online and it works well for the function it is required for.
My issue is, after I do the continuous sampling, I cannot get the ADC analogRead values to return the same as they where before the continuous sample.
I have checked the datasheet and it says the initial value for the ADCSRA, ADCSRB & ADMUX = 0 – I have tried this and quite a few other things with no success.
I have attached some code that does the same as my program – i.e. analogRead returns a different value after the continuous sample.
byte samplesADC[100];
int samplesADCCount = 0;
bool ADCEnd = false;
void startADCAcquire(){
int dacChan = 14;
Serial.println("Start ADC Aquire: ");
cli();//diable interrupts
//set up continuous sampling of analog pin 0
//clear ADCSRA and ADCSRB registers
ADCSRA = 0;
ADCSRB = 0;
ADMUX |= dacChan&0x07;
if (dacChan >= 8)
ADCSRB |= _BV(MUX5);
else
ADCSRB &= ~_BV(MUX5);
ADMUX |= (1 << REFS0); //set reference voltage
ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only
ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500kHz
ADCSRA |= (1 << ADATE); //enabble auto trigger
ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete
ADCSRA |= (1 << ADEN); //enable ADC
ADCSRA |= (1 << ADSC); //start ADC measurements
sei();//enable interrupts
}
void stopADCAcquire(){
Serial.println("");
Serial.println("Stop ADC Acquire");
cli();//diable interrupts
//set up continuous sampling of analog pin 0
//clear ADCSRA and ADCSRB registers
ADCSRA = 0;
ADCSRB = 0;
ADMUX = 0;
// ADCSRB &= ~_BV(MUX5);
// ADMUX &= ~(1 << ADLAR);
// ADCSRA &= ~(1 << ADSC); // disable adc interrupt
sei();//enable interrupts
}
void setup(){
Serial.begin(9600);
Serial.println("");
Serial.println("START");
Serial.print("Pin A2 (1): ");
Serial.println(analogRead(A2));
startADCAcquire();
int i;
while(ADCEnd == false){
i++;
}
while ((UCSR0A & _BV (TXC0)) == 0)
{}
Serial.print("Pin A2 (2): ");
Serial.println(analogRead(A2));
Serial.println("END");
}
ISR(ADC_vect) {//when new ADC value ready
samplesADC[samplesADCCount] = ADCH;
Serial.print(samplesADC[samplesADCCount]);
Serial.print(", ");
samplesADCCount++;
if(samplesADCCount == 100){
stopADCAcquire();
ADCEnd = true;
}
}
void loop(){
}
Output:
START
Pin A2 (1): 0
Start ADC Aquire:
127, 127, 127...... (x100)
Stop ADC Acquire
Pin A2 (2): 510
END
Thanks #hcheung...
So I'm not sure if you pointed me to the interrupt page, with reference to the code issues around my interrupt handlers - I think I have sorted these by using volatile variables and removing excess code/print statements from the ISR handler. So thanks for the link - it was a helpful reminder.
However this did nothing to resolve my issue and the output remained the same! On the interrupt page I noticed some code where registers are copied to a buffer and then reassigned later. I decided to try this and copied the ADCSRA, ADCSRB & ADMUX registers on program load and reassigned them after the AD scan.
This also failed - Then as last ditch I copied the registers just before the call to start the AD scan (i.e afer analogRead had been called) and it worked. I am now able to use the analogRead command after my continuous read.
I attach updated code that works - i.e analogRead works after being in continuous mode.
volatile byte samplesADC[100];
volatile int samplesADCCount = 0;
volatile bool ADCEnd = false;
uint8_t ADCSRASave;
uint8_t ADCSRBSave;
uint8_t ADMUXSave;
void startADCAcquire(){
int dacChan = 14;
ADCSRASave = ADCSRA;
ADCSRBSave = ADCSRB;
ADMUXSave = ADMUX;
cli();//diable interrupts
//set up continuous sampling of analog pin 0
//clear ADCSRA and ADCSRB registers
ADCSRA = 0;
ADCSRB = 0;
ADMUX |= dacChan&0x07;
if (dacChan >= 8)
ADCSRB |= _BV(MUX5);
else
ADCSRB &= ~_BV(MUX5);
ADMUX |= (1 << REFS0); //set reference voltage
ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only
ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500kHz
ADCSRA |= (1 << ADATE); //enabble auto trigger
ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete
ADCSRA |= (1 << ADEN); //enable ADC
ADCSRA |= (1 << ADSC); //start ADC measurements
sei();//enable interrupts
}
void stopADCAcquire(){
cli();//diable interrupts
ADCSRA = ADCSRASave; //0;
ADCSRB = ADCSRBSave; //0;
ADMUX = ADMUXSave; //;
sei();//enable interrupts
}
void setup(){
Serial.begin(9600);
Serial.println("");
Serial.println("START");
Serial.print("Pin A2 (1): ");
Serial.println(analogRead(A14));
Serial.println("Start ADC Aquire: ");
while ((UCSR0A & _BV (TXC0)) == 0){}
startADCAcquire();
while(ADCEnd == false){ }
stopADCAcquire();
for(int x = 0; x < 100; x++){
Serial.print(samplesADC[x]);
Serial.print(", ");
}
Serial.println("");
Serial.println("Stop ADC Acquire");
Serial.print("Pin A2 (2): ");
Serial.println(analogRead(A14));
Serial.println("END");
}
ISR(ADC_vect) {//when new ADC value ready
samplesADC[samplesADCCount] = ADCH;
// Serial.print("p");
samplesADCCount++;
if(samplesADCCount == 100){
ADCEnd = true;
}
}
void loop(){
}
Output:
START
Pin A2 (1): 511
Start ADC Aquire:
127, 127, 127, 127 <<< x 100
Stop ADC Acquire
Pin A2 (2): 511 <<< value now same as first
END
I have a serial communication between STM32 and Linux computer.
STM transmits every 10ms 6 bytes of data "iiiiiC" (i = transmission_counter % 10, C = character 'C').
The receiver however does not have a specific iteration time and may read serial faster or slower than 10ms. Also, the read function should be non-blocking.
This means that sometimes received data:
RD = '111'
RD = '11C2'
RD = '222'
RD = '2C33'
I want usable_data = 22222C
and sometimes:
RD = '333C44444C'
RD = '55555C66666'
RD = 'C77777C8888'
I want usable_data = 77777C
Code is similar to following:
int main() {
int serial_port = open("/dev/ttyACM1", O_RDWR);
struct termios tty;
// Read in existing settings, and handle any error
if(tcgetattr(serial_port, &tty) != 0) {
printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
return 1;
}
tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
tty.c_cflag &= ~CSIZE; // Clear all bits that set the data size
tty.c_cflag |= CS8; // 8 bits per byte (most common)
tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)
tty.c_lflag &= ~ICANON;
tty.c_lflag &= ~ECHO; // Disable echo
tty.c_lflag &= ~ECHOE; // Disable erasure
tty.c_lflag &= ~ECHONL; // Disable new-line echo
tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes
tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
// tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX)
// tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX)
tty.c_cc[VTIME] = 0; // No blocking, return immediately with what is available
tty.c_cc[VMIN] = 0;
cfsetispeed(&tty, B115200);
cfsetospeed(&tty, B115200);
// Save tty settings, also checking for error
if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
return 1;
}
while (1){
char read_buf [100]; // Large serial buffer so even if the receiver is slow the most recent data will be in this array
memset(&read_buf, '\0', sizeof(read_buf));
int num_bytes = read(serial_port, &read_buf, sizeof(read_buf));
std::cout << num_bytes << " " << read_buf << std::endl;;
... unknown time ahead ...
}
close(serial_port);
return 0; // success
}
I tried some workarounds, but they don't solve all the problems or I'm otherwise not happy with them:
// For cases where receiver is slow and receives more than one complete message at once
char part [6];
uint16_t index = 0;
for (index; index < 6; index++){
if (read_buf[index] == 'C'){
while (read_buf[index] == 'C'){
index += 6;
}
index -= 6;
break;
}
}
memcpy(part, read_buf + index - 5, 6);
.
// For cases where received data does not fit into read_buffer, i.e. we are reading old data - flush it.
int num_bytes = read(serial_port, &read_buf, sizeof(read_buf));
while (num_bytes == sizeof(read_buf)){
num_bytes = read(serial_port, &read_buf, sizeof(read_buf));
}
.
// For cases where received data is out of phase (message does not end with a 'C'). Reads one character at a time until message ends with 'C'. Has many problems.
if (read_buf[sizeof(read_buf)-1] != 'C'){
read(serial_port, &read_buf, 1);
}
but since usable_data might be split into parts (part of usable_data in the current message, part of it in the previous one) it's difficult to merge the correct bytes together.
The best way to handle that specific challenge is to let read() take care of that for you by leveraging the fact that You don't have to point the second argument of read() to the start of the buffer. You can make it write the data from wherever it last stopped.
constexpr std::size_t msg_len = 6;
std::array<char, msg_len> read_buf;
int received = 0;
void poll_port() {
auto count = read(
serial_port,
read_buf.data() + received, // Append to whatever we already have
msg_len - received); // Only read data up to the end of the buffer.
if(count != -1) {
received += count;
if(received == msg_len) {
handle_message(read_buf);
received = 0;
}
}
else if(errno != EAGAIN) {
// we failed for some other reason than lack of data.
}
}
Combine this with configuring the port in non-buffered mode as per https://stackoverflow.com/a/5616108/4442671, to make read() non-blocking, and you'll have pretty much what you need.
Obviously, this is a simplified example that assumes all messages are of the same length and that no data corruption happens along the way, but it should set you on the general path.
How to ensure correct data is received, if serial receiver execution time varies
Write a parser that will parse the incoming data and accumulate them in a buffer and notify "upper processing stage" only when a full packet is received.
bytes of data "iiiiiC"
That's trivially trivial to write, a sample parser might look like the following:
struct myrecv {
std::array<char, 6> buf;
unsigned pos;
// pointer to a function that return EOF or valid character
std::function<int()> readc;
// pointer to callback function to call when full buffer is received
std::function<void(std::array<char, 6>&)> cb;
myrecv(std::function<int()> readc,
std::function<void(std::array<char, 6>&)> cb) :
readc(readc), cb(cb), pos(0) {}
int process() {
buf[pos] = readc();
if (buf[pos] == EOF) return ETIMEDOUT;
pos++;
if (pos != buf.size()) {
return 0;
}
pos = 0;
// check message integrity
if (buf.end() != 'C') {
return -EINVAL;
}
cb(buf);
return 1;
}
};
I am trying to use TIM6 on STM32F103C8T6 to generate time and blink an led but the timer doesnt see to be working, what other parameters do i need to initialize in order to be able to use the timer ? code below ?
#include "stm32f10x.h"
int main(void)
{
RCC->APB1ENR |= 0x00000010 ; // CLOCK SIGNAL TO BASIC TIMER 6 IS INITIALIZED
RCC->APB2ENR |= 0x00000004 ; //CLOCK SIGNAL TO GPIO PORT A IS INITIALIZED
GPIOA->CRL |= 0x33333333 ; // LOWER PINS OF GPIO PORT A ARE DEFINED AS PUSH AND PULL OUTPUT
TIM6->CR1 |= 0x0081 ; // COUNTER AND AUTO RELOAD BUFFER ENABLED
TIM6->PSC |= 0x1F40 ; // PRESCALER SET AS 8000
TIM6->ARR |= 0x05DC ; // AUTO RELOAD REGISTER SET AT 1000
while(1)
{
if ( TIM6->CNT == 1000 )
{
GPIOA->BSRR |= 0X0044 ; //SET PINS 2 AND 6 OF GPIOA TO HIGH
}
if ( TIM6->CNT == 0x05DC )
{
GPIOA->BRR |= 0X0044 ; //SET PINS 2 AND 6 OF GPIOA TO HIGH
}
}
}
STM32F103C8T6 has only TIM1 - TIM4, so trying to use TIM6 is doomed to fail. See "Table 4. Timer feature comparison" in the datasheet (page 17).
We are migrating from an older OS (OpenSuse 10.2) to Ubuntu 16.04, and one of our applications communicates via a serial port. Communication stopped working on Ubunutu, but with a small hack(?) it does start working. That hack is to send a tcsendbreak() right after the call to open, like so:
fd = open(pname, O_RDWR | O_NOCTTY); //pname becomes /dev/ttyS6
if (fd < 0)
{
printf("Couldnt open comms port \"%s\".\n", pname);
return SYSERR;
}
if (tcsendbreak(fd, 0) < 0)
{
printf("tcsendbreak error\n");
}
After doing this everything runs normally. I've tried doing a tcflush at various points (without the tcsendbreak), that didn't make a difference.
What are some reasons why the tcsendbreak would allow communication to be established? Any ideas of what to try without using the tcsendbreak? Trying to understand why its needed, and if there is an underlying issue that this break skips past.
We set the modes the following way:
int r = 0;
struct termios port_opt, *popt;
r |= tcgetattr(fd, &original_port_options);
port_opt = original_port_options;
popt = &port_opt;
cfmakeraw(&port_opt);
/* parity/framing errors come in as nulls. */
popt->c_iflag |= (IGNBRK);
popt->c_cflag |= (CLOCAL);
popt->c_cc[VMIN] = 0; /* ignored by line discipline. */
popt->c_cc[VTIME] = 1; /* ignored by line discipline. */
popt->c_cflag |= CREAD; //enable receiver
r |= cfsetispeed(popt, B19200);
popt->c_cflag &= ~(PARENB);/* turn off parity. */
popt->c_cflag = (popt->c_cflag & ~CSIZE) | CS8; /* 8 bits. */
popt->c_cflag &= ~CSTOPB; /* only 1 stop bit. */
r |= cfsetospeed(popt, B19200);
r |= tcsetattr(fd, TCSANOW, popt);
if (r != 0)
gos_panic("Cant set comms driver parameters");
Additionally, we also set a line discipline:
r = ioctl(fd, TIOCGETD, &old_line_discipline);
if (r != 0)
old_line_discipline = -1;
r = map_line_discipline("LINE_DISC", 27);
r = ioctl(fd, TIOCSETD, &r);
Note that communication works when sending the tcsendbreak before setting all these modes.
In a MAC OS X (10.10) program, I have a hard time setting up termios correctly for RS-485 serial communication (I use a starcom USB → RS-485 featuring the FTDI chip)
I need to set up the following:
1 Start bit (0 bit)
8 Databits
1 Odd parity bit
1 Stop bit (1 bit)
19200 baud
Communication is binary, so there is no stop character.
Currently, I have found how to set most of the settings (see code below), but I didn't found where to tell termios I want a start bit.
#property(readwrite) int fileDescriptor;
_fileDescriptor = open(bsdPath, O_RDWR | O_NOCTTY | O_NONBLOCK);
ioctl(_fileDescriptor, TIOCEXCL)
fcntl(_fileDescriptor, F_SETFL, 0)
tcgetattr(_fileDescriptor, &gOriginalTTYAttrs)
struct termios options = gOriginalTTYAttrs;
cfmakeraw(&options);
struct termios* rawOptions = &options;
// Timeout 100 ms
rawOptions->c_cc[VTIME] = 1;
rawOptions->c_cc[VMIN] = 0;
// 8 bits
rawOptions->c_cflag |= CS8;
// Parity ODD
rawOptions->c_cflag |= PARENB;
rawOptions->c_cflag |= PARODD;
// Stop bit (I hope it means one stop bit)
rawOptions->c_cflag = rawOptions->c_cflag & ~CSTOPB;
// Flow control none
rawOptions->c_cflag = rawOptions->c_cflag & ~CRTSCTS;
rawOptions->c_cflag = rawOptions->c_cflag & ~(CDTR_IFLOW | CDSR_OFLOW);
rawOptions->c_cflag = rawOptions->c_cflag & ~CCAR_OFLOW;
// Turn on hangup on close (NO IDEA WHAT IT DOES)
rawOptions->c_cflag |= HUPCL;
// Set local mode on (NO IDEA WHAT IT DOES)
rawOptions->c_cflag |= CLOCAL;
// Enable receiver (USEFUL, I GUESS)
rawOptions->c_cflag |= CREAD;
// Turn off canonical mode and signals (NO IDEA WHAT IT DOES)
rawOptions->c_lflag &= ~(ICANON /*| ECHO*/ | ISIG);
// Raw (binary output)
rawOptions->c_oflag &= ~OPOST;
// 19200 baud
cfsetspeed(rawOptions, 19200);
// Applying settings
tcsetattr(_fileDescriptor, TCSANOW, rawOptions);