Tilt sensing with Lis3dh and stm32 - accelerometer

I am using the LIS3DH sensor with STM32F4 and I want to calculate the tilt angle.
I am aware that I am supposed to calculate the angles(Yaw-Pitch-Roll(ψ-θ-φ)) using some formulas but I don't know how to calculate values obtained after
applying accelerometer calibration on raw measurement data(Ax1,Ay1, Az1).
And how can I make sure that the sensor understands that it is in its steady state before being moved?
while (1)
{
// HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_0);
// HAL_Delay(100);
/* USER CODE END WHILE */
lis3dh_reg_t reg;
/* Read output only if new value available */
lis3dh_xl_data_ready_get(&dev_ctx, &reg.byte);
if (reg.byte) {
/* Read accelerometer data */
memset(data_raw_acceleration, 0x00, 3 * sizeof(int16_t));
lis3dh_acceleration_raw_get(&dev_ctx, data_raw_acceleration);
acceleration_mg[0] =lis3dh_from_fs2_hr_to_mg(data_raw_acceleration[0]);
acceleration_mg[1] =lis3dh_from_fs2_hr_to_mg(data_raw_acceleration[1]);
acceleration_mg[2] =lis3dh_from_fs2_hr_to_mg(data_raw_acceleration[2]);
sprintf((char *)tx_buffer,"Acceleration [mg]:%4.2f\t%4.2f\t%4.2f\r\n",acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
tx_com(tx_buffer, strlen((char const *)tx_buffer));
}
roll = atan2(acceleration_mg[1] , acceleration_mg[2]) * 57.3;
pitch = atan2((-acceleration_mg[0]) , sqrt(acceleration_mg[1] *acceleration_mg[1] +acceleration_mg[2] *acceleration_mg[2])) * 57.3;
if (pitch==-0.0645269975){
HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_0);
}
/* USER CODE BEGIN 3 */
}
I'm using the library shared in: https://github.com/s54mtb/LEDS/blob/master/Src/lis3dh_driver.c

Related

Generating a DLL from a Simulink model with S-Function and using it in Unity 3D

I'm trying to generate a DLL for a Simulink model with an S function and use that in Unity 3D. To try a simple example, I just made a model with an S-function that multiplies the input value by 2.
I've generated the DLL of this using the Embedded Coder feature. The code generated contains the essential function as follows:
void S_function_tlc_try_step(RT_MODEL_S_function_tlc_try_T *const
S_function_tlc_try_M, real_T S_function_tlc_try_U_x, real_T
*S_function_tlc_try_Y_y)
{
/* local block i/o variables */
real_T rtb_Level2MATLABSFunction1;
/* M-S-Function: '<Root>/Level-2 MATLAB S-Function1' incorporates:
* Inport: '<Root>/x'
*/
/* Multiply input by two */
rtb_Level2MATLABSFunction1 = S_function_tlc_try_U_x * 2.0;
/* Outport: '<Root>/y' */
*S_function_tlc_try_Y_y = rtb_Level2MATLABSFunction1;
/* Update absolute time for base rate */
/* The "clockTick0" counts the number of times the code of this task has
* been executed. The absolute time is the multiplication of "clockTick0"
* and "Timing.stepSize0". Size of "clockTick0" ensures timer will not
* overflow during the application lifespan selected.
*/
S_function_tlc_try_M->Timing.t[0] =
((time_T)(++S_function_tlc_try_M->Timing.clockTick0)) *
S_function_tlc_try_M->Timing.stepSize0;
UNUSED_PARAMETER(S_function_tlc_try_M);
}
The script in Unity is as follows:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
public class Sfunctiontry : MonoBehaviour
{
public double input, output;
double constant;
[DllImport("S_function_tlc_try_win64")]
static extern void S_function_tlc_try_step(double constant, double inp, ref double outp);
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
S_function_tlc_try_step(constant, input, ref output);
Debug.Log("Multiplying by 2");
print(output);
}
}
However whenever I attach this to an object and execute, Unity crashes. It works fine when I'm using the DLL of a model without any S-function.
Is there a solution for this? Any leads would be great.
Thanks in advance.

