2018-08-22 05:13 AM
Hi, I'm new to the ST microcontroller, and I'm learning how to use it. I am working with the 32F746GDISCOVERY board and want to operate an S2S interface via the Arduino-IOs on the board.
From the data sheets I can see that I should be able to use the I2S2 resource for this:
I also found an example (STM32Cube_FW_FW7_V1.12.0) that configures an I2S interface:
File: I2S/I2S_DataExchangeInterrupt/Src/main.c ->This example describes how to configure I2S using the STM32F7xx HAL API.
If I do this now analogous to this example, it does not work.
My first question: Where can I find more detailed documentation on the HAL drivers?
My second question: As I have understood this, the I2S2 resource can be assigned to different IOs. How is this configured?
2018-08-22 05:40 AM
JW
2018-08-22 07:46 AM
OK, need some hours to understand a part of your answer, but so far an example for my Clock on PI1:
In addition I have also to setup the ouput states, speed selection etc. How do I change this registers in C? Which function do I have call, or which Macro do I have to use?
2018-08-22 08:54 AM
> In addition I have also to setup the ouput states, speed selection etc. How do I change this registers in C?
> Which function do I have call, or which Macro do I have to use?
As I've said I don't Cube, but if you look at the examples, you certainly notice that there is something like GPIO_Init() or similar function, and in there, a struct is filled with things like "mode is AF" and "number of alternate function" and then a initialization function (HAL_GPIO_Init()) is called, which does the "magic". They may be initialized also elsewhere, in some callback called from the I2S initialization, I don't quite get Cube's logic of doing things (that's why I dont' use it).
> Do I have to write a five somewhere? In the AFR5-Section?
Yes; but in Cube the "magic" in the init function as mentioned above does that. I do this using the usual bit manipulation routines, utiilizing macros defined in the standard CMSIS-mandated device header:
GPIOI->MODER = (GPIOI->MODER
& (~GPIO_MODER_MODER1) // clear the field
) | (0
| (GPIO_Mode_AlternateFunction * GPIO_MODER_MODER1_0) // and now set it to AF
);
GPIOI->AFRL = (GPIOI->AFRL
& (~GPIO_AFRL_AFRL1) // clear the field
) | (0
| (GPIO_AlternateFunction_I2S2 * GPIO_AFRL_AFRL1_0) // I2S2_CK
);
(This, as it stands, wouldn't compile, as many constants are missing from the CMSIS-mandated device header, so I have my collection of header augmentations like
// GPIOx_MODER - 2 bits per pin
#define GPIO_Mode_In 0x00 // GPIO Input Mode
#define GPIO_Mode_Out 0x01 // GPIO Output Mode
#define GPIO_Mode_AlternateFunction 0x02 // GPIO Alternate function Mode
#define GPIO_Mode_Analog 0x03 // GPIO Analog Mode
)
JW
2018-08-22 09:07 AM
You may also perhaps check out CubeMX - again something I don't use but that's a clicky program which might generate some code for you.
JW
2018-08-23 02:24 AM
Nice! Slowly it is getting clearer.. Also a nice example I found :
http://hertaville.com/stm32f0-gpio-tutorial-part-1.html
Unfortunately the macros GPIO_AFRL_AFRL1, GPIO_AlternateFunction_I2S2 and GPIO_AFRL_AFRL1_0 are not defined in my stm32f746xx.h What have you defined there?
Also for GPIOI->AFRL I had to take GPIOI->AFR[0]
Yes I installed the CubeMX on my computer to see how it works. For some strange reason I could not find the 32F746GDISCOVERY board on it. But I also prefer understanding the GPIOs better, so I will try first to do it manually..
2018-08-23 03:00 AM
> GPIO_AFRL_AFRL1 [...] GPIO_AFRL_AFRL1_0
I don't use 'F7xx, but generally the scheme is the same. As I've said (and for the last few years I keep saying loudly and annoyingly wherever I meet ST employees, to no effect) ST doesn't define most of the needed constants in the device headers (they define them in the "libraries" headers, mostly in a non-systematic way, different in SPL and Cube) so I am augmenting the headers myself, trying to stick to a scheme used by ST where similar is existing, and sticking to my own scheme (with "final functionality" after double-underscore) where not.
In the headers I took from SPL and early Cube, GPIO_AFRL_AFRL1 was defined but GPIO_AFRL_AFRL1_0 wasn't so I defined them myself. However, looking into [STM32Cube_FW_F7_V1.7.0]\Drivers\CMSIS\Device\ST\STM32F7xx\Include\stm32f746xx.h , I see
/****************** Bit definition for GPIO_AFRL register *********************/
#define GPIO_AFRL_AFRL0_Pos (0U)
#define GPIO_AFRL_AFRL0_Msk (0xFU << GPIO_AFRL_AFRL0_Pos) /*!< 0x0000000F */
#define GPIO_AFRL_AFRL0 GPIO_AFRL_AFRL0_Msk
#define GPIO_AFRL_AFRL0_0 (0x1U << GPIO_AFRL_AFRL0_Pos) /*!< 0x00000001 */
#define GPIO_AFRL_AFRL0_1 (0x2U << GPIO_AFRL_AFRL0_Pos) /*!< 0x00000002 */
#define GPIO_AFRL_AFRL0_2 (0x4U << GPIO_AFRL_AFRL0_Pos) /*!< 0x00000004 */
#define GPIO_AFRL_AFRL0_3 (0x8U << GPIO_AFRL_AFRL0_Pos) /*!< 0x00000008 */
#define GPIO_AFRL_AFRL1_Pos (4U)
#define GPIO_AFRL_AFRL1_Msk (0xFU << GPIO_AFRL_AFRL1_Pos) /*!< 0x000000F0 */
#define GPIO_AFRL_AFRL1 GPIO_AFRL_AFRL1_Msk
#define GPIO_AFRL_AFRL1_0 (0x1U << GPIO_AFRL_AFRL1_Pos) /*!< 0x00000010 */
#define GPIO_AFRL_AFRL1_1 (0x2U << GPIO_AFRL_AFRL1_Pos) /*!< 0x00000020 */
#define GPIO_AFRL_AFRL1_2 (0x4U << GPIO_AFRL_AFRL1_Pos) /*!< 0x00000040 */
#define GPIO_AFRL_AFRL1_3 (0x8U << GPIO_AFRL_AFRL1_Pos) /*!< 0x00000080 */
etc.
I don't update Cuben regularly as I don't use them so this may be slightly outdated; please don't tell me ST omitted these constants from newer device headers...
> GPIO_AlternateFunction_I2S2
My own. Make it 5 if most of the I2S2 functionality is in the 5th column of the pin-AF table.
Also for GPIOI->AFRL I had to take GPIOI->AFR[0]
Yes, I have
#define AFRL AFR[0]
#define AFRH AFR[1]
I have a problem with the device headers not following the RM nomenclature, however failed it is.
JW
2018-08-23 03:00 AM
Hmm.. when I read this:
http://www.se.rit.edu/~swen-563/resources/STM32L476/GPIO%20and%20Alternate%20Function%20Setup.pdf
.. and combine it with your code it shoud be:
#define GPIO_AFRL_AFRL1 ((uint32_t)0x000000F0)
#define GPIO_AFRL_AFRL1_0 ((uint32_t)0x00000100)
#define GPIO_AlternateFunction_I2S2 ((uint32_t)0x00000005)
is this correct?
2018-08-23 03:12 AM
One more thing - this is stylistic and my own again, so don't take it as a guideline or whatever, just one idea maybe worth some consideration: the vast majority of GPIO functionality tend to be assigned once for the whole life of program, and never or only seldom changed. So what I do is that I write the MODER and AFRx and also OTYPER and OSPEEDR and PUPDR registers at once, at the beginning of my program. In other words, I don't change only certain pins of a port, as it comes with a certain module's initialization. This avoids the read-mask-change-write process, as I described above (however, I take into account the non-standard reset values for the pins with debug functionality, and if appropriate, retain them, in the values written into the registers).
But the truth is, that I too group "functionality", through using my own preprocessor which reorders code; so my GPIO initialization for one pin then looks like:
PC9 I2S_CKIN <table name="dxp GPIO"> <item name="PC"/><item name="pin"> 9 </item> <item name="mode"> AF </item> <item name="AF"> I2S1 </item> <item name="speed"> 25MHz </item> <_item name="PUPD"/> <_item name="type"/> </table>
from which (several lines like these, for the different pins) then my preprocessing framework generates something like
GPIOC->ODR = 0
OR (1 * GPIO_ODR_ODR_4);
GPIOC->PUPDR = 0
OR (GPIO_PullUp * GPIO_PUPDR_PUPDR5_0);
{
const bit64 a = { .l[0] = 0, .l[1] = 0,
.n12 = GPIO_AlternateFunction_SPI3,
.n10 = GPIO_AlternateFunction_SPI3,
.n9 = GPIO_AlternateFunction_I2S1,
};
GPIOC->AFR[0] = a.l[0];
GPIOC->AFR[1] = a.l[1];
}
GPIOC->OSPEEDR = 0
OR (GPIO_Speed_25MHz * GPIO_OSPEEDER_OSPEEDR12_0)
OR (GPIO_Speed_25MHz * GPIO_OSPEEDER_OSPEEDR10_0)
OR (GPIO_Speed_25MHz * GPIO_OSPEEDER_OSPEEDR11_0)
OR (GPIO_Speed_25MHz * GPIO_OSPEEDER_OSPEEDR4_0)
OR (GPIO_Speed_25MHz * GPIO_OSPEEDER_OSPEEDR9_0);
GPIOC->OTYPER = 0 ;
GPIOC->MODER = (0
OR (GPIO_Mode_In * GPIO_MODER_MODER5_0)
OR (GPIO_Mode_AF * GPIO_MODER_MODER12_0)
OR (GPIO_Mode_AF * GPIO_MODER_MODER10_0)
OR (GPIO_Mode_Out * GPIO_MODER_MODER11_0)
OR (GPIO_Mode_Out * GPIO_MODER_MODER4_0)
OR (GPIO_Mode_AF * GPIO_MODER_MODER9_0)
OR (GPIO_Mode_Out * GPIO_MODER_MODER3_0)
OR (GPIO_Mode_Out * GPIO_MODER_MODER8_0));
:D
YMMV
JW
2018-08-23 03:43 AM
#define GPIO_AFRL_AFRL1 ((uint32_t)0x000000F0)
#define GPIO_AFRL_AFRL1_0 ((uint32_t)0x00000010)
#define GPIO_AlternateFunction_I2S2 ((uint32_t)0x00000005)