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
Related
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 using MSO430F2418 for my project. I am sending Hello world message to Bluetooth module via UART pins. Also I need to set pin P2.3 to high to reset the Bluetooth. Unfortunately Im unable to set that perticuler pin to high. When I check the voltage at Reset pin of Bluetooth it is low.
You can see below two lines in my code. I have used these statements to set the P2.3.
P2DIR|=0x08;
P2OUT|=0x08;
I have attached an image. There you can see the hardware. enter image description here
#include <stdio.h>
#include <msp430.h>
const char string[] = { "Hello World\r\n" };
unsigned int i;
int main(void){
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
if (CALBC1_1MHZ==0xFF) // If calibration constant erased
{
while(1); // do not load, trap CPU!!
}
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_1MHZ; // Set DCO
DCOCTL = CALDCO_1MHZ;
P2DIR|=0x08;
P2OUT|=0x08;
P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= UCSSEL_3; // SMCLK
UCA0BR0 = 8; // 1MHz 115200
UCA0BR1 = 0; // 1MHz 115200
UCA0MCTL = UCBRS2 + UCBRS1; // Modulation UCBRSx = 5
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
// IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt
IE2 |= UCA0TXIE;
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled
}
#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{
UCA0TXBUF = string[i++]; // TX next character
if (i == sizeof string - 1){ // TX over?
IE2 &= ~UCA0TXIE; // Disable USCI_A0 TX interrupt
_delay_cycles(1000000);
i = 0;
IE2 |= UCA0TXIE; // Enable USCI_A0 TX interrupt
}
}
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).
I bought board like this now i want to connect temperature sensor to this board.
How to read temperature from sensor in c or c++?
I tried to write some code but it won't work. I connect DS18B20 data cabel directly to TXD and RXD pins.
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <cstring>
#include <inttypes.h>
#include <errno.h>
int
set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
std::cout<<"error "<<errno<<" from tcgetattr";
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // ignore break signal
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
std::cout<<"error "<<errno<<" from tcsetattr";
return -1;
}
return 0;
}
void
set_blocking (int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
std::cout<<"error "<<errno<<" from tggetattr";
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
std::cout<<"error "<<errno<<" setting term attributes";
}
int main()
{
char *portname = "/dev/ttyUSB0";
int tty_fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (tty_fd < 0)
{
std::cout<<"error "<<errno<<" opening "<<portname<<": "<< strerror (errno);
return -1;
}
set_interface_attribs (tty_fd, B9600, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (tty_fd, true);
unsigned char c = 0xCC;
if(!write(tty_fd, &c, sizeof(c)))
std::cout<<"Write error";
sleep(2);
unsigned char buffer[8];
int size;
if((size = read(tty_fd, &buffer, 8)) < 0)
std::cout<<"Error";
else
std::cout<<"CC("<<size<<")='"<<buffer<<"'";
std::cout<<"\n";
c = 0x44;
if(!write(tty_fd, &c, sizeof(c)))
std::cout<<"Write error2";
c = 0xBE;
if(!write(tty_fd, &c, sizeof(c)))
std::cout<<"Write error2";
sleep(2);
if((size = read(tty_fd, &buffer, 8)) < 0)
std::cout<<"Error";
else
std::cout<<"BE("<<size<<")='"<<buffer<<"'";
std::cout<<"\n######################\n";
close(tty_fd);
}
I got:
CC(1)='Č#'
BE(2)='#ž#'
######################
CC(1)='Č#'
BE(2)='#ž#'
######################
CC(1)='Č#'
BE(2)='#ž#'
######################
Can you help me?
You can't do this with any software. The DS18B20 is electrically incompatible with the board you have. The sensor uses a 1-wire, open-collector communication scheme that is completely different from the serial protocol normally used with this board. With great difficulty you might be able to do some bit-banging of the RTS/CTS signals but you need circuitry to combine them into a bidirectional open-collector signal.
You can hack the UART to communicate with 1 wire protocol.
Connect Rx to Tx and add 4.7 pull-up resistor
See the application note from maxim:
http://www.maximintegrated.com/en/app-notes/index.mvp/id/214
As pointed out by user3804701, it's indeed possible to communicate with a 1-Wire device using a UART interface, and the application note at https://www.maximintegrated.com/en/app-notes/index.mvp/id/214 contains all the information needed to make it work.
But the OP's code needs several fixes:
Each transaction with DS18B20 is made of 3 steps: initialization (also called reset), ROM command and function command, optionally followed by a data exchange
The initialization or reset step is performed by configuring the UART with 9600 bps baud rate, transmitting 0x0F, and receiving a dummy byte; then, the baud rate must be set to 115200 bps to perform the next steps
Following the reset step, data is sent to DS18B20 by writing to the UART a 0xFF byte for each data bit set to 1, and a 0x00 byte for each bit set to 0, starting from the least significant bit; for example, to send 0xAB (i.e. 10101011), one would write to the UART the sequence (FF FF 00 FF 00 FF 00 FF); for each byte written to the UART, there is a "return byte" that needs to be read from the UART and discarded
Data is received from DS18B20 by sending the 0xFF byte following the rules in the previous bullet point, but instead of discarding the "return bytes" reading from the UART a byte for each data bit, starting from the least significant bit: a 0xFF value means that the bit value is 1, otherwise the bit value is 0; for example, the sequence (00 FF FF 00 FF 00 00 FF) read from the UART means that DS18B20 sent 0x96 (i.e. 10010110)
If there is just one DS18B20 connected to the 1-Wire bus, all transactions can use "skip ROM" (byte value 0xCC) as ROM command
The first transaction to be performed is the one that triggers a temperature conversion from DS18B20, with function command 0x44
After waiting for the conversion to complete (which can take up to 750 ms), the host can perform a second transaction to read the DS18B20 scratchpad memory (function command 0xBE); the scratchpad memory is 9 bytes long and contains among other things the temperature value
So in summary the steps needed to get a temperature sample from DS18B20 are: reset, write 0xCC, write 0x44, wait for conversion, reset, write 0xCC, write 0xBE, read 9 bytes.
Example code that implements this stuff is available at https://github.com/dword1511/onewire-over-uart.
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.