I am a very beginner of QEMU and mcu programming, recently practicing uart control on QEMU.
What I’m trying to do is virtually connect QEMU with host PC through USART2.
I have learned that option -serial is probably able to do so and tried adding
-serial mon:stdio => nothing happened
-serial stdio => error, but nothing shown in console.
Processor: STM32F407VG
Board: STM32F4-Discovery
IDE: Eclipse IDE
Host device os: macOS Catalina 10.15.7
Following are my codes and run configuration
#include "stm32f4xx.h"
void UART2_Init(void);
void UART2_Write(int ch);
void delayMs(int delay);
int main(void){
UART2_Init();
while(1){
UART2_Write('H');
delayMs(500);
UART2_Write('i');
delayMs(500);
}
}
void UART2_Init(void){
RCC -> APB1ENR |= 0x20000; // Enable usart2 clock
RCC -> AHB1ENR |= 0x8; // Enable PD5 clock
GPIOD -> AFR[0] = 0x700000; // access PD5 AF7
GPIOD -> MODER |= 0x800;
USART2 -> BRR = 0x0683; // Set buad rate to 9600
USART2 -> CR1 = 0x8; // Tx enable
USART2 -> CR1 = 0x2000; // USART enable
}
void UART2_Write(int ch){
// wait until Tx buffer is empty
while(!(USART2 -> SR & 0x80)){
USART2 -> DR = (ch & 0xff);
}
}
enter image description here
Related
I'm trying to make a custom library for nRF24l01 for a stm32f103 target device, and I am writing code for a primary TX device.
And here I'm trying to read the register contents of nRF by sending the R_REGISTER command along with the address I am looking for, but I'm not able to figure out how to read the data after the R_REGISTER command is transmitted.
And i'm using the standard stm32f10x.h header file which comes along with startup files on Kiel uVision5.
Here are the configurations,
clock setup
RCC->CR |= RCC_CR_HSION; //HSI on
while( !(RCC_CR_HSIRDY & (RCC->CR)) ); //wait till its ready
//clocks for peripherals
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //enable clock forport A
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; //enable clock for alternate functions
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; //enable clock for SPI1
GPIO setup
these are my custom-defined functions, they just work fine
//GPIO pin setup as alternate function
pin_mode(IOPA, GPIOA, 7, op_50MHz, op_afpp); //MOSI pin as GPIO alternate_pin can run upto 50MHz
pin_mode(IOPA, GPIOA, 6, ip, ip_pupd); //MISO pin as GPIO alternate_pin can run upto 50MHz
pin_mode(IOPA, GPIOA, 5, op_50MHz, op_afpp); //SCK pin as GPIO alternate_pin can run upto 50MHz
pin_mode(IOPA, GPIOA, 4, op_50MHz, op_gppp); //CS pin as GPIO general_puspose_pin can run upto 50MHz
SPI setup
SPI1->CR1 |= SPI_CR1_MSTR; //master mode
SPI1->CR1 |= SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_BR_2; //at 571Kbps, max 31Mbps
SPI1->CR1 |= SPI_CR1_SSI; //Software slave management enabled
SPI1->CR2 |= SPI_CR2_SSOE; //SS o/p enable
SPI1->CR1 |= SPI_CR1_SPE; //turn on the SPI
Im stuck here
uint8_t SPI_read_uint8_t(uint8_t addr){
uint8_t reg_val;
//sending the read command first along with address where we are reading from
delay_us(50);
digital_writepin(GPIOA, 4, LOW);
SPI1->DR = (R_REGISTER | addr); //sending the R_REGISTER command along with address
while( (SPI1->SR) & (SPI_SR_BSY) );
//please help here, how do I read the Register data from MISO pin
uint8_t spi_read_write(uint8_t data)
{
while(SPI1 -> SR & SPI_SR_RXNE) (void)*(volatile uint8_t *)&SPI1 -> DR; //clean the FIFO
*(volatile uint8_t *)&SPI1 -> DR = data;
while(!(SPI1 -> SR & SPI_SR_RXNE));
return *(volatile uint8_t *)&SPI1 -> DR;
}
uint8_t youroperation(uint8_t command, uint16_t *data)
{
uint8_t status;
setCSLine();
status = spi_read_write(command);
*data = spi_read_write(0);
*data |= ((uint16_t)spi_read_write(0)) << 8;
clearCSLine();
return status
}
youroperation will return Sn status register
command parameter means Cn command bits
data will contain the Dx data bits
To read data from SPI slave you need to send dummy bytes because master provides the clock for the slave.
I have a STM32 NUCLEO-64 F103RB and I am using Keil uVision 5. I was just testing the device with CubeMX software and was able to blink or turn on the green LED in my device. I then decided to do the same by changing the values in the registers on the board in C code directly. This is an schematic of the device:
Where I have highlited the GPIO A and the Bus that connects to the referred port. According to my understanding, two things should be done before actually turning the LED on:
1 - Activating the clock for the APB2 bus
2 - Setting the GPIOA Port 5 (which corresponds to the LED) to output mode.
I have done these two steps. However, the LED still won't turn on. I've tried looking at the documentation and found that the PA5 could be used as SPI, and I tried to change the register AFIO_MAPR (Page 184 of the reference manual) but that also didn't work. I tried looking at the clock activation for AHB2, but I didn't quite understand how it would work.
My C code is:
#include "stm32f10x.h" // Device header
int main() {
// Initialise clock of APB2 Bus
RCC->APB2ENR = (RCC->APB2ENR & 0x0) | RCC_APB2ENR_IOPAEN;
// Put the GPIOA in Output mode
GPIOA->CRL = (GPIOA->CRL & 0x44444444) | GPIO_CRL_MODE5_1;
// Changinging the ODR Register (Lighting the LED)
while(1) {
GPIOA->ODR = (GPIOA->ODR & 0x0) | GPIO_ODR_ODR5;
}
}
Nucleo64 F103RB Reference Manual
Nucleo64 F103RB User Manual
What step?
Enable GPIOA clock.
Configure pin to be push-pull output.
Toggle the pin.
For general GPIO do not set any AFIOs.
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
__DSB();
GPIOA -> CRL &= ~GPIO_CRL_CNF5_Msk;
GPIOA -> CRL |= GPIO_CRL_MODE5_Msk;
while(1)
{
GPIOA -> ODR ^= GPIO_ODR_ODR5;
for(volatile unsigned x = 0; x < 500000; x++);
}
you need also to check the solder bridges on the board:
I tried to implement a classic blink example on an STM32L476RG Nucleo board.
According to the STM32L4x datasheet: the LD2 is connected to the GPIOA PORT 5 (PA5).
The PA5 uses the AHB2 bus.
Note: I used Keil uVision 5; I created a New uVision Project with STM32L476RGTx target.
In the "Manage Run-Time Environment" dialog box I selected:
CMSIS >> Core (flag)
Device >> Startup (flag)
Here the code:
#include "stm32l4xx.h" // Device header
//#include <stdint.h>
//#define MASK(x) ((uint32_t) (1<<(x))) // bitmasking
void delayMs(int delay);
int main(void){
// RCC->AHB2RSTR |=1;
// RCC->AHB2RSTR &=~1;
// RCC->AHB2ENR |= MASK(0); //bitwise OR. Enable GPIOA clock
RCC->AHB2ENR |= 1;
//GPIOA->MODER |= MASK(10);
GPIOA->MODER |= 0x400;
while(1){
//GPIOA->ODR |= MASK(4);
GPIOA->ODR |= 0x20;
delayMs(500);
//GPIOA->ODR &= ~MASK(4);
GPIOA->ODR &= ~0x20;
delayMs(500);
}
}
void delayMs(int delay){
int i;
for(;delay>0; delay --){
for (i=0; i<3195;i++);
}
}
The Build output returns:
Build started: Project: blinknew
*** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
Build target 'Target 1'
compiling main.c...
linking...
Program Size: Code=520 RO-data=408 RW-data=0 ZI-data=1632
".\Objects\blinknew.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed: 00:00:09
and when I download it, Keil uV 5 returns:
Load "C:\\Users\\gmezz\\OneDrive\\Documenti\\Bare_Metal\\Blinknew\\Objects\\blinknew.axf"
Erase Done.
Programming Done.
Verify OK.
Flash Load finished at 22:37:52
The LED should blink with a period of 1 s, but in reality, nothing happens.
Honestly, I don't understand what is going wrong.
Someone can help me?
GM
I may be wrong, but according to the reference manual (RM0351) section 6.2.19, you should wait 2 clock cycles after enabling the peripheral clock, before accessing its registers. Try introducing a short delay after RCC->AHB2ENR |= 1; line. In your case, I think MODER register is not getting the correct value.
I also suggest checking the actual values of registers with a debugger.
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.
On a Tiva (Texas Instruments Cortex M4F ARM) TM4C129XNCZAD I have a problem with I2C interface. I have enabled both a master on I2C module 4 thru port K and a slave on I2C module 6 thru port B. I have interconnected both I2C modules. Using Texas Instruments driver library I tried to send 1 byte using I2C_MASTER_CMD_SINGLE_SEND command. I spend a lot of time to make it working, but SCK line keeps Low logical level. I followed exactly TivaWare™ Peripheral Driver Library USER’S GUIDE, but the communication doesn't work. Has anybody some experience with it?
There is my code:
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "inc/tm4c129xnczad.h"
#define SLAVE_ADDRESS 0x3C
void delay (void)
{
volatile uint32_t ui32Loop;
for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++);
}
volatile uint32_t result;
int main (void)
{
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
//
// Enable the GPIO port that is used for the on-board LED.
//
SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R3 | SYSCTL_RCGCGPIO_R9 | SYSCTL_RCGCGPIO_R1;
//
// Do a dummy read to insert a few cycles after enabling the peripheral.
//
result = SYSCTL_RCGCGPIO_R;
//
// Enable the GPIO pin for the LED (PD3). Set the direction as output, and
// enable the GPIO pin for digital function.
//
GPIO_PORTD_AHB_DIR_R = 0x8;
GPIO_PORTD_AHB_DEN_R = 0x8;
GPIO_PORTK_DEN_R = 0xC0; // Enable Port K for I2C module 4
GPIO_PORTB_AHB_DEN_R = 0xC0; // Enable Port B for I2C module 6
SYSCTL_RCGCI2C_R = (1 << 4) | (1 << 6); // Mode Clock Gating Control for I2C modules 4 and 6
GPIO_PORTK_AFSEL_R = 0xC0; // Alternate Function Select PK6, PK7
GPIO_PORTB_AHB_AFSEL_R = 0xC0; // Alternate Function Select PB6, PB7
GPIOPinConfigure(GPIO_PK6_I2C4SCL);
GPIOPinConfigure(GPIO_PK7_I2C4SDA);
GPIOPinConfigure(GPIO_PB6_I2C6SCL);
GPIOPinConfigure(GPIO_PB7_I2C6SDA);
GPIOPinTypeI2C(GPIO_PORTK_BASE, 7); // Configurtes SDA
GPIOPinTypeI2CSCL(GPIO_PORTK_BASE, 6); // Configurtes SCL
GPIOPinTypeI2C(GPIO_PORTB_BASE, 7); // Configurtes SDA
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, 6); // Configurtes SCL
I2CMasterInitExpClk(I2C4_BASE, SysCtlClockGet(), false);
I2CSlaveEnable(I2C6_BASE);
I2CSlaveInit(I2C6_BASE, SLAVE_ADDRESS);
I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
//
// Loop forever.
//
while(1)
{
//
// Turn on the LED.
//
GPIO_PORTD_AHB_DATA_R |= 0x8;
I2CMasterDataPut(I2C4_BASE, 0x33);
I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_SINGLE_SEND);
//
// Wait until the slave has received and acknowledged the data.
//
while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));
//
// Read the data from the slave.
//
result = I2CSlaveDataGet(I2C6_BASE);
//
// Wait until master module is done transferring.
//
while(I2CMasterBusy(I2C4_BASE));
//
// Delay for a bit.
//
delay ();
//
// Turn off the LED.
//
GPIO_PORTD_AHB_DATA_R &= ~(0x8);
//
// Delay for a bit.
//
delay ();
}
}
The problem has been resolved. There were issues:
It is essential to populate external pull ups.
Use GPIOPinTypeI2C() 2nd parameter as a bit field instead of a bit number.
The procedure SysCtlClockSet() is dedicated specially to TM4C123 devices. Instead use g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 40000000);
For a Master clock setting do not use SysCtlClockGet() procedure. This is also dedicated to TM4C123 devices. Instead use I2CMasterInitExpClk(I2C4_BASE, g_ui32SysClock, false);
Here is the updated code,
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "inc/tm4c129xnczad.h"
#define SLAVE_ADDRESS 0x3C
void delay (void)
{
volatile uint32_t ui32Loop;
for(ui32Loop = 0; ui32Loop < 200; ui32Loop++);
}
volatile uint32_t result;
uint32_t g_ui32SysClock;
int main(void)
{
g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 40000000);
//
// Enable the GPIO port that is used for the on-board LED.
//
SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R3 | SYSCTL_RCGCGPIO_R9 | SYSCTL_RCGCGPIO_R1;
//
// Do a dummy read to insert a few cycles after enabling the peripheral.
//
result = SYSCTL_RCGCGPIO_R;
//
// Enable the GPIO pin for the LED (PD3). Set the direction as output, and
// enable the GPIO pin for digital function.
//
GPIO_PORTD_AHB_DIR_R = 0x8;
GPIO_PORTD_AHB_DEN_R = 0x8;
SYSCTL_RCGCI2C_R = (1 << 4) | (1 << 6); // Mode Clock Gating Control for I2C modules 4 and 6
GPIOPinConfigure(GPIO_PK6_I2C4SCL);
GPIOPinConfigure(GPIO_PK7_I2C4SDA);
GPIOPinConfigure(GPIO_PB6_I2C6SCL);
GPIOPinConfigure(GPIO_PB7_I2C6SDA);
GPIOPinTypeI2C(GPIO_PORTK_BASE, (1 << 7)); // Configures SDA
GPIOPinTypeI2CSCL(GPIO_PORTK_BASE, (1 << 6)); // Configures SCL
GPIOPinTypeI2C(GPIO_PORTB_BASE, (1 << 7)); // Configures SDA
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, (1 << 6)); // Configures SCL
I2CMasterInitExpClk(I2C4_BASE, g_ui32SysClock, false);
I2CSlaveEnable(I2C6_BASE);
I2CSlaveInit(I2C6_BASE, SLAVE_ADDRESS);
I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
//
// Loop forever.
//
while(1)
{
//
// Turn on the LED.
//
GPIO_PORTD_AHB_DATA_R |= 0x8;
I2CMasterDataPut(I2C4_BASE, 0x33);
I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_SINGLE_SEND);
//
// Wait until the slave has received and acknowledged the data.
//
while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));
//
// Read the data from the slave.
//
result = I2CSlaveDataGet(I2C6_BASE);
//
// Wait until master module is done transferring.
//
while(I2CMasterBusy(I2C4_BASE));
//
// Delay for a bit.
//
delay ();
//
// Turn off the LED.
//
GPIO_PORTD_AHB_DATA_R &= ~(0x8);
//
// Delay for a bit.
//
delay ();
}
}
I was able to get I2C working on TIVA Launchpad TM4C123GH6PM. I used the the Tivaware library. I created 3 functions, init and write. Here are the functions.
Initialization
void initI2C0(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
//reset I2C module
SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
//enable GPIO peripheral that contains I2C
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
// Configure the pin muxing for I2C0 functions on port B2 and B3.
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
// Select the I2C function for these pins.
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
// Enable and initialize the I2C0 master module. Use the system clock for
// the I2C0 module. The last parameter sets the I2C data transfer rate.
// If false the data rate is set to 100kbps and if true the data rate will
// be set to 400kbps.
I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
//clear I2C FIFOs
HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;
}
I2C Write Function
void writeI2C0(uint16_t device_address, uint16_t device_register, uint8_t device_data)
{
//specify that we want to communicate to device address with an intended write to bus
I2CMasterSlaveAddrSet(I2C0_BASE, device_address, false);
//register to be read
I2CMasterDataPut(I2C0_BASE, device_register);
//send control byte and register address byte to slave device
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
//wait for MCU to finish transaction
while(I2CMasterBusy(I2C0_BASE));
I2CMasterSlaveAddrSet(I2C0_BASE, device_address, true);
//specify data to be written to the above mentioned device_register
I2CMasterDataPut(I2C0_BASE, device_data);
//wait while checking for MCU to complete the transaction
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
//wait for MCU & device to complete transaction
while(I2CMasterBusy(I2C0_BASE));
}
Complete code for TIVA + I2C can be found here.
Reference
I2C Communication with the TI Tiva TM4C123GXL