0
\$\begingroup\$

I'm using Nucleo STM32F401RE board.

I have a small issue. I have connected SPI connections + two potentiometers and FreeRTOS. But I can't read the ADCs. I wonder why?

I have created an array called

uint32_t adcData[2]; // Two ADC inputs

Then I have started the ADC with DMA. The ADC triggers on a timer.

// Init ADC with DMA - The ADC have DMA with a time trigger
HAL_TIM_Base_Start(&htim2);
HAL_ADC_Start_DMA(&hadc1, adcData, 2);

But when I read the adcData in the thread ControlTask, I'll get this. The first element have a very large number. The second element does not change at all. Notice that the both threads are running because r[0] is showing the value 250 all the time.

enter image description here

The code is:

  r[0] = saturation((adcData[0] - 512) / 2, -250, 250);  // This shows 250 because adcData[0] is a very large number, but adcData[1] remains initial 600.

The init of the peripherals looks like this:

  MX_GPIO_Init();
  MX_DMA_Init(); // <-- This one is before ADC1_init()
  MX_USART2_UART_Init();
  MX_ADC1_Init();
  MX_SPI1_Init();
  MX_TIM2_Init();
  MX_SPI2_Init();
  MX_TIM5_Init();

Timer 2 configuration: enter image description here

ADC 1 configuration: enter image description here

And DMA for ADC1 configuration. enter image description here

FreeRTOS configuration enter image description here

Complete code:

#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "MCP2515/CANSPI.h"
#include "stdbool.h"
#include "LCD_ILI9341/LCDCore/LCD_ILI9341.h"
#include "LCD_ILI9341/LCDTools/LCDTools.h"
#include "FlashMemory/ReadWrite.h"
#include "CControl/Headers/Functions.h"
#include "math.h"
#include "Encoder/Encoder.h"

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

SPI_HandleTypeDef hspi1;
SPI_HandleTypeDef hspi2;

TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim5;

UART_HandleTypeDef huart2;

/* Definitions for LCDTask */
osThreadId_t LCDTaskHandle;
const osThreadAttr_t LCDTask_attributes = {
  .name = "LCDTask",
  .priority = (osPriority_t) osPriorityBelowNormal,
  .stack_size = 3000 * 4
};
/* Definitions for ControlTask */
osThreadId_t ControlTaskHandle;
const osThreadAttr_t ControlTask_attributes = {
  .name = "ControlTask",
  .priority = (osPriority_t) osPriorityBelowNormal1,
  .stack_size = 500 * 4
};
/* USER CODE BEGIN PV */
uCAN_MSG txMessage;
uCAN_MSG rxMessage;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_ADC1_Init(void);
static void MX_SPI1_Init(void);
static void MX_TIM2_Init(void);
static void MX_SPI2_Init(void);
static void MX_TIM5_Init(void);
void LCDTaskStart(void *argument);
void ControlTaskStart(void *argument);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
bool update_main_frame = true; // Set this to true, then Win95 screen will disappear later
bool decimalbutton_show = false;
bool minusbutton_show = false;
bool closedloop_on = true; // Start with control mode
bool only_move_array = false;
bool clear_plot = false;

float gain = 0.0;
float valve_diff_gain = 0.0;
float limit = 0.0;
float new_output_float = 0;
float new_input_float = 0;

