如何在嵌入式 ANSI C 中制作锁/临界区?
How to make lock / critical section in embedded ANSI C?
我有这样的代码:(非常简化的代码)
// This is code for Microchip 8-bit microcontroller, XC8 compiler (GCC based)
#define TIMER_COUNT 8;
volatile uint16_t timer_values[TIMER_COUNT];
volatile uint16_t timer_max_values[TIMER_COUNT];
// executes every 100ms
void timer1_interrupt_handler()
{
for (uint8_t i = 0; i < TIMER_COUNT ; i++){
timer_values[i];
}
}
void main(){
// (...) some initialization, peripherial and interrupt handler setup
while(1){
for (uint8_t i = 0; i < TIMER_COUNT ; i++) {
// what if interrupt happens in the middle of comparison?
if (timer_values[i] >= timer_max_values[i])
{
timer_values[i] = 0; // reset timer
executeTimerElapsedAction(i);
}
}
}
}
问题是这是 8 位微控制器,当中断发生在 16 位变量的非原子操作中间时:
timer_values[i] >= timer_max_values[i]
或者这个:
timer_values[i] = 0;
有可能 uint16_t 的一半将被中断处理程序重写,一切都搞砸了。
这不是 RTOS,所以我没有内置锁。
我能做什么?如何从头开始制作锁?
我正在考虑像这样创建 "critical section":
GlobalInterruptsDisable(); // enter critical section
if (timer_values[i] >= timer_max_values[i])
{
timer_values[i] = 0; // reset timer
GlobalInterruptsEnable(); // exit critical section
executeTimerElapsedAction(i);
}
但是我担心我会同时跳过一些中断(我正在使用 2 个定时器、2 个 UART 和 I2C 中断)并且其他东西会搞砸。
补充问题:
如果我禁用中断大约 20-30 个处理器周期,然后一些数据到达 UART - 我将跳过此数据或中断处理程序将在我启用中断后稍后执行?
您可以为停止中断的保存参数副本编写一个函数,进行复制然后重新启动中断。
#define protectedXfer(destination, source) protectedMemcpy(&(destination), \
&(source), \
sizeof(destination))
void protectedMemcpy(void *destination, const void *source, size_t num)
{
int volatile oldIpl;
oldIpl = SRbits.IPL;
SRbits.IPL2 = 1; // If an Interrupt occurs here
SRbits.IPL1 = 1; // the IPL bits are saved/restored
SRbits.IPL0 = 1; // from the stack
memcpy(destination, source, num);
SRbits.IPL = oldIpl;
}
知道您可以从您的计时器值进行保存传输并在之后进行检查。
protectedXfer(destinaion, source);
我有这样的代码:(非常简化的代码)
// This is code for Microchip 8-bit microcontroller, XC8 compiler (GCC based)
#define TIMER_COUNT 8;
volatile uint16_t timer_values[TIMER_COUNT];
volatile uint16_t timer_max_values[TIMER_COUNT];
// executes every 100ms
void timer1_interrupt_handler()
{
for (uint8_t i = 0; i < TIMER_COUNT ; i++){
timer_values[i];
}
}
void main(){
// (...) some initialization, peripherial and interrupt handler setup
while(1){
for (uint8_t i = 0; i < TIMER_COUNT ; i++) {
// what if interrupt happens in the middle of comparison?
if (timer_values[i] >= timer_max_values[i])
{
timer_values[i] = 0; // reset timer
executeTimerElapsedAction(i);
}
}
}
}
问题是这是 8 位微控制器,当中断发生在 16 位变量的非原子操作中间时:
timer_values[i] >= timer_max_values[i]
或者这个:
timer_values[i] = 0;
有可能 uint16_t 的一半将被中断处理程序重写,一切都搞砸了。
这不是 RTOS,所以我没有内置锁。
我能做什么?如何从头开始制作锁?
我正在考虑像这样创建 "critical section":
GlobalInterruptsDisable(); // enter critical section
if (timer_values[i] >= timer_max_values[i])
{
timer_values[i] = 0; // reset timer
GlobalInterruptsEnable(); // exit critical section
executeTimerElapsedAction(i);
}
但是我担心我会同时跳过一些中断(我正在使用 2 个定时器、2 个 UART 和 I2C 中断)并且其他东西会搞砸。
补充问题:
如果我禁用中断大约 20-30 个处理器周期,然后一些数据到达 UART - 我将跳过此数据或中断处理程序将在我启用中断后稍后执行?
您可以为停止中断的保存参数副本编写一个函数,进行复制然后重新启动中断。
#define protectedXfer(destination, source) protectedMemcpy(&(destination), \
&(source), \
sizeof(destination))
void protectedMemcpy(void *destination, const void *source, size_t num)
{
int volatile oldIpl;
oldIpl = SRbits.IPL;
SRbits.IPL2 = 1; // If an Interrupt occurs here
SRbits.IPL1 = 1; // the IPL bits are saved/restored
SRbits.IPL0 = 1; // from the stack
memcpy(destination, source, num);
SRbits.IPL = oldIpl;
}
知道您可以从您的计时器值进行保存传输并在之后进行检查。
protectedXfer(destinaion, source);