STM32F103 USB CDC Rx Error - Page 1
Forum section: electronics / beginners

author: noname4me
author_rank: Regular Contributor
timestamp: September 13, 2016, 09:52:21 pm
content: Hi,I'm trying to get an LCD screen to work using SPI (4 wire), but I don't think I have the start up sequence correct.To troubleshoot this, I am trying to send commands in hex via the USB connected as a CDC device.I have previously asked questions about using STM32 HAL libraries, and was informed that they were buggy for the CDC driver.For transmission I used CDC_Transmit_FS((pointer to variable that holds information to be transmitted) , (size)).In this vein I am trying to use CDC_Receive_FS() but when I try and compile it using Keil V5 it complains that it is being declared implicitly.I checked the header file "usbd_cdc_if.h", and it seems that the receive function is not defined there, even though it exists in the "usbd_cdc_if.c".How do I enter this into the header file?Is there any better way that I can send data via the USB to the dev. board to send commands directly to the LCD (assuming that the SPI is working correctly - I can get the LCD to invert and switch on fine).ThanksETA: corrected syntax of transmit function

author: Signal32
author_rank: Frequent Contributor
timestamp: September 13, 2016, 10:27:13 pm
content: How much speed do you need ? You can use a USB->RS232 adapter + 8-bit shift register.I think you'll have more luck with the USB part if posting in the Microcontrollers & FPGAs forum

author: noname4me
author_rank: Regular Contributor
timestamp: September 13, 2016, 10:56:58 pm
content: Thanks - Can the moderators move it there please?I don't need it to be fast at the moment - just so that I can send commands in hex to the LCD screen.It would be nice if I could write this code once and recycle it for other stuff in the future - hence the long way round about doing this.

author: MosherIV
author_rank: Super Contributor
timestamp: September 14, 2016, 06:41:15 am
content: QuoteIn which case, concentrate on the lcd and spi code. Is the lcd accepting spi messages (is the spi driver returning error or timing out)?Is it the command sequence for the lcd that is not correct?Trying to get 2 things working symutaneously while neither work is going to be very hard work.If you do not need high speed serial, the USB CDC will be fine, the bug is to do with transfering data at high speed or lots of data.

author: noname4me
author_rank: Regular Contributor
timestamp: September 14, 2016, 10:01:59 am
content: Quote from: MosherIV on September 14, 2016, 06:41:15 amYes...during the initialisation i believe.It's one of these lcds from ebay for which i am not quite sure of the driver chip.I'll post what I've done so far later today...but i know the invert display and turn display on work.ThanksSent from my SM-G935F using Tapatalk