How to implement UART1 Interrupts correctly on STM32f103xx while running a main programme?

I am trying to program my bluePill to blink an LED at the PB11 pin while echoing whats being send over the serial port UART1.
as far as my knowledge, Interrupts allows us to run the programme we want and while running it if any flag triggered an interrupt signal the program the control will be diverted to run the interrupt service routine while the original program is running, am I correct here?
So, I'm trying to keep the Green LED blinking and when I type anything on the serial port the red LED blinks while the green is blinking and the blue led must be always turned on unless data is being sent.
Problem 1:
The green led never blinks!
Problem 2:
Whenever sending letters or numbers through Arduino serial monitor the received echo is always 2 letters out of the entire send letters, also the echo is always on the same line, I mean not not on a newline
so typing Hello and pressing enter yields He and when typing hi there and pressing enter the it just adds the first two letters like so Hehi , why?
my code is
/* ********************** Project Description ***********************
STM32f103xx BluePill Board
PB10 = Green LED
PB11 = Blue LED (To be toggled)
PB0 = Red LED (PWM OUTPUT Controlling the Brightness)
PB9 = Push Button for toggling the state of the blue LED
PA0 = Potentiomater Pin (Analog Input)
USART1 Activated and Sends the Voltage of PA0 to the user1
*/
#include "stm32f1xx.h" // Include the MCU header
#include <stdbool.h> // Boolean Library header
#include <stdint.h>
// Prototypes:
void UART1_Init(void); //Enable UART1 on PA9(Tx) & PA10(Rx).
void portsEnable(void); //Enable Clock for desired MCU Ports.
void delay(uint32_t delay); //Intuduce Delays.
void pinsConfig(void); //Configure the used pins.
// Defines and Macros
int main(void)
{
// Inintialization:
portsEnable();
pinsConfig();
UART1_Init(); // Enable USART1 & interrupts # 8Mhz clock Speed only # 9600Bps
while(1)
{
// ******** Blink The green LED ***********************
GPIOB->BSRR = GPIO_BSRR_BS11;
delay(100000);
GPIOB->BSRR = GPIO_BSRR_BR11;
delay(100000);
} // End of while loop
} // End main() loop
// ************** Function Implimentation *****************************
void UART1_Init(void) // Initiallize USART1
{
// Reset Setting (8bit, one stop bit, no parity)
// Enable clock for UART1 First after already enabling the PortA clock
RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // Enable Clock to the USART1 Module
// Pin Configuration for the USART1 Peripheral where Tx(PA9) = AF Push-Pull and Rx = Input Floating
// Setting Tx (PA9) Pin
GPIOA->CRH |= ((1<<4) | (1<<5)); // Set PA9 to Output 50Mhz Mode
GPIOA->CRH &= ~(1<<6); // Configure it to be an AF push-pull
GPIOA->CRH |= (1<<7); // Same as above^
// Setting Rx (PA10) pin
// Nothing to be set as the reset value makes it an input pin with floating configuration
// Set the Baud-Rate
USART1->BRR = 0x341; //# 8Mhz, USARTDIV = 8Mhz/(16*9600) = 52.083 -> 52=0x34 and 0.083 * 16 = 1.328 = 1 which is 0x1
// Enable Interrupts for the USART1 Module:
// A peripheral can generates a flag at a certain event, this flag can trigger an interrupt signal but first the certain event interrupt must be enabled and the peripheral interrupt as well and the global interrupts.
USART1->CR1 |= USART_CR1_TXEIE | USART_CR1_RXNEIE; // Enable the Transmit Data Register Empty Interrupt register and data received interrupt
// Enable the Tx, Rx, USART1 as a whole block
USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
// Enable the USART1 Global interrupt on NVIC "Nested Vectored Interrupt controller" side. The NVIC is the interrupt processing unit in the MCU.
NVIC_EnableIRQ(USART1_IRQn); // This function's name can't be changed!
}
// This is a global interrupt service routine, any flag from the USART1 will lead to the same ISR, to distinguesh which is which we check the the flags and if one is set then this what caused the interrupt
void USART1_IRQHandler(void) // This function's name must be the same as it's defined in the main libraries
{
// Check if we are here because we Received Data or simply the "RXNE flag is set".
if(USART1->SR & USART_SR_RXNE) // If Rx is Not Empty, or if we received Data, The USART1->SR register is going to change as it is controlled by the hardwart and we compare it to the value of the register USART_SR_RXNE which indicates a 1 at bit5
{
char temp = USART1->DR; // Read the 8bit data received fron the data register into a char called temp
USART1->DR = temp; // Put the same data in the data register to be resent again, here the data registers are clled shadow registers they are not the same registers from the hardware prospective but from programming prospective we use the same registers
while(!(USART1->SR & USART_SR_TC))
{
// Wait while the transmission completes and indicate the waiting process by flashing the RED led indicating data being sent.
GPIOB->BSRR = GPIO_BSRR_BR10; // When not ready to accept more data (e.g. while transmitting data process) turn of the Blue LED
GPIOB->BSRR = GPIO_BSRR_BS1;
delay(10000);
GPIOB->BSRR = GPIO_BSRR_BR1;
}
}
// Check if we are here because the TXEIE is set "OR the Transmit complete" meaning we are ready to accept more data to transmit
if(USART1->SR & USART_SR_TXE)
{
// Handle transmit complete here: (Blink an LED)
GPIOB->BSRR = GPIO_BSRR_BS10; // When Ready to accept more data
}
else
{
GPIOB->BSRR = GPIO_BSRR_BR10; // When not ready to accept more data (e.g. while transmitting data process)
}
}
void portsEnable(void) /* Enable PortA and PortB */
{
// Enable clock for Ports (A & B) on "APB2" Bus.
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Enable PortA Clock
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Enable PortB Clock
}
void pinsConfig(void) //Configure the used pins.
{
//Set pin "PB1" as output push-pull (Red LED)
GPIOB->CRL |= ((1<<4) | (1<<5)); //Set Pin to Output 50Mhz max speed
GPIOB->CRL &= ~((1<<6) | (1<<7)); //Configure Pin as Push-Pull
//Set Pin "PB9" as Input Pulled-Up (Push Button Pin)
GPIOB->CRH &= ~(1<<6); //Set PB9 to input "pullup|pulldown"
GPIOB->CRH |= (1<<7);
GPIOB->ODR |= (1<<9); //Set PB9 input pin as Pull-up pin.
//Set pin "PB10" as output push-pull (Blue LED)
GPIOB->CRH |= ((1<<9) | (1<<8)); //Set Pin to Output 50Mhz max speed
GPIOB->CRH &= ~((1<<11) | (1<<10)); //Configure Pin as Push-Pull
//Set pin "PB11" as output push-pull (Green LED)
GPIOB->CRH |= ((1<<12) | (1<<13)); //Set Pin to Output 50Mhz max speed
GPIOB->CRH &= ~((1<<14) | (1<<15)); //Configure Pin as Push-Pull
//Set pin PA0 as Analog input
GPIOA->CRL &= ~((1<<0) | (1<<1)); // Make sure the Mode registers are 00 for input
GPIOA->CRL &= ~((1<<2) | (1<<3)); // Set the CNF registers to 00 for input analog
} // End PinsConfig()
void delay(uint32_t delay) /* Psudo-delay in Milliseconds */
{
for(uint32_t i = 0; i <= delay; i++)
{
// Looping to delay!
}
}
Maybe below link is helpful for you:
stm32 dead lock

