I have been using STM32 IDE which incorporates the CUBE MX.
Using the HAL code I am able to read on three pins using a separate ADC for each
pin.
I have started all the ADC's at the same time and then I poll for completion.
I am I correct in thinking these ADC reads should be practically simultaneous (i.e.
they all read in at a very similar time)?
Code fragment below.
Using a NUCLEO-STM32 F446RE btw.
MX_ADC1_Init();
MX_ADC2_Init();
MX_ADC3_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
static int flip,sysclk=0,old_sysclk=0,adc1,adc2,adc3;//adc3_0,adc3_1,adc3_2, adc_pstat0,
int adc_pstat1, adc_pstat2, adc_pstat3;
flip ^= 1;
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0/*|GPIO_PIN_2|GPIO_PIN_6*/, flip);
HAL_ADC_Start(&hadc3);
HAL_ADC_Start(&hadc2);
HAL_ADC_Start(&hadc1);
adc_pstat1 = HAL_ADC_PollForConversion(&hadc1, 10);
adc_pstat3 = HAL_ADC_PollForConversion(&hadc3, 10); // should already be done!
adc_pstat2 = HAL_ADC_PollForConversion(&hadc2, 10); // should already be done!
adc3 = HAL_ADC_GetValue(&hadc3);
adc2 = HAL_ADC_GetValue(&hadc2);
adc1 = HAL_ADC_GetValue(&hadc1);
if (adc_pstat2 ||adc_pstat3)
asm("\t nop");
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
sysclk = HAL_GetTick();
if ( (sysclk - 1000) > old_sysclk ){
//printf("nucleo F446 0x%X adc3_0 0x%X adc3_1 0x%X adc3_2 0x%X\n",sysclk,adc3_0,adc3_1,adc3_2);
printf("|->nucleo F446 sysclk=0x%X adc1=0x%X adc2=0x%X adc3=0x%X\n",sysclk,adc1,adc2,adc3);
old_sysclk = sysclk;
}
}
/* USER CODE END 3 */
}
Your code does not read it simultaneously as you do not start the ADCs at the sime moment.
You need to use the same external trigger for all of them or use ADCs in the double or tripple mode.
I found a way to do this easily. I set up a timer and used to to update a trigger event. The ADC's then triggered off this event (TIM8_TRGO).
Using this trigger I can get two or three ADCs to read simultaneously.
The Dual Simultaneous mode seems to support ADCs reading at the same time
Related
I'm programming the Atmega64M1. The access on the EEPROM is described in the datasheet, and I have no issues writing it or reading it.
In the datasheet it is said to wait for completing of previous write before reading or writing the eeprom :
{
/* Wait for completion of previous write */
while(EECR & (1<<EEPE))
;
/* Set up address and Data Registers */
EEAR = uiAddress;
EEDR = ucData;
/* Write logical one to EEMPE */
EECR |= (1<<EEMPE);
/* Start eeprom write by setting EEPE */
EECR |= (1<<EEPE);
}
My question is : is there a chance that the while loop doesn't stop ? The EEPE bit is supposed to be cleared by hardware, but is it a good practice to add a software verification to make sure that we eventually exit the loop ?
Something like:
int i = 0;
/* Wait for completion of previous write */
while((EECR & (1<<EEPE)) && (i < 100))
{
i++;
}
I've been trying to configure & run hardware timer over SAML21 MCU to generate a 100ms delay i.e. ISR is supposed to hit at every 100ms. But it is observed that after starting the timer ISR is hitting at every 10us and changing the Prescaler & Compare register values isn't creating any difference in the 10us interval. Please review my code and let me know where I'm doing wrong.
I'm trying to configure Timer1(TC1) in 16bit mode, using GCLK_GENERATOR_1 as its clock source running at 8MHz frequency(CPU Main Clock:16MHz). The timer is expected to cause overflow interrupt every 100ms.
TcCount16 *tc_hw1 = NULL; /* Pointer to TC1 hardware registers Initilized later */
void init_timer1(void)
{
struct tc_module tc_inst1;
struct tc_config conf_tc1;
tc_get_config_defaults(&conf_tc1);
conf_tc1.clock_source = GCLK_GENERATOR_1;
conf_tc1.clock_prescaler = TC_CLOCK_PRESCALER_DIV64; /* 8MHz/64 = 125KHz*/
conf_tc1.reload_action = TC_RELOAD_ACTION_GCLK;
conf_tc1.counter_size = TC_COUNTER_SIZE_16BIT;
conf_tc1.count_direction = TC_COUNT_DIRECTION_UP;
conf_tc1.counter_16_bit.value = 0x0000;
/** Rest of the settings are used as defaults **/
while (tc_init(&tc_inst1, TC1, &conf_tc1) != STATUS_OK){
}
tc_set_top_value(&tc_inst1, 12500); /* Set counter compare top value */
/* Enable interrupt & Set Priority */
tc_hw1 = &(tc_inst1.hw->COUNT16); /* Initialize pointer to TC1 hardware register */
tc_hw1->INTENSET.reg |= TC_INTFLAG_OVF; /* Enable Overflow Interrupt */
NVIC_SetPriority(TC1_IRQn, 2);
NVIC_EnableIRQ(TC1_IRQn);
tc_enable(&tc_inst1); /*Start The TIMER*/
}
void TC1_Handler(void)
{
if((tc_hw1->INTFLAG.reg) & (TC_INTFLAG_OVF))
{
port_pin_toggle_output_level(PIN_PB03);
}
system_interrupt_clear_pending(SYSTEM_INTERRUPT_MODULE_TC1);
}
Debugger Information: I can see that the timer register is configured correctly but the COUNT register is not incrementing itself every time I pause to capture the debug info it shows only 0x0000 values.
Please help. Thanks!
I resolved the issue actually it's kind of mandatory to clear the timer OVF bit in the INTFLAG register. So the interrupt handler should've been like this:
void TC1_Handler(void)
{
if((tc_hw1->INTFLAG.reg) & (TC_INTFLAG_OVF))
{
tc_hw1->INTFLAG.reg = TC_INTFLAG_OVF; /*Clears the flag by writing 1 to it*/
port_pin_toggle_output_level(PIN_PB03);
}
system_interrupt_clear_pending(SYSTEM_INTERRUPT_MODULE_TC1); /*Not necessarily needed*/
}
I'm trying to get the external interrupt running on a
Nucleo-F030R8
and hit a wall.
Everything is configured and runs just fine in step mode but when I'm connecting my board to another testboard with a simple jumper wire and run the same code, an External Interrupt is triggered even when that testboard (a second
Nucleo-F302R8,
which should only produce a single signal peak that I want to measure with the first) is not turned on.
I'm using a mix of the HAL Library from STM and a bit code of my own.
Has somebody eventually encountered a similar problem?
I'm using the System Workbench for STM32.
Part of the ISR, Interrupthandler is cut
void EXTI0_1_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_1_IRQn 0 */
if ((EXTI->IMR & EXTI_IMR_MR0) && (EXTI->PR & EXTI_PR_PR0))
{
int_flag_pin.copen = 1;
}
if ((EXTI->IMR & EXTI_IMR_MR1) && (EXTI->PR & EXTI_PR_PR1))
{
int_flag_pin.ma1 = 1;
}
/* USER CODE END EXTI0_1_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
/* USER CODE BEGIN EXTI0_1_IRQn 1 */
/* USER CODE END EXTI0_1_IRQn 1 */
}
Between setting the Pin low and change rising, the Interrupt triggers.
TEST_GPIO_Port->BSRR = (uint32_t) TEST_Pin;
//HAL_GPIO_WritePin(TEST_GPIO_Port, TEST_Pin, GPIO_PIN_RESET);
TEST_GPIO_Port->BRR = (uint32_t) TEST_Pin;
change_rising(0);
Update:
Could it be that resetting the Pin through BSRR or BRR generates an interrupt?
I'm checking my code step-by-step and everytime the pin is getting resetted the interrupt is generated.
if TEST_Pin is GPIO_PIN_0 or GPIO_PIN_1 pin, you will receive irq legally. EXTI0_1_IRQHandler catches irq from any port but from #0 or #1 pin.
I'm using hal can library for stm32L476vg mcu. I'm debugging my can transmission app and I can observe something apparently wrong in HAL_CAN_Transmit() sequence execution and its returned value, specially when it musts return HAL_TIMEOUT value.
Main code:
#include "main.h"
#include "Pm03_SystemConfig.h"
#include "App_Task_CAN.h"
uint8_t charBuffer[10]={0x00};
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
Pm03_SystemClock_Config();
App_Task_CAN_reset();
App_Task_CAN_init();
charBuffer[0]=0xCA;
charBuffer[1]=0xFE;
while (1)
{
App_Task_CAN_sendData(&charBuffer[0]);
}
}
My TX higher level function implementation that calls hal_can transmit and init for can configuration in App_Task_CAN.c file:
uint8_t App_Task_CAN_sendData(uint8_t* cBuffer)
{
for (uint8_t index=0; index< DATABTXLONG; index ++)
{
HCAN_Struct.pTxMsg->Data[index]= cBuffer[index];
}
if (HAL_CAN_Transmit(&HCAN_Struct, TIMEOUT)!=HAL_OK)
{
TaskCan_Error_Handler();
}
}
void App_Task_CAN_init(void)
{
static CanTxMsgTypeDef TxMessage;
static CanRxMsgTypeDef RxMessage;
/*configuracion timing para obtener 500kb/s*/
HCAN_Struct.Instance = CAN1;
HCAN_Struct.pTxMsg = &TxMessage;
HCAN_Struct.pRxMsg = &RxMessage;
HCAN_Struct.Init.Prescaler = 1;
HCAN_Struct.Init.Mode = CAN_MODE_NORMAL;//values defined in different hal libraries
HCAN_Struct.Init.SJW = CAN_SJW_1TQ;
HCAN_Struct.Init.BS1 = CAN_BS1_6TQ;//segment point at 87.5%
HCAN_Struct.Init.BS2 = CAN_BS2_1TQ;
HCAN_Struct.Init.TTCM = DISABLE;
HCAN_Struct.Init.ABOM = DISABLE;
HCAN_Struct.Init.AWUM = DISABLE;
HCAN_Struct.Init.NART = DISABLE;
HCAN_Struct.Init.RFLM = DISABLE;//Fifo locked mode disabled
HCAN_Struct.Init.TXFP = DISABLE;//prioridad de tx por id (más bajo más prioridad)
if (HAL_CAN_Init(&HCAN_Struct) != HAL_OK)
{
TaskCan_Error_Handler();
}
//TX
HCAN_Struct.pTxMsg->StdId = 0x321;
HCAN_Struct.pTxMsg->ExtId = 0x01;//29 bits
HCAN_Struct.pTxMsg->IDE = CAN_ID_STD;//values defined in different hal libraries
HCAN_Struct.pTxMsg->RTR = CAN_RTR_DATA;//values defined in different hal libraries
HCAN_Struct.pTxMsg->DLC = DATABTXLONG;//1-9
}
some defines used above, declared in App_Task_CAN.h:
/* Timeout for can operations in bit time units */
#define TIMEOUT 100
/* param for config mesg frames */
#define DATABTXLONG 2
I was debugging and going step by step through all the hal transmit function sequence (concerned piece of code below) and I can see how, after first TXRQ ->
Part of hal_can_transmit function in stm32l4xx_hal_can.c file:
HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout)
{
...
/* Request transmission */
hcan->Instance->sTxMailBox[transmitmailbox].TIR |= CAN_TI0R_TXRQ;
...
/* Check End of transmission flag */
while(!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox)))
{
/* Check for the Timeout */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout))
{
hcan->State = HAL_CAN_STATE_TIMEOUT;
/* Process unlocked */
__HAL_UNLOCK(hcan);//line in which thread breaks
return HAL_TIMEOUT;//ignored line during debug
}
}
}
...
}
(NOTE: This next piece of code belongs to hal library provided by ST)
-> once the thread passes through the above transmit call, after TXRQ line this happens:
the thread waits for end Tx flag and
after timeout value expires, the threads goes into timeout state line
it arrives until hal unlock() macro line
after this, it exits/breaks the execution and returns to the line where this function was called ignoring the next line "return HAL_TIMEOUT".
The thread is broken just before arriving to this line (red text line). It returns to my transmit call a HAL_OK value! I recieve HAL_OK value! I confirm this after mounting a switch case in order to see what value it was reciving instead of HAL_TIMEOUT.
It happens from the first time transmit is called. I don't know if it is normal behavior. Obviously it is a hal_can code fact and I can not do anything from code user to fix it.
Has someone else, who worked with hal can for stm32, faced this situation?
My Tx does not work and I was looking for the possible fail causes through debugging. Hence I have seen this. Maybe there is more than this code problem to solve. But I think my code is very simple to fail: I only call send data in a infinite loop (of course after can init). By debugging I can see how data is arriving to the mailboxes correctly, but flag of TXOk never sets.
So, maybe this hal_can strange behavior is part of the cause of my transmission fail.
It seems to be a third party bug. Has someone deal with same situation? Any suggestion about my user code? is there something to improve?
I generated my code from STM32CubeMx and wanted to generate a update event every 1µs. I work with the internal clock at 48MHz, which should be with Prescaler:0 and Autoreload:47 result to 1µs.
I use a STM32F030 with TrueStudio V.9.0.0
generated code
/* TIM17 init function */
static void MX_TIM17_Init(void)
{
LL_TIM_InitTypeDef TIM_InitStruct;
/* Peripheral clock enable */
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_TIM17);
/* TIM17 interrupt Init */
NVIC_SetPriority(TIM17_IRQn, 3);
NVIC_EnableIRQ(TIM17_IRQn);
TIM_InitStruct.Prescaler = 0;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 47;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
TIM_InitStruct.RepetitionCounter = 0;
LL_TIM_Init(TIM17, &TIM_InitStruct);
LL_TIM_EnableARRPreload(TIM17);
}
I added in my init:
LL_TIM_EnableIT_UPDATE(TIM17);
LL_TIM_EnableCounter(TIM17);
In the IRQ_Handler i toggle a PIN:
void TIM17_IRQHandler(void)
{
/* USER CODE BEGIN TIM17_IRQn 0 */
LL_GPIO_TogglePin(LED_D2_2_GPIO_Port,LED_D2_2_Pin);
/* USER CODE END TIM17_IRQn 0 */
/* USER CODE BEGIN TIM17_IRQn 1 */
/* USER CODE END TIM17_IRQn 1 */
}
After flashing my device with the code it generates a Signal with Frequency 889kHz with Pulsewidth of 564ns measured with Oscilloscope. Changes on Prescaler or Autoreload does not affect this output, it stays right away at T_Pulse=564ns or F=889kHz.
Any idea what I am missing here?
Register output from debugging:
CR1:0x81 CR2:0
DIER:0x01 SR:0x03
CCMR1_O/I:0 CCER:0
PSC:0 ARR:0x2f
RCR:0 CCR1:0
BDTR:0 DCR:0
DMAR:0x81
The solution was the clearance of the FLAG UIE in TIM17->SR in the IRQ_Handler.
I was stuck permanently in the IRQ routine.