STM32 - Cortex M3: STIR register - stm32

I'm trying to write code in order to generate software trigger. Datasheets seem confusing to me and I cannot find any example on NET.
In the "Cortex-M3 devices Generic User Guide" in 4.2.8 I read to write in NVIC->STIR register to generate a software interrupt:
[STIR register][1]
But, if I understood correctly USERSETMPEND must be set to 1 for unprivileged software (I think it's my case).
But If I want to access to SCR I have to be "privileged"
[SCR register][2]
So, how can I enter in privileged mode? Is it really necessary enter in this mode only for interrupt configuration?
What I've done in code is
SCB->CCR |= 0x02; // USERSETMPEND = 1. But I must be "privileged"
HAL_NVIC_EnableIRQ(EXTI0_IRQn); // enable interrupt line
.... some code....
... ...
if(my_software_trigger)
{
my_software_trigger = 0;
NVIC->STIR = EXTI0_IRQn; // triggers interrupt??
}
Is it the correct approach? Anyone has experience in this matter? Any help is really appreciatedd..
P.s. Sorry for my english
Marco.

Related

QSPI connection on STM32 microcontrollers with other peripherals instead of Flash memories

I will start a project which needs a QSPI protocol. The component I will use is a 16-bit ADC which supports QSPI with all combinations of clock phase and polarity. Unfortunately, I couldn't find a source on the internet that points to QSPI on STM32, which works with other components rather than Flash memories. Now, my question: Can I use STM32's QSPI protocol to communicate with other devices that support QSPI? Or is it just configured to be used for memories?
The ADC component I want to use is: ADS9224R (16-bit, 3MSPS)
Here is the image of the datasheet that illustrates this device supports the full QSPI protocol.
Many thanks
page 33 of the datasheet
The STM32 QSPI can work in several modes. The Memory Mapped mode is specifically designed for memories. The Indirect mode however can be used for any peripheral. In this mode you can specify the format of the commands that are exchanged: presence of an instruction, of an adress, of data, etc...
See register QUADSPI_CCR.
QUADSPI supports indirect mode, where for each data transaction you manually specify command, number of bytes in address part, number of data bytes, number of lines used for each part of the communication and so on. Don't know whether HAL supports all of that, it would probably be more efficient to work directly with QUADSPI registers - there are simply too many levers and controls you need to set up, and if the library is missing something, things may not work as you want, and QUADSPI is pretty unpleasant to debug. Luckily, after initial setup, you probably won't need to change very much in its settings.
In fact, some time ago, when I was learning QUADSPI, I wrote my own indirect read/write for QUADSPI flash. Purely a demo program for myself. With a bit of tweaking it shouldn't be hard to adapt it. From my personal experience, QUADSPI is a little hard at first, I spent a pair of weeks debugging it with logic analyzer until I got it to work. Or maybe it was due to my general inexperience.
Below you can find one of my functions, which can be used after initial setup of QUADSPI. Other communication functions are around the same length. You only need to set some settings in a few registers. Be careful with the order of your register manipulations - there is no "start communication" flag/bit/command. Communication starts automatically when you set some parameters in specific registers. This is explicitly stated in the reference manual, QUADSPI section, which was the only documentation I used to write my code. There is surprisingly limited information on QUADSPI available on the Internet, even less with registers.
Here is a piece from my basic example code on registers:
void QSPI_readMemoryBytesQuad(uint32_t address, uint32_t length, uint8_t destination[]) {
while (QUADSPI->SR & QUADSPI_SR_BUSY); //Make sure no operation is going on
QUADSPI->FCR = QUADSPI_FCR_CTOF | QUADSPI_FCR_CSMF | QUADSPI_FCR_CTCF | QUADSPI_FCR_CTEF; // clear all flags
QUADSPI->DLR = length - 1U; //Set number of bytes to read
QUADSPI->CR = (QUADSPI->CR & ~(QUADSPI_CR_FTHRES)) | (0x00 << QUADSPI_CR_FTHRES_Pos); //Set FIFO threshold to 1
/*
* Set communication configuration register
* Functional mode: Indirect read
* Data mode: 4 Lines
* Instruction mode: 4 Lines
* Address mode: 4 Lines
* Address size: 24 Bits
* Dummy cycles: 6 Cycles
* Instruction: Quad Output Fast Read
*
* Set 24-bit Address
*
*/
QUADSPI->CCR =
(QSPI_FMODE_INDIRECT_READ << QUADSPI_CCR_FMODE_Pos) |
(QIO_QUAD << QUADSPI_CCR_DMODE_Pos) |
(QIO_QUAD << QUADSPI_CCR_IMODE_Pos) |
(QIO_QUAD << QUADSPI_CCR_ADMODE_Pos) |
(QSPI_ADSIZE_24 << QUADSPI_CCR_ADSIZE_Pos) |
(0x06 << QUADSPI_CCR_DCYC_Pos) |
(MT25QL128ABA1EW9_COMMAND_QUAD_OUTPUT_FAST_READ << QUADSPI_CCR_INSTRUCTION_Pos);
QUADSPI->AR = (0xFFFFFF) & address;
/* ---------- Communication Starts Automatically ----------*/
while (QUADSPI->SR & QUADSPI_SR_BUSY) {
if (QUADSPI->SR & QUADSPI_SR_FTF) {
*destination = *((uint8_t*) &(QUADSPI->DR)); //Read a byte from data register, byte access
destination++;
}
}
QUADSPI->FCR = QUADSPI_FCR_CTOF | QUADSPI_FCR_CSMF | QUADSPI_FCR_CTCF | QUADSPI_FCR_CTEF; //Clear flags
}
It is a little crude, but it may be a good starting point for you, and it's well-tested and definitely works. You can find all my functions here (GitHub). Combine it with reading the QUADSPI section of the reference manual, and you should start to get a grasp of how to make it work.
Your job will be to determine what kind of commands and in what format you need to send to your QSPI slave device. That information is available in the device's datasheet. Make sure you send command and address and every other part on the correct number of QUADSPI lines. For example, sometimes you need to have command on 1 line and data on all 4, all in the same transaction. Make sure you set dummy cycles, if they are required for some operation. Pay special attention at how you read data that you receive via QUADSPI. You can read it in 32-bit words at once (if incoming data is a whole number of 32-bit words). In my case - in the function provided here - I read it by individual bytes, hence such a scary looking *destination = *((uint8_t*) &(QUADSPI->DR));, where I take an address of the data register, cast it to pointer to uint8_t and dereference it. Otherwise, if you read DR just as QUADSPI->DR, your MCU reads 32-bit word for every byte that arrives, and QUADSPI goes crazy and hangs and shows various errors and triggers FIFO threshold flags and stuff. Just be mindful of how you read that register.

HALL Low Level Alternate pull push

I want to Initialize and send a single int using UART in blue_pill (STM32F10C8). Manual ask to set GPIO mode on ALTRN_PULL_PUSH in blue_pill. But Low level HALL library dosn't have such a option. Here is my code for initializing the UART:
void uart2_init()
{
LL_APB1_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
LL_APB1_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE); // ***this line should be corrected***
LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_OUTPUT_50MHz);
LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX);
LL_USART_ConfigCharacter(USART1, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
LL_USART_SetBaudRate (USART1, 8000000, 9600);
LL_USART_Enable(USART1);
}
I need to set pin mode to "LL_GPIO_MODE_ALTERNATE_PUSH_PULL" but the library dosn't provide
it. Can anyone correct me?
I think you should use LL_GPIO_SetPinOutputType(GPIO_TypeDef *GPIOx, uint32_t PinMask, uint32_t OutputType) function.
Which allows You to set output type of pin as :
LL_GPIO_OUTPUT_PUSHPULL
LL_GPIO_OUTPUT_OPENDRAIN
I am highly recommend You to search this kind of information in - UM1850, where You can find a lot of information, for e.g. there is a information about above function on page 807.