Interfacing ICM20948 with STM32F446RE HAL Layer in SPI

I am having troubles in interfacing the ICM20948 IMU with the HAL_layer of ST. My Master device (ST) is sending the data correctly to the slave (ICM) but the slave is not responding. I have checked very well every connection. I have tested several ICM's(3) and I have debugged it with my Logic analyser also (see pic below) I would really appreciate any help or pointer you could provide me.
My current setup is
The code its very simple I just have two simple read/write rotines
// --------------------------------------------------------------------------------------
/// \brief
///
/// \param *imu[in,out]: (IMU_def) IMU object with their respective ports
/// \param reg[in]: (uint8_t) register address
/// \param *pData[out]: (uint8_t) Data buffer
/// \return void
// --------------------------------------------------------------------------------------
void ICM_ReadOneByte (IMU_def *imu, uint8_t reg, uint8_t *pData)
{
reg = reg | 0x80; // Make the MSB active to tell is a read see p31
HAL_GPIO_WritePin(imu->CS_GPIO_Port, imu->CS_Pin, GPIO_PIN_RESET); // Start transmission
HAL_Delay(1);
HAL_SPI_Transmit(imu->spi_bus, &reg, 1,1000);
while (HAL_SPI_GetState(imu->spi_bus) != HAL_SPI_STATE_READY) // TODO: Possible inf loop if slave don't answer. Counter?
;
HAL_SPI_Receive(imu->spi_bus, pData, 1,1000);
while (HAL_SPI_GetState(imu->spi_bus) != HAL_SPI_STATE_READY) // TODO: Possible inf loop if slave don't answer. Counter?
;
HAL_GPIO_WritePin(imu->CS_GPIO_Port, imu->CS_Pin, GPIO_PIN_SET); // End transmission
}
// --------------------------------------------------------------------------------------
/// \brief
///
/// \param *imu[in,out]: (IMU_def) IMU object with their respective ports
/// \param reg[in]: (uint8_t) register address
/// \param Data[in]: (uint8_t) Data to write
/// \return void
// --------------------------------------------------------------------------------------
void ICM_WriteOneByte (IMU_def *imu, uint8_t reg, uint8_t Data)
{
reg = reg & 0x7F; // Make the MSB disable to tell is a write see p31
HAL_GPIO_WritePin(imu->CS_GPIO_Port, imu->CS_Pin, GPIO_PIN_RESET); // Start transmission
HAL_Delay(5);
HAL_SPI_Transmit(imu->spi_bus, &reg, 1,1000);
HAL_SPI_Transmit(imu->spi_bus, &Data, 1,1000);
HAL_GPIO_WritePin(imu->CS_GPIO_Port, imu->CS_Pin, GPIO_PIN_SET); // End transmission
}
In the main function I use the SPI_HandleTypeDef hspi2; instance to initialise an IMU object as
imu.spi_bus = &hspi2;
imu.CS_GPIO_Port = GPIOB;
imu.CS_Pin = GPIO_PIN_4;
Just for testing that everything is fine I Just selected the BANK_0 and ask WHOIAM by
ICM_WriteOneByte(imu,USER_BANK_SEL, ICM_BANK_0); // USER_BANK_SEL (0x7F); USER_BANK_0:(0x00)
ICM_ReadOneByte(imu, 0x00, &whoami); //
I have also try several steps in between when before calling WHOIAM() such as setting the reseting the device, Seting the internal clock, etc but nothing works. This is how I set other lines just in case:
ICM_WriteOneByte(imu,PWR_MGMNT_1, PWR_MGMNT_1_DEV_RESET); //PWR_MGMNT_1 (0x06);PWR_MGMNT_1_DEV_RESET:(0x80)
ICM_WriteOneByte(imu,PWR_MGMNT_1,PWR_MGMNT_1_CLOCK_SEL_AUTO);//(0x01)
In addition I also try NSS Disable (as is only one device) or Hardware(ST as output) but nothing changed.
Here is a picture of my Logic analyser
As you can see The Master is sending correctly the data to the slave but the slave is always High in the MISO line. I checked the frequency with my logic analyser and is bellow 7MHz as stated in the datashet
Nfalling 8
Nrising 8
fmin 3.846 MHz
fmax 4.167 MHz
fmean 3.977 MHz
Any Ideas are very welcome.
Thanks!
From the manual:
NOTE: To prevent switching into I2C mode when using SPI, the I2C interface should be disabled by setting the I2C_IF_DIS configuration bit. Setting this bit should be performed immediately after waiting for the time specified by the “Start-Up Time for Register Read/Write” in Section 6.3.