ILI9341_SPI spi;
Encoder encoder;
uint32_t adcData[2]; // Two ADC inputs
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
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();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  MX_ADC1_Init();
  MX_SPI1_Init();
  MX_TIM2_Init();
  MX_SPI2_Init();
  MX_TIM5_Init();
  /* USER CODE BEGIN 2 */

    // Init CAN
    CANSPI_Initialize();

    // Init ADC with DMA - The ADC have DMA with a time trigger
    HAL_TIM_Base_Start(&htim2);
    HAL_ADC_Start_DMA(&hadc1, adcData, 2);

    // Init encoder
    HAL_TIM_Encoder_Start(&htim5, TIM_CHANNEL_ALL);
    Encoder_init(&encoder, &htim5, 30, 100);

    // Set the address and sector for F401RE CPU where we are going to store the settings. Look at chapter 3.3 at document RM0368 for STM32F446XX processors
    FlashSetSectorAddrs(7, 0x08060000);

    // Init LCD
    ILI9341_Init(&spi, &hspi2, LCD_CS_GPIO_Port, LCD_CS_Pin, LCD_DC_GPIO_Port, LCD_DC_Pin, LCD_RST_GPIO_Port, LCD_RST_Pin, TS_CS_GPIO_Port, TS_CS_Pin);

    // Show welcome screen
    ILI9341_setRotation(&spi, 2);
    ILI9341_printImage(&spi, 0, 0, 320, 240, windowsME_intro, 640 * 240 * sizeof(uint8_t));
    HAL_Delay(5000);

    // Load the user configurations
    float rdBuf[7];
    FlashReadN(0, rdBuf, 7, DATA_TYPE_FLOAT);
    spi.myTS_Calibrate.Scale_X = rdBuf[0];
    spi.myTS_Calibrate.Scale_Y = rdBuf[1];
    spi.myTS_Calibrate.Bias_X = rdBuf[2];
    spi.myTS_Calibrate.Bias_Y = rdBuf[3];
    gain = rdBuf[4];
    limit = rdBuf[5];
    valve_diff_gain = rdBuf[6];

    // Calibrate the touch if blue Nucleo board button is pressed
    if (HAL_GPIO_ReadPin(CALIBRATE_GPIO_Port, CALIBRATE_Pin) == GPIO_PIN_RESET) {
        TSC2046_Calibrate(&spi);
    }

    // Create initial frame
    show_main_frame(&spi, closedloop_on, update_main_frame);

  /* USER CODE END 2 */

  /* Init scheduler */
  osKernelInitialize();

  /* USER CODE BEGIN RTOS_MUTEX */
    /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
    /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
    /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
    /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of LCDTask */
  LCDTaskHandle = osThreadNew(LCDTaskStart, NULL, &LCDTask_attributes);

  /* creation of ControlTask */
  ControlTaskHandle = osThreadNew(ControlTaskStart, NULL, &ControlTask_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
    /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* Start scheduler */
  osKernelStart();
 
  /* We should never get here as control is now taken by the scheduler */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

    while (1) {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

    }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  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_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief ADC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_10B;
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 2;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
  */
  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

/**
  * @brief SPI1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
  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();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

/**
  * @brief SPI2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI2_Init(void)
{

  /* USER CODE BEGIN SPI2_Init 0 */

  /* USER CODE END SPI2_Init 0 */

  /* USER CODE BEGIN SPI2_Init 1 */

  /* USER CODE END SPI2_Init 1 */
  /* SPI2 parameter configuration*/
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */

  /* USER CODE END SPI2_Init 2 */

}