author: noname4me
author_rank: Regular Contributor
timestamp: September 14, 2016, 07:16:56 pm
content: Hi,The following is all the code that I have for this. I am using Keil V5.Code:#include "stm32f1xx_hal.h"#include "usb_device.h"/* USER CODE BEGIN Includes */#define LCD_RST_1 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1,GPIO_PIN_SET);#define LCD_RST_0 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1,GPIO_PIN_RESET);#define LCD_CMD HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3,GPIO_PIN_RESET);#define LCD_DATA HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3,GPIO_PIN_SET);#define CMD 0#define DATA 1/* USER CODE END Includes *//* Private variables ---------------------------------------------------------*/SPI_HandleTypeDef hspi1;/* USER CODE BEGIN PV *//* Private variables ---------------------------------------------------------*/uint16_t buffer_tx;uint8_t buffer_rx;uint8_t usb_buf_rx;uint8_t usb_buf_tx;uint8_t screenbuffer;/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);void Error_Handler(void);static void MX_GPIO_Init(void);static void MX_SPI1_Init(void);/* USER CODE BEGIN PFP *//* Private function prototypes -----------------------------------------------*/void lcdSendData(unsigned int lcddata_type,unsigned char data);void lcd_reset(void);void lcd_init(void);void lcdRecData(unsigned int lcddata_type);void lcdSendRecData(unsigned int lcddata_type,unsigned char data);/* USER CODE END PFP *//* USER CODE BEGIN 0 */void lcdRecData(unsigned int lcddata_type){if (lcddata_type == DATA) {LCD_DATA;HAL_SPI_Receive(&hspi1, buffer_rx, 3,50);HAL_Delay(100);screenbuffer = ((uint8_t)&buffer_rx);}else if (lcddata_type == CMD){ //this will probably never be used, because it makes no senseLCD_DATA;HAL_SPI_Receive(&hspi1, buffer_rx, 3,50);screenbuffer = ((uint8_t)&buffer_rx);}}void lcdSendData(unsigned int lcddata_type, unsigned char data){if (lcddata_type == DATA) {LCD_DATA;HAL_SPI_Transmit(&hspi1, &data, 1,50);HAL_Delay(100);}else if (lcddata_type == CMD){LCD_CMD;HAL_SPI_Transmit(&hspi1, &data, 1,50);HAL_Delay(100);}}void usb_tx(uint8_t data){CDC_Transmit_FS(&data, 1);HAL_Delay(100);}unsigned char usb_rx(){unsigned char scrout;CDC_Transmit_FS(usb_buf_rx,4);HAL_Delay(100);scrout = (unsigned char)(usb_buf_rx);return scrout;}void lcdSendRecData(unsigned int lcddata_type,unsigned char data){if (lcddata_type == DATA) {LCD_DATA;HAL_SPI_TransmitReceive(&hspi1, &data, buffer_rx, 4,50);HAL_Delay(100);}else if (lcddata_type == CMD){LCD_CMD;HAL_SPI_TransmitReceive(&hspi1, &data, buffer_rx, 4,140);HAL_Delay(1000);}HAL_Delay(10);}void lcd_reset(void){LCD_RST_1;HAL_Delay(150);LCD_RST_0;HAL_Delay(150);LCD_RST_1;HAL_Delay(150);}void lcd_init(void){lcd_reset();lcdSendData(CMD,0x01); //software reset//HAL_Delay(150); //Delay 150 ms to allow resetlcdSendData(CMD,0x11); //sleep out// HAL_Delay(130);lcdSendData(CMD,0x3A); //interface pixel format// HAL_Delay(130);lcdSendData(DATA,0x05); //16bit colour// HAL_Delay(130);lcdSendData(CMD,0x29); //display invert// HAL_Delay(130);lcdSendData(CMD,0x21);// HAL_Delay(130);}void lcd_sendFour(unsigned int lcddata_type, unsigned char cmnd, unsigned char data){if (lcddata_type == DATA) {LCD_DATA;HAL_SPI_Transmit(&hspi1, &data, 1,50);//HAL_SPI_(&hspi1,&data,3,50);HAL_Delay(100);}else if (lcddata_type == CMD){LCD_CMD;HAL_SPI_Transmit(&hspi1, &cmnd, 1,50);LCD_DATA;HAL_SPI_Transmit(&hspi1,&data,3,50);}}// Function to read LCD Screen IDvoid lcd_readID(void) {lcdSendData(CMD,0x04);lcdRecData(DATA);HAL_Delay(10);}void lcd_pix(unsigned char X, unsigned char Y, unsigned int colour){lcdSendData(CMD,0x2A);//HAL_Delay(130);//lcdSendData(DATA,0x00);//HAL_Delay(130);lcdSendData(DATA,X);lcdSendData(DATA,X);lcdSendData(DATA,X);lcdSendData(DATA,X);//HAL_Delay(130);lcdSendData(CMD,0x2B);lcdSendData(DATA,Y);lcdSendData(DATA,Y);lcdSendData(DATA,Y);lcdSendData(DATA,Y);//HAL_Delay(130);//lcdSendData(DATA,0x00);//HAL_Delay(130);//HAL_Delay(130);lcdSendData(CMD,0x2C);//HAL_Delay(130);// lcdSendData(DATA,0x00);//HAL_Delay(130);//lcdSendData(DATA,(colour)>> 8);lcdSendData(DATA,(colour));lcdSendData(DATA,(colour));//HAL_Delay(130);//lcdSendData(DATA,colour);//lcdSendData(DATA,colour & 0xFFFF);//HAL_Delay(130);}void lcd_at(unsigned char startX, unsigned char startY,unsigned char stopX, unsigned char stopY){lcdSendData(CMD,0x2A);lcdSendData(DATA,0x00);lcdSendData(DATA,startX);lcdSendData(DATA,0x00);lcdSendData(DATA,stopX);lcdSendData(CMD,0x2B);lcdSendData(DATA,0x00);lcdSendData(DATA,startY);lcdSendData(DATA,0x00);lcdSendData(DATA,stopY);}/* USER CODE END 0 */int main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration----------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* Configure the system clock */SystemClock_Config();/* Initialize all configured peripherals */MX_GPIO_Init();MX_SPI1_Init();MX_USB_DEVICE_Init();/* USER CODE BEGIN 2 *///lcd_reset();lcd_init();// lcd_readID();//Write a function that can send 16 bits of info/read 16 bits of info - 32 as well.HAL_Delay(150);//lcd_readID();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */unsigned char lcdcmd;// while (1){HAL_Delay(1000);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */}/** System Clock Configuration*/void SystemClock_Config(void){RCC_OscInitTypeDef RCC_OscInitStruct;RCC_ClkInitTypeDef RCC_ClkInitStruct;RCC_PeriphCLKInitTypeDef PeriphClkInit;RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){Error_Handler();}HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);/* SysTick_IRQn interrupt configuration */HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);}/* SPI1 init function */static void MX_SPI1_Init(void){hspi1.Instance = SPI1;hspi1.Init.Mode = SPI_MODE_MASTER;hspi1.Init.Direction = SPI_DIRECTION_1LINE;hspi1.Init.DataSize = SPI_DATASIZE_8BIT;hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi1.Init.TIMode = SPI_TIMODE_DISABLE;hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi1.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi1) != HAL_OK){Error_Handler();}}/** Configure pins as* Analog* Input* Output* EVENT_OUT* EXTI* Free pins are configured automatically as Analog (this feature is enabled through* the Code Generation settings)*/static void MX_GPIO_Init(void){GPIO_InitTypeDef GPIO_InitStruct;/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pins : PC13 PC14 PC15 */GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/*Configure GPIO pins : PA0 PA2 PA6 PA8PA9 PA10 PA15 */GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_6|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_15;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pins : PA1 PA3 */GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_3;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pins : PB0 PB1 PB2 PB10PB11 PB12 PB13 PB14PB15 PB3 PB4 PB5PB6 PB7 PB8 PB9 */GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1|GPIO_PIN_3, GPIO_PIN_RESET);}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief This function is executed in case of error occurrence.* @param None* @retval None*/void Error_Handler(void){/* USER CODE BEGIN Error_Handler *//* User can add his own implementation to report the HAL error return state */while(1){}/* USER CODE END Error_Handler */}#ifdef USE_FULL_ASSERT/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/void assert_failed(uint8_t* file, uint32_t line){/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */}#endif/*** @}*//*** @}*//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