PlatformIO in VSCode

I downloaded the latest version of VS Code with PlatformIO, i also downloaded the library Mouse.h from PlatformIO Library Manager, and even so, after i upload the code to my Micro Pro the mouse does not respond to the joystick!
But the same code works when i upload via Arduino IDE!
I compared the Mouse.h from .platformio/lib with the Mouse.h from program files\Arduino\libraries
I compared the Mouse.cpp from .platformio/lib with the Mouse.cpp from program files\Arduino\libraries
And they have exactly the same code!
This is my code for my MICRO PRO 32u4 5v:
/* HID Joystick Mouse Example
by: Jim Lindblom
date: 1/12/2012
license: MIT License - Feel free to use this code for any purpose.
No restrictions. Just keep this license if you go on to use this
code in your future endeavors! Reuse and share.
This is very simplistic code that allows you to turn the
SparkFun Thumb Joystick (http://www.sparkfun.com/products/9032)
into an HID Mouse. The select button on the joystick is set up
as the mouse left click.
*/
#include <Arduino.h>
#include <Mouse.h>
int horzPin = A0; // Analog output of horizontal joystick pin
int vertPin = A1; // Analog output of vertical joystick pin
int selPin = 9; // select button pin of joystick
int vertZero, horzZero; // Stores the initial value of each axis, usually around 512
int vertValue, horzValue; // Stores current analog output of each axis
const int sensitivity = 200; // Higher sensitivity value = slower mouse, should be <= about 500
int mouseClickFlag = 0;
void setup()
{
pinMode(horzPin, INPUT); // Set both analog pins as inputs
pinMode(vertPin, INPUT);
pinMode(selPin, INPUT); // set button select pin as input
digitalWrite(selPin, HIGH); // Pull button select pin high
delay(1000); // short delay to let outputs settle
vertZero = analogRead(vertPin); // get the initial values
horzZero = analogRead(horzPin); // Joystick should be in neutral position when reading these
}
void loop()
{
vertValue = analogRead(vertPin) - vertZero; // read vertical offset
horzValue = analogRead(horzPin) - horzZero; // read horizontal offset
//delay(3000);
if (vertValue != 0)
Mouse.move(0, vertValue/sensitivity, 0); // move mouse on y axis
if (horzValue != 0)
Mouse.move((horzValue/sensitivity) *-1, 0, 0); // move mouse on x axis
if ((digitalRead(selPin) == 0) && (!mouseClickFlag)) // if the joystick button is pressed
{
mouseClickFlag = 1;
Mouse.press(MOUSE_LEFT); // click the left button down
}
else if ((digitalRead(selPin))&&(mouseClickFlag)) // if the joystick button is not pressed
{
mouseClickFlag = 0;
Mouse.release(MOUSE_LEFT); // release the left button
}
}
Did you restart VS Code after installing the lib?
For me it fix this kind of problems in some cases.
Edit: Did you "rebuild IntelliSense Index" by press "Ctrl + shift + p"?