I get an Error when setting PCROP STM32H7 (STM32H743)

Goal
I'm trying to set a PCROP area on my STM32H743VI microcontroller, but I'm getting the error code HAL_FLASH_ERROR_OB_CHANGE when executing HAL_FLASH_OB_Launch() and my PCROP area is not set.
The relevant part of the code I'm using should be the following sections
My code
#include "stm32h7xx_hal.h"
FLASH_OBProgramInitTypeDef OBInit;
HAL_FLASHEx_OBGetConfig(&OBInit);
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
// program OB
OBInit.OptionType = OPTIONBYTE_PCROP;
OBInit.PCROPStartAddr = 0x8030000;
OBInit.PCROPEndAddr = 0x8031000;
OBInit.PCROPConfig = OB_PCROP_RDP_ERASE;
OBInit.Banks = FLASH_BANK_1; // (1, 2 oder BOTH)
HAL_FLASHEx_OBProgram(&OBInit);
/* write Option Bytes */
if (HAL_FLASH_OB_Launch() != HAL_OK) {
// Error handling
while (1)
{
}
}
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
The code is mostly inspired by the youtube video "Security Part3 - STM32 Security features - 07 - PCROP lab" (by STMicroelectronics) and the working code I have to change RDP level.
Setup
My secret function is in the expected address range, I did that by adding the memory area in the Flash.Id File
MEMORY
{
[...]
PCROP (x) : ORIGIN = 0x08030000, LENGTH = 16K
}
and putting the function file into the section accordingly
SECTIONS
{
[...]
.PCROPed :
{
. = ALIGN(4);
*led_blinking.o (.text .text*)
. = ALIGN(4);
} > PCROP
[...]
}
I set the flag -mslow-flash-data for the file I'm keeping my secret function in. I did this without really understanding why, following the tutorial in the video (see above).
What I tried
I debugged my program with my J-Trace Debugger and it seems like I'm doing the Option byte modification sequence described in the STM32H743/753 reference manual (p. 159) succesfully.
Securing an entire Flashpage (start 0x080020000, end 0x0803FFFF) didn't work either, even though I did not expect it to make a difference.
I also tried the other option for PCROPConfig, namely the OB_PCROP_RDP_NOT_ERASE option.
HAL_FLASHEx_OBProgram(&OBInit) works as intended and the ObInit Configuration is set correctly into the _FLASH->PRAR_PRG1 register. For my code the content of the register is 0x80880080
I did disconnect and reconnect the microcontroller from power and debugger in case I did not POR correctly.
I checked the errata sheet, but there is no errata which would be applicable to my problem.
EDIT
I changed the area which is protected by PCROP in the My code section.
I did this, since my code is generally functional and I found out it's not a good idea to protect an area in the first flash page!
Hmm, the code looks good so far.
Are you sure PCROP is disabled before setting it again?
Check if PRAR_CUR1 is not set from somewhere else. PCROP will raise a failure when trying to set although it is set.