author: noname4me
author_rank: Regular Contributor
timestamp: September 14, 2016, 07:27:47 pm
content: When I try and compile that, it complains that the CDC_Receive_FS() is being declared implicitly. When I checked the usbd_cdc_it.h file that command is missing from it.I know the SPI is working because I have used a logic analyser to check what the NSS, Reset, C/D, MOSI and SCK lines are doing when I send SPI commands.I am able to read the LCD ID when I send the correct command.https://community.particle.io/t/on-going-problems-with-cheap-st7735-tft-displays/1That is the LCD screen that I have. I think it uses the ST7735 chip - but I really don't know how to get the initialisation correct. I have read the datasheet, and my head is letting out smoke from trying to understand what to do.I tried reading the ADAFruit libraries, and even heavily modifying them so that they work for my purpose - to no avail.I still don't understand how to initialise the screen. When I run my code, when the LCD ON command is sent, it shows speckled colours all over the screen. When I sent the invert command it inverts it as expected.This leads me to believe that I almost have it, but I wanted to use the USB CDC serial connection to try different sequences of commands and data.This will also be useful to me in the future when I want to debug other things that will be connected via SPI, and if I want to send configuration data from a PC to my microcontroller.Any tips/things that I can read?

author: MosherIV
author_rank: Super Contributor
timestamp: September 14, 2016, 07:48:04 pm
content: If you have turn on the screen and it has speckly colours all over it, it means that the screen is working but you have not filled it yet with an image, by image I mean that you should create an image buffer that is sent to the display.Sorry have not looked at your code.For the USB CDC, try searching for the function declaration, I do seem to remember it is declared in a higher up layer header file, the USB is a communications stack with many layers.You could add the definition into the header file yourself.The last trick, though I always hated it because you then have no idea where the actual code is, is to do a 'extern ' declaration, this tells the complier to ignore the fact that it cannot find the definiton and let the linker look for the code later.

