I am working with UART of lPC1788,in that I did the following settings for PCLK as 12MHZ and baud rate as 115200 but while I am simulating this code the baud rate is not assigned as 115200 or approx.
uint32_t uart0_init()
{
LPC_SC->PCONP |=(1<<3); //Enabling power/clock for UART0
LPC_IOCON->P0_2 = 1; //Selecting fn. 001 for P0.2(U0_TXD)
LPC_IOCON->P0_3 = 1; //Selecting fn. 001 for P0.3(U0_RXD)
LPC_UART0->LCR =(0x83); //Selecting DLAB=1,1 stop bit,Parity bit and 8-bit character length
LPC_UART0->DLL = 0x04; //For PCLK=12MHZ and baud rate as 115200,DLL=4(in dec.)
LPC_UART0->DLM = 0x00; //For PCLK=12MHZ and baud rate as 115200,DLM=0(in dec.)
LPC_UART0->FDR =(0x85); //DIVADDVAL=1(3:0) and MULVAL=2(7:4) in FDR calculated from the FRest value
LPC_UART0->LCR =(0x03); //Disabling DLAB=0
LPC_UART0->FCR |=(7<<0); //Enable FIFOEN,TXFIFORES and RXFIFORES in FCR(0,1,2)
LPC_UART0->FCR |=(0<<0); //Disable FIFOEN,TXFIFORES and RXFIFORES in FCR(0,1,2)
//NVIC_EnableIRQ(UART0_IRQn);
//LPC_UART0->IER = IER_RBRIE | IER_THREIE | IER_RXIE;
return 1;
}
For me its coming near 384615,its totally different.Is there any calculations to be done to obtain exact of 115200 baud.
Please do clear for me..
Dont use uart init to change system control settings. You will overwrite them elsewhere if you are not careful. Create sysInit function and set it there. Set divider to 10 (0x0a).
LPC_SC->PCLKSEL = 0x0A;
This will divide MCLK with 10 and you will get 12Mhz clock for peripherals. After that you need to set FDR and DLL settings to achieve ~115200 baud.
Related
I am beginner in embedded systems. I am trying to write data on UART2 of STM32F103C8 (i. e., the Blue Pill board) and want to see the data in one of the ports of my computer using an FTDI adapter, which is connected to UART2 of the STM32F103C8 board. But on my console I receive some random square block instead of the character which I want to transmit.
Here is my code written in Keil IDE.
#include "stm32f10x.h" // Device header
void usart2_init(void);
void USART_write(int data);
void delayMs(int delay);
int main(void)
{
usart2_init();
while(1)
{
USART_write('A');
delayMs(5000);
}
}
void usart2_init(void)
{
// Enable clock source for USART2
RCC->APB1ENR |= 0x20000; // 0b 0000 0000 0000 0010 0000 0000 0000 0000
RCC->APB2ENR |= 0x4;
GPIOA->CRL |= 0x900; // Set PA2 as TX pin (AF)
USART2->BRR = 0x341; // Setting Baudrate to 9600 #8 MHz.
USART2->CR1 |= 0x00008; // Enable TX only
USART2->CR1 |= 0x02000; // Enable USART module by setting bit 13 to 1 i
USART->CR1 register
}
void USART_write(int data)
{
// We need to wait until Tx buffer is empty for sending data.
while(!(USART2->SR & 0x0080)); // 0x0080
USART2->DR = (data & 0xFF);
}
void delayMs(int delay)
{
int i;
for( ; delay>0 ; delay--)
{
for(i=0; i<3195; i++)
{
}
}
}
Below I attached the screenshot while debugging.
Click here to see screenshot.
You can see the unwanted square block instead of character instead of the characters I want to transmit. In the image you can also see the UART registers and their values.
I am using ST-LINK2 to upload the firmware.
Am I missing some information or doing some mistake while dealing with FTDI and Tera Term? This is my Tera Term configuration:
Baud rate = 9600
Data = 8 bit
Parity = none
Stop bit = 1
Control flow = none
How can I fix this?
When working with those devices you should have a careful reading of datasheets/reference manuals and possibly applicable AN (application notes) widely available from the producer site.
In the specific case, the STM32F10x family works generally with a system clock of 72 MHz generated by an internal PLL oscillator which use the external crystal, having frequency of 8 MHz on Blue Pill, as the reference for the PLL (phase-locked loop) circuitry that controls it. The 8 MHz crystal oscillator is called HSE, which stands for High Speed External oscillator.
I said 'generally' because the user can select different system clock frequencies by programming the specific prescalers and internal clock circuitry, which can become very complicated at first sight (and even at second…).
Now assuming the standard configuration the peripheral interfaces, where the system clock is selected at 72 MHz and the AHB prescaler to 1, the two peripheral clocks (PCLCKx) are set to 36 MHz (PCLCK1: prescaler = 2) and 72 MHz (PCLCK2), respectively.
On STM32F10x chips, only USART1 is clocked from PCLCK2, and all other are clocked from PCKLK1 (maximum 36 MHz).
So your device presumably is clocked at 36 MHz. To have a rate of 9600 baud, we need an overall divisor of 36 MHz / (9600 * 16) = 234.375.
The baud rate generator can handle fractional divisions by considering the integer and fractional parts separately. We get:
DIV_Fraction = 16 * 0.375 = 6 = 0x06
DIV_Mantissa = 234 = 0xEA
USART_BRR = (DIV_Mantissa << 4) | DIV_Fraction = 0xEA6
The notation 0dxx is taken from ST documentation and stands for decimal representation.
Conclusion
To operate on those devices, read carefully the documentation before starting to program, use helping libraries if possible. Personally I prefer libopencm3 over standard HAL libraries, which simplifies the use.
this will work man, i tested it
void init_Usart(void)
{
// Enable clock source for USART2
RCC->APB1ENR |= 0x20000; // 0b 0000 0000 0000 0010 0000 0000 0000 0000
RCC->APB2ENR |= 0x4;
GPIOA->CRL |= 0x900; // Set PA2 as TX pin (AF)
USART2->BRR = 0xEA6; // Setting Baudrate to 9600 #8 MHz.
USART2->CR1 |= 0x00008; // Enable TX only
USART2->CR1 |= 0x02000; // Enable USART module
}
void USART_write(int data)
{
// We need to wait until Tx buffer is empty for sending data.
while(!(USART2->SR & 0x0080)); // 0x0080
USART2->DR = (data & 0xFF);
}
I'm trying to write my own driver for USART_TX on an STM32L476RG Nucleo Board.
Here the datasheet and the reference manual.
I'm using Keil uVision 5 and I set in the Manage dialog:
CMSIS > Core
Device > Startup
Xtal=16MHz
I want to create a single character transmitter. According to the manual instructions in Sec. 40 p 1332 I wrote this code:
// APB1 connects USART2
// The USART2 EN bit on APB1ENR1 is the 17th
// See alternate functions pins and label for USART2_TX! PA2 is the pin and AF7 (AFRL register) is the function to be set
#include "stm32l4xx.h" // Device header
#define MASK(x) ((uint32_t) (1<<(x)));
void USART2_Init(void);
void USART2_Wr(int ch);
void delayMs(int delay);
int main(void){
USART2_Init();
while(1){
USART2_Wr('A');
delayMs(100);
}
}
void USART2_Init(void){
RCC->APB1ENR1 |= MASK(17); // Enable USART2 on APB1
// we know that the pin that permits the USART2_TX is the PA2, so...
RCC->AHB2ENR |= MASK(0); // enable GPIOA
// Now, in GPIOA 2 put the AF7, which can be set by placing AF7=0111 in AFSEL2 (pin2 selected)
// AFR[0] refers to GPIOA_AFRL register
// Remember: each pin asks for 4 bits to define the alternate functions. see pg. 87
// of the datasheet
GPIOA->AFR[0] |= 0x700;
GPIOA->MODER &= ~MASK(4);// now ... we set the PA2 directly with moder as alternate function "10"
// USART Features -----------
//USART2->CR1 |=MASK(15); //OVER8=1
USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?
//USART2->BRR = 0x1A1; //This one works!!!
USART2->CR1 |=MASK(0); //UE
USART2->CR1 |=MASK(3); //TE
}
void USART2_Wr(int ch){
//wait when TX buffer is empty
while(!(USART2->ISR & 0x80)) {} //when data is transfered in the register the ISR goes 0x80.
//then we lock the procedure in a while loop until it happens
USART2->TDR =(ch & 0xFF);
}
void delayMs(int delay){
int i;
for (; delay>0; delay--){
for (i=0; i<3195; i++);
}
}
Now, the problem:
The system works, but not properly. I mean: if I use RealTerm at 9600 baud-rate, as configured by 0x683 in USART_BRR reg, it shows me wrong char but if I set 2400 as baud rate on real term it works!
To extract the 0x683 in USART_BRR reg i referred to Sec. 40.5.4 USART baud rate generation and it says that if OVER8=0 the USARTDIV=BRR. In my case, USARTDIV=16MHz/9600=1667d=683h.
I think that the problem lies in this code row:
USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?
because if I replace it as
USART2->BRR = 0x1A1; //USARTDIV=16Mhz/9600?
THe system works at 9600 baud rate.
What's wrong in my code or in the USARTDIV computation understanding?
Thank you in advance for your support.
Sincerely,
GM
The default clock source for the USART is PCLK1 (figure 15) PCLK1 is SYSCLK / AHB_PRESC / AHB1_PRESC. If 0x1A1 results in a baud rate of 9600, that suggests PCLK1 = 4MHz.
4MHz happens to be the default frequency of your processor (and PCLK1) at start-up when running from the internal MSI RC oscillator. So the most likely explanation is that you have not configured the clock tree, and are not running from the 16MHz HSE as you believe.
Either configure your clock tree to use the 16MHz source, or perform your calculations on the MSI frequency. The MSI precision is just about good enough over normal temperature range to maintain a sufficiently accurate baud rate, but it is not ideal.
I am new to STM8, and trying to use a STM8S103F3, using IAR Embedded Workbench.
Using C, I like to use the registers directly.
I need serial on 14400 baud, 8N2, and getting the UART transmit is easy, as there are numerous good tutorials and examples on the net.
Then the need is to have the UART receive on interrupt, nothing else will do.
That is the problem.
According to iostm8s103f3.h (IAR) there are 5 interrupts on 0x14 vector
UART1_R_IDLE, UART1_R_LBDF, UART1_R_OR, UART1_R_PE, UART1_R_RXNE
According to Silverlight Developer: Registers on the STM8,
Vector 19 (0x13) = UART_RX
According to ST Microelectronics STM8S.h
#define UART1_BaseAddress 0x5230
#define UART1_SR_RXNE ((u8)0x20) /*!< Read Data Register Not Empty mask */
#if defined(STM8S208) ||defined(STM8S207) ||defined(STM8S103) ||defined(STM8S903)
#define UART1 ((UART1_TypeDef *) UART1_BaseAddress)
#endif /* (STM8S208) ||(STM8S207) || (STM8S103) || (STM8S903) */
According to STM8S Reference manual RM0016
The RXNE flag (Rx buffer not empty) is set on the last sampling clock edge,
when the data is transferred from the shift register to the Rx buffer.
It indicates that a data is ready to be read from the SPI_DR register.
Rx buffer not empty (RXNE)
When set, this flag indicates that there is a valid received data in the Rx buffer.
This flag is reset when SPI_DR is read.
Then I wrote:
#pragma vector = UART1_R_RXNE_vector //as iostm8s103f3 is used, that means 0x14
__interrupt void UART1_IRQHandler(void)
{ unsigned character recd;
recd = UART1_SR;
if(1 == UART1_SR_RXNE) recd = UART1_DR;
etc.
No good, I continually get interrupts, UART1_SR_RXNE is set, but UART1_DR
is empty, and no UART receive has happened. I have disabled all other interrupts
I can see that can vector to this, and still no good.
The SPI also sets this flag, presumably the the UART and SPI cannot be used
together.
I sorely need to get this serial receive interrupt going. Please help.
Thank you
The problem was one bit incorrectly set in the UART1 setup.
The complete setup for the UART1 in the STM8S103F3 is now(IAR):
void InitialiseUART()
{
unsigned char tmp = UART1_SR;
tmp = UART1_DR;
// Reset the UART registers to the reset values.
UART1_CR1 = 0;
UART1_CR2 = 0;
UART1_CR4 = 0;
UART1_CR3 = 0;
UART1_CR5 = 0;
UART1_GTR = 0;
UART1_PSCR = 0;
// Set up the port to 14400,n,8,2.
UART1_CR1_M = 0; // 8 Data bits.
UART1_CR1_PCEN = 0; // Disable parity.
UART1_CR3 = 0x20; // 2 stop bits
UART1_BRR2 = 0x07; // Set the baud rate registers to 14400
UART1_BRR1 = 0x45; // based upon a 16 MHz system clock.
// Disable the transmitter and receiver.
UART1_CR2_TEN = 0; // Disable transmit.
UART1_CR2_REN = 0; // Disable receive.
// Set the clock polarity, clock phase and last bit clock pulse.
UART1_CR3_CPOL = 0;
UART1_CR3_CPHA = 0;
UART1_CR3_LBCL = 0;
// Set the Receive Interrupt RM0016 p358,362
UART1_CR2_TIEN = 0; // Transmitter interrupt enable
UART1_CR2_TCIEN = 0; // Transmission complete interrupt enable
UART1_CR2_RIEN = 1; // Receiver interrupt enable
UART1_CR2_ILIEN = 0; // IDLE Line interrupt enable
// Turn on the UART transmit, receive and the UART clock.
UART1_CR2_TEN = 1;
UART1_CR2_REN = 1;
UART1_CR1_PIEN = 0;
UART1_CR4_LBDIEN = 0;
}
//-----------------------------
#pragma vector = UART1_R_RXNE_vector
__interrupt void UART1_IRQHandler(void)
{
byte recd;
recd = UART1_DR;
//send the byte to circular buffer;
}
You forget to add global interrupt flag
asm("rim") ; //Enable global interrupt
It happens at non isolated connections whenever you connect your board's ground with other source's ground (USB<->TTL converter connected to PC etc.), In this case microcontroller is getting noise due to high value SMPS's Y capacitor etc.
Simply connect your RX and TX line's via 1K resistor and put 1nF (can be deceased for high speed) capacitors on these lines and to ground (micro controller side) to suppress noises.
I am having trouble setting up high speed PWM on my ATtiny85. I need to use the PCK, at a speed of 400 kHz. I believe that I have followed the data sheet correctly, but for some reason, the timer interrupt flags are not working.
If I program the device, the output of the corresponding pin is a constant 5 V.
If I comment out the PCK setup and use the system clock instead, the flags are correctly set and PWM works fine. The code is posted. Why aren't the flags setting and the PWM isn't working?
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
PORTB = 0; //Reset values on port B
// After setting up the timer counter,
// set the direction of the ports to output
DDRB |= (1<<PB1) | (1<<PB0); // Set the direction of PB1 to an output
// PLLCSR - PLL control and status register:
// PLL is a clock multiplier - multiplies system 8 MHz by 8 to 64 MHz
// PLL is enabled when:PLLE bit is enabled,
// CKSEL fuse is programmed to 0001. This clock is
// switched off in sleep modes!
PLLCSR |= (1<<PLLE); // PLL enable
// Wait until the PLOCK bit is enabled
// before allowing the PCK to be enabled
//WaitForPLOCK();
//unsigned int i = 0;
while ((PLLCSR & (1<<PLOCK)) == 0x00)
{
// Do nothing until plock bit is set
}
PLLCSR |= (1<<PCKE); // Enable asynchronous mode, sets PWM clock source
TCCR1 =
(1<<CTC1) | // Enable PWM
(1<<PWM1A) | // Set source to pck
(1<<(CS10)) | // Clear the pin when match with ocr1x
(1<<COM1A1);
GTCCR = (1<<PWM1B) | (1<<COM1B1);
// Set PWM TOP value - counter will count and reset
// after reaching this value
// OCR1C
// 400 kHz 159
// 450 kHz 141
// 500 kHz 127
OCR1C = 159;
// Enable Timer1 OVF interrupt
TIMSK = (1<<OCIE1A) | (1<<TOIE1);
sei();
// This should set the duty cycle to about 75%
OCR1A = 120;
The solution involved the CKDIV8 fuse. To program this fuse correctly however, HVSP "High Voltage Serial Programming" was required. After removing this fuse so that the device operated at 8 MHz, the PWM gave a 400 kHz output. I hope other people find this useful!
The errata (section 27 of the datasheet) states 'PLL will not lock under 6 MHz'. The only workaround listed is to set the clock to 6 MHz or higher.
The following code won't set any of the pins high on my PIC18F14K50, yet it couldn't be simpler!
#include <pic18.h>
#include <htc.h>
void main(void)
{
// Set ALL pins to output:
TRISA = 0;
TRISB = 0;
TRISC = 0;
// Set ALL pins to high:
LATA = 0b11111111;
LATB = 0b11111111;
LATC = 0b11111111;
// Leave pins high and wait forever:
while (1);
}
I'm using MPLAB v8.43 and the Hi-Tech ANSI C Compiler.
A logic probe shows none of the pins high except the VUSB and the MCLR.
Any ideas?
At least some of the pins may be configured as Analog Inputs.
From the Datasheet for this device
The operation of pin RA4 as analog is selected by setting the ANS3
bit in the ANSEL register which is the default set-ting after a
Power-on Reset.
If you do not set the ANSEL register the pin cannot be used as output as it is configured as an analog input.
This applies to all the pins that can be A/D inputs, which does not cover all the pins you have.
Then again I do not see any configuration bit setup in your code. That device e.g. has 2 different instruction sets and you have to at the very least specify which instruction set you are using in the configuration bits.
You may try adding this to the top of your code just after the includes :
// Configuration BITS setup
__CONFIG(1, FOSC_INTIO2 & XINST_OFF);
__CONFIG(2, WDTEN_OFF & PWRTEN_ON);
__CONFIG(3, MCLRE_OFF);
I suppose that you didn't configure the MCPU oscillator, try to define:
; Oscillator:
config FOSC = INTIO2 ;Internal RC oscillator
;
; PLL x4 Enable bit:
config PLLCFG = OFF
and
;Define oscillator frequency
;{
movlw b'01100000'
movwf OSCCON
movlw b'01000000'
movwf OSCTUNE
;};
This directives are for MPLAB asm and not for Hi-Tech, but file registers should have the same names.