what is proper way to change properties/generated code of custom HID in STM32CubeIDE

I`m trying to create custom HID device with STM32F103C8, IDE that i choose is STM32CubeIDE and the tutorial that i was following is at ST youtube official channel.
ST offers great tool "Device configuration tool" where i can configure microcontroler, and a lot of code based on my configuration will be generated. That generated code has "user code parts" where user creates his logic, and if he needs to reconfigure microcontroller "Device configuration tool" will not remove that parts of code.
Problem:
To configure custom usb HID i need to change code generated by "Device configuration tool" in places where is no place for user code and that changes will be removed if i run "Device configuration tool" again.
Fields that i only can set in "Device configuration tool" are this:
But that is not enough i also need to change CUSTOM_HID_EPIN_SIZE and CUSTOM_HID_EPOUT_SIZE defines which represent amount of bytes device and host send to each other at once, and also if i change the size of "data pack" i will need to change the default generated callback function that receives that data and works with it, for example the tool generates code like this:
{
USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassData;
if (hhid->IsReportAvailable == 1U)
{
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->OutEvent(hhid->Report_buf[0],
hhid->Report_buf[1]);
hhid->IsReportAvailable = 0U;
}
return USBD_OK;
}
but i need the pointer to "Report_buf" not the copy of its first 2 elements, and the default generated code pass only copy of 2 first bytes, and i cant change this in "Device configuration tool".
My current solution:
Actually i solved this issue, but i don`t think i solved it the right way and it works. I have changed the template files which are here "STM32CubeIDE_1.3.0\STM32CubeIDE\plugins\com.st.stm32cube.common.mx_5.6.0.202002181639\db\templates"
And also changed files at "STM32CubeIDE_1.3.0\en.stm32cubef1.zip_expanded\STM32Cube_FW_F1_V1.8.0\Middlewares\ST\STM32_USB_Device_Library\Class\HID"
I don`t think this is the right way to do it, does any one know the right way to do this thing ?
I also found same question on ST forum here but it was not resolved.
what you want to achieve is exactly what is explained by st trainer on this link.
https://www.youtube.com/watch?v=3JGRt3BFYrM
Trainer is step by step explaining how to change the code to use the pointer to buffer
if (hhid->IsReportAvailable == 1U)
{
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->OutEvent(hhid->Report_buf);
hhid->IsReportAvailable = 0U;
}

Reading/writing SPI devices

(I am really unsure of which tags to apply, so apologies in advance if I chose the wrong ones.)
I hope that this is not a too stupid question, but I'm really lost here.
A client lent me an Atmel SAMA5D2 Xplained board with Linux4SAM to play around with. I'm trying to interface the SPI interface on it, but I have no clue where to start.
To be clear, I've used similar boards (not this particular one) bare-metal. I've also used Linux for many years and wrote a few simple devices drivers some years ago. And still I'm lost.
dmesg | grep spi gives me the following output:
[ 1.840000] atmel_spi f8000000.spi: version: 0x311
[ 1.840000] atmel_spi f8000000.spi: Using dma0chan0 (tx) and dma0chan1 (rx) for DMA transfers
[ 1.850000] atmel_spi f8000000.spi: Using FIFO (16 data)
[ 1.860000] atmel_spi f8000000.spi: Atmel SPI Controller at 0xf8000000 (irq 32)
[ 1.860000] m25p80 spi32766.0: at25df321a (4096 Kbytes)
From this I infer that a driver is loaded and that it is configured to use DMA. Yet, looking in /dev/ there is nothing that looks like a SPI device (I was expecting to find something like /dev/spidev or /dev/spi32766.0 or similar.)
Does this mean that there is no actual device driver loaded? Do I have to write one in order to use the SPI?
If I look at the Makefile in the Linux4SAM source tree, I see around line 1171 that the kernel does not support loading of modules. Does this imply I have to recompile the kernel to include my new driver? This seems to be a silly approach; why providing a Linux distribution if I can't access the hardware with it?
What am I missing here?
(I feel rather stupid...)
EDIT To be clear: I want to access the external SPI interface that will be connected to some external device. I think the m25p80 is some internal Flash memory; I'm not interested to read/write there.
spidev is a standard Linux device driver which just exports a low level API to userspace via /dev interface
if you want to access specific SPI client(slave) you should write your driver
according to Linux SPI driver model:
static const struct of_device_id myspi_dt_ids[] = {
{ .compatible = "xxxx,yyyyy" },
{},
static struct spi_driver xxx_spi_driver = {
.driver = {
.name = "myspi",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(myspi_dt_ids),
},
.probe = myspi_probe,
.remove = myspi_remove,
e.g. define spi_driver struct, of_device_id struct, callbacks(hooks), and register it.
You should bind it to your DT node with compatible property string.
myspi#0 {
compatible = "xxxx,yyyyy";
spi-max-frequency = <5000000>;
reg = <0>;
};
second,
compatible = "linux,spidev";
Linux discourages using this compatible property because nodes should
describe real HW devices not userspace abstractions
#0andriy put me on the right track. I had to add a SPI resource to the Device Tree and flash the compile Device Tree Blob to the board. (Since I didn't know about Device Trees at all, this information is really hard to find...).
I now have a /dev/spidev32765.0. I added this to the device tree:
spi1: spi#fc000000 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spi1_default>;
status = "okay";
spidev#0 {
compatible = "linux,spidev";
spi-max-frequency = <83000000>;
reg = <0>;
};
};
pinctrl#fc038000 {
pinctrl_spi1_default: spi1_default {
pinmux = <PIN_PD25__SPI1_SPCK>,
<PIN_PD26__SPI1_MOSI>,
<PIN_PD27__SPI1_MISO>,
<PIN_PD28__SPI1_NPCS0>;
bias-disable;
};
};
Although I read that adding the spidev#0 is not really the right thing to do (I indeed see in dmesg output "spidev spi32765.0: buggy DT: spidev listed directly in DT").
Now, if I run spidev_test it still doesn't work (it times out), but I guess that's for another question.