author: noname4me
author_rank: Regular Contributor
timestamp: September 14, 2016, 08:21:31 pm
content: Thanks for your help.How do I add something to the header file?I've never actually done this before, and I tried hacking it so that it looks a bit like the transmit function, but I don't think it looks correct.The transmit function is like:uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);So does the receive function look like:uint8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len);?The .c file defines it as:static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len){/* USER CODE BEGIN 6 */USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf);USBD_CDC_ReceivePacket(&hUsbDeviceFS);return (USBD_OK);/* USER CODE END 6 */Could you also give me a link to read on how to deal with the size limitations on the CDC transmission?Thanks

author: MosherIV
author_rank: Super Contributor
timestamp: September 14, 2016, 09:29:33 pm
content: QuoteAh, the problem is the 'static' in front of the function in the source.This means that it is only accessible in that source file.Is it being called by another function in that file?There no size limit per say to USB CDC, it is a serial stream.However, there is something like (I do not remember exactly) 512 byte buffer for the USB end point.The comms stack is suppose to empty the end point buffer up to the next layer so that data flows.The ST stack does not always work properly, works most of the time.For your purposes, do not worry about it. Do not try to dump a picture to the screen, this may cause the problem. The diference in data rates will not suit spi anyway.

author: newbrain
author_rank: Super Contributor
timestamp: September 14, 2016, 10:40:47 pm
content: That function is static as it must not be called directly by the user.It is, in fact, a callback that is usedby the driverwhen the bulk OUT endpoint (so, the input to the MCU, confusing, isn't it?) has received data.The code must be supplied by the user, though, and she can do whatever they like with the received data.Until USBD_CDC_ReceivePacket() is called again, the driver will NACK further incoming packets.So, in your case, you could transmit the received data over SPI, and then call USBD_CDC_ReceivePacket() before leaving the receive routine.It's an event/callback style of programming, a bit different from a straightforward busy-loop waiting to receive something and then acting on it.If you want to handle that in an endless loop in main() you should set a (volatile) flag in the receive routine, check for it in main and transmit over SPI, and the call USBD_CDC_ReceivePacket().Beware of leaving the USB device hanging for too long, though. I don't think it will be happy.Look at the CDC example in the cube SW directory, and try to follow it.Edit: posted too soon.One piece of advice, though: heed MosherIV suggestion of tackling one problem at the time.

author: noname4me
author_rank: Regular Contributor
timestamp: September 18, 2016, 10:24:22 pm
content: Hi,Thanks for your help - I've not forgotten to get back to you, but have been really busy so I haven't had time to test anything yet.I know the SPI is correct - but I don't know what the correct sequence to initate the LCD is. I've never actually done this sort of stuff before, so it's a steep learning curve.I'll hopefully have something done soon - appreciate the help guys.Thanks

author: noname4me
author_rank: Regular Contributor
timestamp: September 23, 2016, 08:35:18 pm
content: Hi,Ok, so I've got the Rx and Tx working - I was using the wrong function, as mentioned previously in the thread.I have a slightly related issue in that I can send using Realterm the string "Hello" and get the function to spit "Hello" back at me.However, if I try and type it in to the serial program (for e.g. as someone would do using Teraterm), it only spits back the last letter typed - in this case "o".I am using the Rx function in polling mode - I think I get why it's happening (because it's taking the last input and spitting it back at me) but I don't know if any way to get around this.Any help please?Thanks

author: MosherIV
author_rank: Super Contributor
timestamp: September 23, 2016, 09:19:11 pm
content: Realterm might be echoing what you typed and fooling you.Start by having the stm32 transmit a steady stream, eg get it to display 'hello' or just a count.Once that is working, then do the echo program with 'received ' added before echoing back what was received, that way you know it was sent by the stm32 and not just the terminal program echoing what was typed.

author: noname4me
author_rank: Regular Contributor
timestamp: September 24, 2016, 11:27:23 am
content: I've confirmed that it is taking this as an input by causing the tx function to repeatedly output the last received information.The repetition rate of the text appearing in the terminal corresponds to the delay i have programmed into the function.To my mind, it seems clumsy to have to read each character, bitshift the register storing that data to make room for the next letter?That's the only solution i can think of...any better way to do this?Sent from my SM-G935F using Tapatalk

author: MosherIV
author_rank: Super Contributor
timestamp: September 24, 2016, 09:29:20 pm
content: QuoteActually it is standard to to buffer or even double buffer comms. You will hear/read about 'stacks' and at each level or layer of stack there will be a buffer.So, your transmit function should have a buffer to hold strings to send to the usb tx, it should hold on to the string if the usb is not ready to receive it. This way you can send more characters than was received.