Arduino sketch that reads serial characters as a command and does something

Currently I am trying to get a sketch working where the Arduino will read a series of characters as a command, and do something based on the series of characters sent from an iDevice. I am using an iPhone 3GS that is jailbroken to send characters to the Arduino. The method that sends the serial characters looks like the following,
- (IBAction)blinkFlow_A_LED:(id)sender {
// Method to blink the Flow_A LED on the kegboard-mini Arduino shield (<https://github.com/Kegbot/kegboard>).
NSLog(#"blink Flow_A btn pressed");
// Open serial port / interface
[serial open:B2400];
NSLog(#"%c", [serial isOpened]);
// Send serial data (TX)
char buffer [7];
buffer[0] = '{';
buffer[1] = 'b';
buffer[2] = 'l';
buffer[3] = 'i';
buffer[4] = 'n';
buffer[5] = 'k';
buffer[6] = '}';
[serial write:buffer length:7];
}
I have created a simple sketch that blinks the LED on the shield I am using, but I want the LED to blink conditionally when the button is clicked in the iOS app. The sketch that blinks the LED looks like the following,
/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.
This sketch is specific to making the kegboard-mini shield.
http://arduino.cc/forum/index.php?topic=157625.new;topicseen#new
This example code is in the public domain.
*/
// Pin D4 - should be connected to the flow_A LED
// Give it a name
int led = 4;
// The setup routine runs once when you press reset:
void setup() {
// Initialize the digital pin as an output.
pinMode(led, OUTPUT);
}
// The loop routine run over and over again forever:
void loop() {
digitalWrite(led, HIGH); // Turn the LED on (HIGH is the voltage level)
delay(1000); // Wait for one second
digitalWrite(led, LOW); // Turn the LED off by making the voltage LOW
delay(1000); // Wait for a second
}
That is a simple sketch!
You may want to begin with looking at the Arduino reference page: Serial
In setup(), you need at least Serial.begin(2400);.
Now, I'll suggest that reading and decoding the string "{blink}" seems like overkill. Let me suggest you send one character (for example 'b'), and detect one character, at least to start. Check out .available() and .read() on the Serial reference page. With these you can determine if a character has arrived at the Arduino and read in a single character.
You can then use these if you want to build a string of characters one at a time and compare it to String("{blink}"). This is a bit more complicated, especially if you take into account exceptions (like lost or damaged characters).
You can easily test your program using the Serial monitor tool -- just be advised that you have to hit "send" to make the characters go out.
I ended putting a simple sketch together like this which allows me to store an array of serial bytes into a String thanks to the SerialEvent example.
The sketch I am currently working with looks like the following,
/*
* kegboard-serial-simple-blink07
* This code is public domain
*
* This sketch sends a receives a multibyte String from the iPhone
* and performs functions on it.
*
* Examples:
* http://arduino.cc/en/Tutorial/SerialEvent
* http://arduino.cc/en/Serial/read
*/
// Global variables should be identified with "_"
// flow_A LED
int led = 4;
// relay_A
const int RELAY_A = A0;
// Variables from the sketch example
String inputString = ""; // A string to hold incoming data
boolean stringComplete = false; // Whether the string is complete
void setup() {
Serial.begin(2400); // Open a serial port. Sets data rate to 2400 bit/s
Serial.println("Power on test");
inputString.reserve(200);
pinMode(RELAY_A, OUTPUT);
}
void open_valve() {
digitalWrite(RELAY_A, HIGH); // Turn RELAY_A on
}
void close_valve() {
digitalWrite(RELAY_A, LOW); // Turn RELAY_A off
}
void flow_A_blink() {
digitalWrite(led, HIGH); // Turn the LED on (HIGH is the voltage level)
delay(1000); // Wait for one second
digitalWrite(led, LOW); // Turn the LED off by making the voltage LOW
delay(1000); // Wait for a second
}
void flow_A_blink_stop() {
digitalWrite(led, LOW);
}
void loop() {
// Print the string when newline arrives:
if (stringComplete) {
Serial.println(inputString);
// Clear the string:
inputString = "";
stringComplete = false;
}
if (inputString == "{blink_Flow_A}") {
flow_A_blink();
}
}
// SerialEvent occurs whenever a new data comes in the
// hardware serial RX. This routine is run between each
// time loop() runs, so using delay inside loop can delay
// response. Multiple bytes of data may be available.
void serialEvent() {
while(Serial.available()) {
// Get the new byte:
char inChar = (char)Serial.read();
// Add it to the inputString:
inputString += inChar;
// If the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}