Using STM32CubeMX and Atollic TrueStudio, I created a project with a KSZ8851SNL ethernet controller.
On an STM32H742, I have a driver for the Micrel KSZ8851SNL, and created a micro TCP/IP stack, to test the chip. I got that working very well, but it currentl;y only supports ARP, UDP and ICMP. I can ping in two directions, handle ARP request in both directions, and request NTP time from internet.
Now, I would like to let it work together with LwIP.
I know it needs to be implemented in a file ethernetif.c.
Basically, I used these functions to let the micro setup work:
// Initializes the KSZ8851SNL
uint8_t ksz8851_init(void)
// Send a packet, returns length of received package
// The received length can be checked if we received a packet
uint16_t ksz8851_Receive(uint8_t *pRXData, uint16_t pRXMaxLength)
// Receive a packet
void ksz8851_Send(uint8_t *pTXData, uint16_t pTXLength)
The project is an Atollic TrueStudio project, and I use HAL.
Are above functions sufficient for LwIP?
How do I implement this in LwIP?
I read lots of documentation, but it seems not detailed to this part.
Sources are on hithub:
https://github.com/bkht/STM32H7_HAL_KSZ8851SNL
Thanks a lot for helping me out!
One more thing other than uncomment // MX_LWIP_Init();.
I have an STM32H743 Nucleo-144 and tried to run it(commit number f8ff06c2c17f3d6dacbff8c2fd8eb95591a0c224), too. However, it was stuck in this loop: https://github.com/bkht/STM32H7_HAL_KSZ8851SNL/blob/master/Drivers/KSZ8851SNL/Src/KSZ8851SNL.c#L443-L506 because of a failure of reading chip ID with ksz8851_reg_read() . Then I dig deeper in to the source code, and here is a possible solution:
Change the GPIO setting of SPI2's NSS/CS pin
In the .ioc file(if you are still generating workspace with it), set SPI2's "Hardware NSS Signal" to "Hardware NSS Output Signal" in
https://github.com/bkht/STM32H7_HAL_KSZ8851SNL/blob/master/Nucleo-H743ZI_Jack_013_tcp_KSZ8851SNL_Test.ioc.
Or change the source directly by giving PB12 a different GPIO-setting as
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
Uncomment the macro of SPI2 CS Pin https://github.com/bkht/STM32H7_HAL_KSZ8851SNL/blob/master/Drivers/KSZ8851SNL/Inc/KSZ8851SNL.h#L55-L67 and the usage of them(// RESET_SPI_CS_PIN(); & // SET_SPI_CS_PIN();) in https://github.com/bkht/STM32H7_HAL_KSZ8851SNL/blob/master/Drivers/KSZ8851SNL/Src/KSZ8851SNL.c
Then, the correct chip ID will be fetched.
Clement
Related
I'm new to STM microcontrollers and trying to use the STM32CubeIDE.
The problem is that it doesn't generate the codes that configure the GPIO registers.
More specifically, I'd like to set the PB14 as an output port so that the LED3 can blink.
After this screen, in my understanding, the code to configure PIO registers should be automatically generated in main.c, whether it's for the Cortex-M4 core or M7. However, there was nothing like that. Even the global search for such a code didn't find one. As a result, the code below, which is supposed to toggle the output level for the LED3, just don't work. (It didn't blink.)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_Delay(1000);
When I manually set the registers as shown below, the LED3 successfully blinks.
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_14;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
I'm using the NUCLEO-H745ZI board.
Edit:
Solved.
For MCUs that have multiple cores, I just had to select the core that I want to put the generated code in, as shown below.
Could you please help me to identify where i make the mistake? LED is on PA5 port.
int main(void){
HAL_Init();
SystemClock_Config();
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
while(1){
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(5000);
}
}
On microcontrollers pins have multiple functions, which functions is enabled has to be configured by software and sometimes by hardware (pulling pins to VCC or GND,...). PA5 of the STM32L073xZ has alternate functions, this is in the datasheet (https://www.mouser.de/datasheet/2/389/stm32l073v8-956245.pdf) on page 39 and 45, the package of the MCU on the Nucleo L073RZ is LQFP64, cf schematic of the Nucleo in https://www.st.com/content/ccc/resource/technical/document/user_manual/98/2e/fa/4b/e0/82/43/b7/DM00105823.pdf/files/DM00105823.pdf/jcr:content/translations/en.DM00105823.pdf on page 64 (https://www.st.com/content/ccc/resource/technical/document/reference_manual/2f/b9/c6/34/28/29/42/d2/DM00095744.pdf/files/DM00095744.pdf/jcr:content/translations/en.DM00095744.pdf).
i do not know if you have enabled the alternate functions somewhere in the rest of your code however this is possibly the core of the problem. The part of the code you posted is accurate, in https://github.com/TechBreiteneder/00_GPIO_BlinkLED/blob/master/Src/main.c is LED blinking code in a CubeMX project. So possibly you enabled an alternate function on pin PA5, in addition you have to enable other components like the clock system for the MCU to work at all, cf https://riptutorial.com/stm32/example/25059/first-time-setup-with-blink-led-example-using-sw4stm32-and-hal-library . So without knowing your configuration of the MCU it is hard to say where the error is ...
What you should do is to set a defined inital state before toggling something however i think this is not the problem
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN5, GPIO_PIN_RESET);
I am trying to receive 8 bytes from my pc on my NUCLEO F446RE stm32 board.
Transmitting to the pc works.
The problem is, I am unable to receive data using DMA.
I saw an example with almost the same code and it has worked for the person.
If I use the interrupt mode (just change HAL_UART_Receive_DMA to HAL_UART_Receive_IT, it does work and the RX Complete callback is being called.
Here is the complete main.c. DMA is in circular mode.
main.c
https://pastebin.com/1W4BCjxB
I got it solved, it is actually ridiculous.
So, this is part of the code that CubeMX generates:
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_DMA_Init();
If I order it as follows:
MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
It works!!!
I had the same problem. Here is the solution with using the CubeMX integrated view.
In the CubeMX->Project Manager->Advanced Settings you can select the order of functions to be generated. I moved my MX_DMA_Init to the top to ensure that the DMA is ready before any other peripherals are initialised.
You haven't initialized the DMA variables as well as handler for the DMA interrupt. You will need to do something along these lines
Initialize DMA:
hdma_usart2_rx.Instance = DMA2_Stream1;
hdma_usart2_rx.Init.Channel = DMA_CHANNEL_2;
hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_rx.Init.MemInc = DMA_MINC_DISABLE;
hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart2_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_usart2_rx);
void DMA2_Stream2_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA2_Stream2_IRQn);
HAL_DMA_IRQHandler(&hdma_usart1_rx);
}
HAL_UART_Receive_DMA only starts the DMA and does not handle the interrupt and the data transfer.
I'm using a STM32L432 device with FreeRTOS and STM32CubeMX.
I try to implement a M2M-Communication via USART based on an ASCII protocol. The protocol sequences can differ in length but have a maximum length and a defined end character ('\r' / 0x0D).
So I thought about collecting all RX-USART data with DMA (like a FIFO) and using the address match isr based on the USART_ICR_CMCF flag to determine an end character.
Initialize USART1 and enable address match isr
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART1) {
/* USART1 clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */
USART1->CR2 |= 0x0D000000; // \r 0x0D
__HAL_UART_ENABLE_IT(&huart1,UART_IT_CM);
}
}
USART1 isr handler
void USART1_IRQHandler(void) {
if (USART1->ISR & USART_ISR_CMF) {
data = USART1->RDR;
SET_BIT(USART1->ICR,USART_ICR_CMCF);
}
HAL_UART_IRQHandler(&huart1);
}
Right now, the address match isr works fine, but I don't have a idea how to implement the DMA / FIFO support.
BTW:
I was very surprised, that the device doesn't support a USART HW FIFO. Is my idea to use DMA to reproduce the FIFO commonly used?
The point of DMA is to not involve the CPU in every byte being transferred. If your ISR is being called for every byte then CPU gets involved so simultaneously enabling DMA, if at all that is possible, won't yield any performance benefits. Get rid of any one of the two - per byte interrupts or the DMA. If you most definitely want to check for a particular character as it arrives then DMA would not help.
Another popular approach to detect end of input when using arbitrary length input along with DMA is to use the USART idle interrupt. This interrupt is triggered when one byte time (time required to transfer one byte at current baud rate) elapses without any transfer. In this interrupt you can transfer the DMA buffer contents to another memory location then reinitialize DMA for future input and leave. Or you can process the input then and there. You can do whatever you want in the Idle ISR as long as the ISR completes execution quickly.
If your input has large continuous runs of data then the idle interrupt would trigger after a long time and you might have overwritten your buffer by then. You can use other DMA interrupts like Half Complete and Full Complete to handle this. So that can be taken care of too. I personally found this method to be buggy during stress testing. But there is no reason for it to be so, I didn't get enough time to debug it when I tried to use it but you will find articles online about this technique.
I want to read/write from external flash (Winbond W25Q16BV) with STM32 micro (stm32F030F4). but running process halt on 'HAL_SPI_Init()' function.
I checked the debug process, and found HAL_SPI_STATE_BUSY.
but i don't know why?
I am using STM32CubeMX to generate main project and Keil IDE to write and debug.
SPI_HandleTypeDef hspi1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
uint8_t spiData[2];
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
MX_FATFS_Init();
SPI_HandleTypeDef my_hspi;
HAL_SPI_Init(&my_hspi);
HAL_FLASH_Unlock();
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET); // CS to HIGH
HAL_Delay(10);
//Read data
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET); // CS to low
spiData[0]=0x05;
//transmit register address
HAL_SPI_Transmit(&my_hspi,spiData,1,10);
//read
HAL_SPI_Receive(&my_hspi,&spiData[1],1,10);
...
Here is our schematic:
Unfortunately, I did not find a good example/instruction of how to use external SPI libraries. Any help in this problem is highly appreciated.
I am not able to comment on the software, but according to your comment you want to enable the reading and writing of the flash.
The Write Protect (/WP) pin can be used to prevent the Status Register from being written.
The /WP pin is active low (GND). (Write disable)
The /WP pin is inactive high (VCC). (Write enable)
Its design only allows reading data.
If you want to read and write data, /WP must be connected to Vcc.
You have not set any parameters for the my_hspi struct so your HAL driver doesn't know what he has to do.
Look at the definition of the struct. There are a lot of comments what the different struct elements are used for. For initialization the my_hspi.init part will be most interesting.
Also you have to the the my_hspi.Instance to the desired SPI Channel.
You can generate an example configuration using the free STM32 Cube Mx Software.