I’m doing a training program for embedded development, and right now I’m working on setting up an ADC interrupt in an RTOS environment in IAR Embedded Workbench.
I’m running into a problem when I try to link the ADC interrupt to the AdcIsr function within the interrupt vector table. The instructions for the assignment says to replace (CPU_FNCT_VOID)BSP_IntHandler_102
on line 102, with (CPU_FNCT_VOID)AdcIsr
Here is the code for interrupts.c, which contains the interrupt vector table and their interrupt handlers:
#include <bsp_cfg.h>
#include <cpu.h>
#include <os.h>
#include <stdint.h>
#include <cpu_core.h>
#include <lib_def.h>
#include <bsp_int_vect_tbl.h>
#include "adc.h"
/*
*********************************************************************************************************
* INTERRUPT VECTOR TABLE
*
* Note(s): 1) Could be in RAM if BSP_CFG_INT_VECT_RAM_EN is set to 1 in 'bsp_cfg.h'
* 2) In either case BSP_IntVectSet() must becalled to boint to BSP_IntVectTbl[]
*
*********************************************************************************************************
*/
#if BSP_CFG_INT_VECT_TBL_RAM_EN > 0u
static CPU_FNCT_VOID BSP_IntVectTbl[] =
#else
const CPU_FNCT_VOID BSP_IntVectTbl[] =
#endif
{
(CPU_FNCT_VOID)BSP_IntHandler_000, /* 00 */
(CPU_FNCT_VOID)BSP_IntHandler_001, /* 01 */
(CPU_FNCT_VOID)BSP_IntHandler_002, /* 02 */
(CPU_FNCT_VOID)BSP_IntHandler_003, /* 03 */
// ... other interrupt handlers ...
(CPU_FNCT_VOID)AdcIsr, /* 102 */
// ... other interrupt handlers ...
};
Here is my header file:
#ifndef _ADC_H
#define _ADC_H
void adc_task (void * p_arg);
#endif /* _ADC_H */
If relevant, here is my C code for the ADC:
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include "os.h"
#include "iorx63n.h"
#include "adc.h"
#include <bsp_glcd.h>
// Message Queue for ISR->Task Communication
static OS_Q g_adc_q;
#define ADC_SOURCE_VR1 2
#define ADC_INTERRUPT_AFTER_SCAN 0x10
#define ADC_START 0x80
#define BIT(n) (1 << (n))
// NOTE: Refer to p. 1,698 to 1,727 of Processor_UsersManual_Hardware.pdf
typedef struct
{
uint8_t control; // Offset 0x00
uint8_t const _unused1[3];
uint16_t channel_select0; // Offset 0x04
uint16_t channel_select1; // Offset 0x06
uint16_t value_addition_mode_select0; // Offset 0x08
uint16_t value_addition_mode_select1; // Offset 0x0A
uint8_t value_addition_count_select; // Offset 0x0C
uint8_t const _unused2;
uint16_t control_extended; // Offset 0x0E
uint8_t start_trigger_select; // Offset 0x10
uint8_t const _unused3;
uint16_t extended_input_control; // Offset 0x12
uint8_t const _unused4[6];
uint16_t temperature_sensor_data; // Offset 0x1A
uint16_t internal_reference_data; // Offset 0x1C
uint8_t const _unused5[2];
uint16_t data[21]; // Offset 0x20
} adc_t;
adc_t volatile * const p_adc = (adc_t *) 0x00089000;
#define adc (*p_adc)
/*!
* @brief Configure the ADC hardware to read Potentiometer VR1 and interrupt.
*/
static void adc_config (void)
{
/* Protection off */
SYSTEM.PRCR.WORD = 0xA503u;
/* Cancel the S12AD module clock stop mode */
MSTP_S12AD = 0;
/* Protection on */
SYSTEM.PRCR.WORD = 0xA500u;
// Select the 12-bit ADC. In the HW course, this detail is in BSP_Init().
SYSTEM.MSTPCRA.BIT.MSTPA17 = 0;
/* Use the AN000 (Potentiometer) pin
as an I/O for peripheral functions */
PORT4.PMR.BYTE = 0x01;
// Enable A/D interrupts at an appropriate priority, as instructed.
uint8_t * p_IER = (uint8_t *)0x0008720C;
uint8_t * p_IPR = (uint8_t *)0x00087366;
*p_IPR = 9; // Set interrupt priority.
*p_IER |= 0x40; // Unmask A/D interrupt.
// Configure the A/D to perform a single scan and interrupt.
adc.control = ADC_INTERRUPT_AFTER_SCAN;
adc.channel_select0 = BIT(ADC_SOURCE_VR1);
}
/*!
*
* @brief: ADC Driver Task
*/
void adc_task (void * p_arg)
{
OS_ERR err;
void *p_msg;
OS_MSG_SIZE msg_size;
uint16_t adc_value;
char p_str[13];
(void)p_arg; // NOTE: Silence compiler warning about unused param.
// Create message queue.
// NOTE: It's safe to do this here, because the ISR is synchornized to us.
OSQCreate(&g_adc_q, "ADC Queue", 1, &err);
assert(OS_ERR_NONE == err);
// Configure ADC hardware to read Potentiometer VR1 and interrupt.
adc_config();
for (;;)
{
// Wait 125 ms.
OSTimeDlyHMSM(0, 0, 0, 125, OS_OPT_TIME_HMSM_STRICT, &err);
// Trigger ADC conversion.
adc.control |= ADC_START;
// TODO: Wait for message from ISR, then format and display on LCD.;
p_msg = OSQPend(&g_adc_q, 100, OS_OPT_PEND_BLOCKING, &msg_size, (void *)0, &err);
adc_value = *(uint16_t*)p_msg;
sprintf(p_str, "ADC: %4u", adc_value);
BSP_GraphLCD_String(5, p_str);
}
}
/*!
*
* @brief ADC Interrupt Handler
*/
void adc_isr (void)
{
static uint16_t sample; // NOTE: Not on the stack; so address is valid.
OS_ERR err;
// Read from the A/D converter and reduce the range from 12-bit to 10-bit.
sample = adc.data[ADC_SOURCE_VR1] >> 2;
// TODO: Send sample value to ADC task via a message queue
OSQPost(&g_adc_q, &sample, sizeof(sample), OS_OPT_POST_FIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED, &err);
}
The assembly code containing the AdcIsr() function has already been provided to me. The instructions state that no changes need to be made within this file, but I will include it here for context:
extern _adc_isr
extern _OSIntExit
extern _OSIntNestingCtr
extern _OSTCBCurPtr
;/*$PAGE*/
;********************************************************************************************************
; AdcIsr()
;********************************************************************************************************
section .text:CODE:ROOT
public _AdcIsr
_AdcIsr:
PUSHC FPSW ; Save processor registers on the stack
PUSHM R1-R15
MVFACHI R1
MVFACMI R2
PUSHM R1-R2
MOV.L #_OSIntNestingCtr, R5 ; Notify uC/OS-III about ISR
MOV.B [R5], R3
ADD #1, R3
MOV.B R3, [R5]
CMP #1, R3 ; if (OSNestingCtr == 1)
BNE _AdcIsr1
MOV.L #_OSTCBCurPtr, R5 ; Save current task's SP into its TCB
MOV.L [R5], R3
MOV.L R0, [R3]
_AdcIsr1 MOV.L #_adc_isr, R5
JSR R5
MOV.L #_OSIntExit, R5
JSR R5 ; Notify uC/OS-III about end of ISR
POPM R1-R2 ; Restore processor registers from stack
SHLL #16, R2
MVTACLO R2
MVTACHI R1
POPM R1-R15
POPC FPSW
RTE
end
The error I am getting is:
Error[Pe020]: identifier "AdcIsr" is undefined