/**
  * @brief TIM2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 83;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 1000;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}

/**
  * @brief TIM5 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM5_Init(void)
{

  /* USER CODE BEGIN TIM5_Init 0 */

  /* USER CODE END TIM5_Init 0 */

  TIM_Encoder_InitTypeDef sConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM5_Init 1 */

  /* USER CODE END TIM5_Init 1 */
  htim5.Instance = TIM5;
  htim5.Init.Prescaler = 83;
  htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim5.Init.Period = 65535;
  htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
  sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC1Filter = 0;
  sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC2Filter = 0;
  if (HAL_TIM_Encoder_Init(&htim5, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM5_Init 2 */

  /* USER CODE END TIM5_Init 2 */

}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/** 
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void) 
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA2_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, LCD_RST_Pin|LCD_DC_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, TS_CS_Pin|LCD_CS_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(MCP2515_CS_GPIO_Port, MCP2515_CS_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : CALIBRATE_Pin */
  GPIO_InitStruct.Pin = CALIBRATE_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(CALIBRATE_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : LCD_RST_Pin LCD_DC_Pin */
  GPIO_InitStruct.Pin = LCD_RST_Pin|LCD_DC_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : TS_CS_Pin LCD_CS_Pin */
  GPIO_InitStruct.Pin = TS_CS_Pin|LCD_CS_Pin;
  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);

  /*Configure GPIO pin : MCP2515_CS_Pin */
  GPIO_InitStruct.Pin = MCP2515_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(MCP2515_CS_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */
void readCANMessageAndSendViaUART() {
    if (CANSPI_Receive(&rxMessage)) {
        txMessage.frame.idType = rxMessage.frame.idType;
        txMessage.frame.id = rxMessage.frame.id;
        txMessage.frame.dlc = rxMessage.frame.dlc;
        txMessage.frame.data0++;
        txMessage.frame.data1 = rxMessage.frame.data1;
        txMessage.frame.data2 = rxMessage.frame.data2;
        txMessage.frame.data3 = rxMessage.frame.data3;
        txMessage.frame.data4 = rxMessage.frame.data4;
        txMessage.frame.data5 = rxMessage.frame.data5;
        txMessage.frame.data6 = rxMessage.frame.data6;
        txMessage.frame.data7 = rxMessage.frame.data7;
        char idMessage[120];
        sprintf(idMessage, "idType=%02x, id=%02x %02x %02x %02x, dlc=%02x, byte0=%02x, byte1=%02x, byte2=%02x, byte3=%02x, byte4=%02x, byte5=%02x, byte6=%02x, byte7=%02x\n",
                rxMessage.frame.idType, rxMessage.frame.id >> 24, rxMessage.frame.id >> 16, rxMessage.frame.id >> 8, rxMessage.frame.id, rxMessage.frame.dlc, rxMessage.frame.data0,
                rxMessage.frame.data1, rxMessage.frame.data2, rxMessage.frame.data3, rxMessage.frame.data4, rxMessage.frame.data5, rxMessage.frame.data6, rxMessage.frame.data7);
        HAL_UART_Transmit(&huart2, (uint8_t*) idMessage, sizeof(idMessage), 50);
    }
}

void sendCANControlMessage(uint8_t DA, uint8_t SA, uint8_t state, uint8_t position) {
    txMessage.frame.idType = dEXTENDED_CAN_MSG_ID_2_0B;
    txMessage.frame.id = 0x0CFE | (DA << 8) | SA; // 0x0CFE "DA" "SA"
    txMessage.frame.dlc = 8;
    txMessage.frame.data0 = position;
    txMessage.frame.data1 = 0xFF;
    txMessage.frame.data2 = state;
    txMessage.frame.data3 = 0xFF;
    txMessage.frame.data4 = 0xFF;
    txMessage.frame.data5 = 0xFF;
    txMessage.frame.data6 = 0xFF;
    txMessage.frame.data7 = 0xFF;
    CANSPI_Transmit(&txMessage);
}
/* USER CODE END 4 */

/* USER CODE BEGIN Header_LCDTaskStart */
/**
 * @brief  Function implementing the LCDTask thread.
 * @param  argument: Not used
 * @retval None
 */
/* USER CODE END Header_LCDTaskStart */
void LCDTaskStart(void *argument)
{
  /* USER CODE BEGIN 5 */
    /* Infinite loop */
    for (;;) {      // Read the LCD touch
        TSC2046_GetTouchData(&spi);
        uint8_t isPressed = spi.myTsData.isPressed;
        uint16_t X = spi.myTsData.X;
        uint16_t Y = spi.myTsData.Y;
        if (isPressed == true) {
            // Check which button we are pressing on on
            if (X >= 8 && X <= 37 && Y >= 8 && Y <= 37) {
                // Learning gain
                decimalbutton_show = true;
                minusbutton_show = false;
                show_num_pad_frame(&spi, decimalbutton_show, minusbutton_show, &gain, "Set gain");
                update_main_frame = true;
                show_main_frame(&spi, closedloop_on, update_main_frame);
            } else if (X >= 8 && X <= 37 && Y >= 55 && Y <= 94) {
                // Saturation
                decimalbutton_show = false;
                minusbutton_show = false;
                show_num_pad_frame(&spi, decimalbutton_show, minusbutton_show, &limit, "Set saturation");
                update_main_frame = true;
                show_main_frame(&spi, closedloop_on, update_main_frame);
            } else if (X >= 8 && X <= 37 && Y >= 100 && Y <= 139) {
                // ADC gain
                decimalbutton_show = true;
                minusbutton_show = false;
                show_num_pad_frame(&spi, decimalbutton_show, minusbutton_show, &valve_diff_gain, "Set ADC gain");
                update_main_frame = true;
                show_main_frame(&spi, closedloop_on, update_main_frame);
            } else if (X >= 8 && X <= 37 && Y >= 146 && Y <= 185) {
                // Open loop or closed loop
                if (closedloop_on == true)
                    closedloop_on = false;
                else
                    closedloop_on = true;
                update_main_frame = false;
                osDelay(300); // Prevent double click
                show_main_frame(&spi, closedloop_on, update_main_frame);
            } else if (X >= 8 && X <= 37 && Y >= 193 && Y <= 232) {
                // Question dialog
                uint8_t choice = show_question_save_settings_dialog(&spi); // Return 1 as YES and 0 as NO
                if (choice == 1) {
                    // Save the touch calibration and the user settings
                    float wrBuf[7] = { spi.myTS_Calibrate.Scale_X, spi.myTS_Calibrate.Scale_Y, spi.myTS_Calibrate.Bias_X, spi.myTS_Calibrate.Bias_Y, gain, limit, valve_diff_gain };
                    FlashEraseSector(); // Must clear first
                    FlashWriteN(0, wrBuf, 7, DATA_TYPE_FLOAT);
                }

                // Restore to normal again
                update_main_frame = true;
                show_main_frame(&spi, closedloop_on, update_main_frame);
            }
        } else {
            // Maximum plot can show is value 203
            uint16_t new_output_uint = new_output_float/3 + 83; // from 0 to 166
            uint16_t new_input_uint = new_input_float/3 + 83;
            show_plot_frame(&spi, new_input_float, new_output_float, new_input_uint, new_output_uint, only_move_array, clear_plot);
        }
        osDelay(1);
    }
  /* USER CODE END 5 */ 
}



/* USER CODE END Header_ControlTaskStart */
void ControlTaskStart(void *argument)
{
  /* USER CODE BEGIN ControlTaskStart */
    /* Infinite loop */
    uint8_t RDIM = 1;
    float I1[RDIM];
    float I2[RDIM];
    float r[RDIM + 1]; // Special case, we won't control with r[1]
    float u[RDIM];
    float y[RDIM];
    memset(u, 0, RDIM * sizeof(float));
    memset(r, 0, RDIM * sizeof(float));
    memset(y, 0, RDIM * sizeof(float));
    memset(I1, 0, RDIM * sizeof(float));
    memset(I2, 0, RDIM * sizeof(float));

    // We are using ADC0 as a differential ADC as well, just to turn MISO system into SISO system
    float differentialADC0 = 0;
    float pastADC0 = 0;
    const uint8_t delay_iterations = 30; // If we got noise, then we need to have a delay iteration
    uint8_t i = 0;

    // Input signals for the sonceboz motors
    float positionValve0;
    float positionValve1;
    adcData[0] = 300;
    adcData[1] = 600;
    uint8_t action;
    for (;;) {
        // Read references and output
        r[0] = saturation((adcData[0] - 512) / 2, -250, 250); // Sonzeboz want command from 0 to 250, but we are using -250 to 250
        r[1] = saturation((adcData[1] - 512) / 2, -250, 250); // This will not be used for control mode
        y[0] = saturation(Encoder_getSpeed(&encoder)/1500.0, -250, 250); // Divide with 1500 because it's average RPM's here

        // Set the plot values
        new_input_float = r[0];
        new_output_float = y[0];

        // Control mode or manual mode
        if (closedloop_on == true) {
            // Take a sample of how fast our ADC0 are
            if (i >= delay_iterations) {
                differentialADC0 = r[0] - pastADC0;
                pastADC0 = r[0];
                i = 0;
            } else {
                i++;
            }

            // Find the control input
            mrac(limit, gain, y, u, r, I1, I2, RDIM);

            // Create the control signals - With differential mode
            if (r[0] > 0) {
                positionValve0 = r[0];
                positionValve1 = r[0] - valve_diff_gain * differentialADC0;
                action = 0x1; // Extend
            } else if (r[0] < 0) {
                positionValve0 = r[0] - valve_diff_gain * differentialADC0;
                positionValve1 = r[0];
                action = 0x2; // Retract
            } else {
                positionValve0 = 0;
                positionValve1 = 0;
                action = 0x0; // Neutral
            }
        } else {
            positionValve0 = r[0];
            if (positionValve0 > 0) {
                action = 0x1; // Extend
            } else if (positionValve0 < 0) {
                action = 0x2; // Retract
            } else {
                action = 0x0; // Neutral
            }

            positionValve1 = r[1]; // Now we using the other potentiometer
            if (positionValve1 > 0) {
                action = 0x1; // Extend
            } else if (positionValve1 < 0) {
                action = 0x2; // Retract
            } else {
                action = 0x0; // Neutral
            }
        }

        // Control them now
        sendCANControlMessage(0x30, 0x22, action, fabsf(positionValve0)); // 0 to 250 only for Sonceboz
        sendCANControlMessage(0x31, 0x23, action, fabsf(positionValve1));

        osDelay(1);
    }
  /* USER CODE END ControlTaskStart */
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

  if (htim->Instance == TIM3) {
    HAL_IncTick();
  }

}


void Error_Handler(void)
{

}

#ifdef  USE_FULL_ASSERT

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,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
\$\endgroup\$
  • \$\begingroup\$ This may not be the cause of your trouble, but you should declare your adcData array as volatile. \$\endgroup\$ – brhans Jul 25 at 20:09
  • \$\begingroup\$ @brhans Tried that. Still the same. \$\endgroup\$ – Daniel Mårtensson Jul 25 at 20:11
  • \$\begingroup\$ The ADC gives 16-bit values. Do you read 16-bit or 32-bit or 8-bit values from it? Also, the target array is an array of 32-bit values. Even if you do read two 16-bit values, they likely are set to the single 32-bit entry in the array, unless the DMA is told to convert it somehow. \$\endgroup\$ – Justme Jul 25 at 20:39
  • \$\begingroup\$ @Justme and brhans. I solved it. I just wrote volatile with this code as well HAL_ADC_Start_DMA(&hadc1, (uint32_t*) adcData, 2); Forgot to use the casting :) \$\endgroup\$ – Daniel Mårtensson Jul 25 at 20:41
  • \$\begingroup\$ @Justme I'm reading 10-bit values. So I'm using volatile uint16_t adcData[2] at the moment. \$\endgroup\$ – Daniel Mårtensson Jul 25 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.