mirror of
https://github.com/RfidResearchGroup/ChameleonMini.git
synced 2026-05-12 11:20:37 -07:00
Faster ISR sharing in ASM
While in the process of writing a new codec I stumbled upon the long standing issue of ISR sharing in AVR MCUs. Actually this is accomplished with an ISR written in C, which simply calls another plain C function referenced via a function pointer updated at runtime. This approach is slow because GCC can't optimize the ISR, since it does not know which registers will be used, so it defaults to push/pop all of them. My solution keeps the concept of pointers to functions, but greatly improves speed by reducing the ISR itself to the bare minimum to call another function, which will be compiled by GCC as a signal. This means all interrupt optimizations will be put in place by GCC, while ISRs can be still written in plain C code, but the overhead is now much smaller. It has proven to reduce by 20 the number of instructions for every ISR, mainly pushes/pops, which cuts the clock cycle count down by 30 cycles (1 cycle for every push, 2 for pop). In time units, this means 1.1 uSec are saved for every ISR invocation and every shared ISR now takes only 13 clock cycles more than the "bare" one. A new ISR_SHARED function type has been defined in Common.h to hide away from the programmer GCC attributes. All new shared interrupt handling routines should be defined of this type to prevent stack and registers corruption. Minor changes were made to Codec.h to allow including it in .S files.
This commit is contained in:
@@ -8,26 +8,6 @@
|
||||
#ifndef CODEC_H_
|
||||
#define CODEC_H_
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../Common.h"
|
||||
#include "../Configuration.h"
|
||||
#include "../Settings.h"
|
||||
|
||||
#include "ISO14443-2A.h"
|
||||
#include "Reader14443-2A.h"
|
||||
#include "SniffISO14443-2A.h"
|
||||
#include "ISO15693.h"
|
||||
|
||||
/* Timing definitions for ISO14443A */
|
||||
#define ISO14443A_SUBCARRIER_DIVIDER 16
|
||||
#define ISO14443A_BIT_GRID_CYCLES 128
|
||||
#define ISO14443A_BIT_RATE_CYCLES 128
|
||||
#define ISO14443A_FRAME_DELAY_PREV1 1236
|
||||
#define ISO14443A_FRAME_DELAY_PREV0 1172
|
||||
#define ISO14443A_RX_PENDING_TIMEOUT 4 // ms
|
||||
|
||||
/* Peripheral definitions */
|
||||
#define CODEC_DEMOD_POWER_PORT PORTB
|
||||
#define CODEC_DEMOD_POWER_MASK PIN0_bm
|
||||
@@ -87,6 +67,27 @@
|
||||
#define CODEC_TIMER_TIMESTAMPS_CCA_VECT TCD1_CCA_vect
|
||||
#define CODEC_TIMER_TIMESTAMPS_CCB_VECT TCD1_CCB_vect
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../Common.h"
|
||||
#include "../Configuration.h"
|
||||
#include "../Settings.h"
|
||||
|
||||
#include "ISO14443-2A.h"
|
||||
#include "Reader14443-2A.h"
|
||||
#include "SniffISO14443-2A.h"
|
||||
#include "ISO15693.h"
|
||||
|
||||
/* Timing definitions for ISO14443A */
|
||||
#define ISO14443A_SUBCARRIER_DIVIDER 16
|
||||
#define ISO14443A_BIT_GRID_CYCLES 128
|
||||
#define ISO14443A_BIT_RATE_CYCLES 128
|
||||
#define ISO14443A_FRAME_DELAY_PREV1 1236
|
||||
#define ISO14443A_FRAME_DELAY_PREV0 1172
|
||||
#define ISO14443A_RX_PENDING_TIMEOUT 4 // ms
|
||||
|
||||
#define CODEC_BUFFER_SIZE 256
|
||||
|
||||
@@ -285,4 +286,7 @@ bool CodecIsReaderToBeRestarted(void);
|
||||
void CodecThresholdSet(uint16_t th);
|
||||
uint16_t CodecThresholdIncrement(void);
|
||||
void CodecThresholdReset(void);
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* CODEC_H_ */
|
||||
|
||||
@@ -79,13 +79,8 @@ static void StartDemod(void) {
|
||||
CODEC_DEMOD_IN_PORT.INT0MASK = CODEC_DEMOD_IN_MASK0;
|
||||
}
|
||||
|
||||
ISR(CODEC_DEMOD_IN_INT0_VECT) {
|
||||
isr_func_CODEC_DEMOD_IN_INT0_VECT();
|
||||
}
|
||||
|
||||
// ISR(CODEC_DEMOD_IN_INT0_VECT)
|
||||
// Find first pause and start sampling
|
||||
void isr_ISO14443_2A_TCD0_CCC_vect(void) {
|
||||
ISR_SHARED isr_ISO14443_2A_TCD0_CCC_vect(void) {
|
||||
/* This is the first edge of the first modulation-pause after StartDemod.
|
||||
* Now we have time to start
|
||||
* demodulating beginning from one bit-width after this edge. */
|
||||
|
||||
@@ -89,7 +89,7 @@ static volatile uint16_t ReadCommandFromReader = 0;
|
||||
* and unregistered writing the INT0MASK to 0
|
||||
*/
|
||||
// ISR(CODEC_DEMOD_IN_INT0_VECT)
|
||||
void isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT(void) {
|
||||
ISR_SHARED isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT(void) {
|
||||
/* Start sample timer CODEC_TIMER_SAMPLING (TCD0).
|
||||
* Set Counter Channel C (CCC) with relevant bitmask (TC0_CCCIF_bm),
|
||||
* the period for clock sampling is specified in StartISO15693Demod.
|
||||
@@ -146,8 +146,7 @@ INLINE void ISO15693_EOC(void) {
|
||||
*
|
||||
* It disables its own interrupt when receives an EOF (calling ISO15693_EOC) or when it receives garbage
|
||||
*/
|
||||
// ISR(CODEC_TIMER_SAMPLING_CCC_VECT) // Reading data sent from the reader
|
||||
void isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT(void) {
|
||||
ISR_SHARED isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT(void) {
|
||||
/* Shift demod data */
|
||||
SampleRegister = (SampleRegister << 1) | (!(CODEC_DEMOD_IN_PORT.IN & CODEC_DEMOD_IN_MASK) ? 0x01 : 0x00);
|
||||
|
||||
|
||||
@@ -170,13 +170,10 @@ INLINE void BufferToSequence(void) {
|
||||
if (BitCount % 8)
|
||||
CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8));
|
||||
}
|
||||
// Frame Delay Time PCD to PICC ends
|
||||
ISR(CODEC_TIMER_SAMPLING_CCC_VECT) {
|
||||
isr_func_TCD0_CCC_vect();
|
||||
}
|
||||
|
||||
// ISR (TCD0_CCC_vect)
|
||||
void isr_Reader14443_2A_TCD0_CCC_vect(void) {
|
||||
// Frame Delay Time PCD to PICC ends
|
||||
ISR_SHARED isr_Reader14443_2A_TCD0_CCC_vect(void) {
|
||||
CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm;
|
||||
CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc;
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
#define ODD_PARITY(Value) OddParityBit(Value)//(parity_even_bit(Value) ? 0 : 1)
|
||||
|
||||
#define ISR_SHARED \
|
||||
void __attribute__((signal)) // This function type has to be used for all the interrupt handlers that have to be changed at runtime
|
||||
|
||||
#define INLINE \
|
||||
static inline __attribute__((always_inline))
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
; This file allows to share ISR at runtime with a low overhead.
|
||||
; Functions that have to be shared MUST be defined as ISR_SHARED types
|
||||
; (Defined in Common.h) to instruct GCC to compile them preserving the stack
|
||||
;
|
||||
; Created on: 2019-12-06
|
||||
; Author: ceres-c
|
||||
;
|
||||
|
||||
#include "Codec/Codec.h"
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
; Find first pause and start sampling
|
||||
.global CODEC_DEMOD_IN_INT0_VECT
|
||||
CODEC_DEMOD_IN_INT0_VECT:
|
||||
push r30
|
||||
push r31
|
||||
lds r30, isr_func_CODEC_DEMOD_IN_INT0_VECT
|
||||
lds r31, isr_func_CODEC_DEMOD_IN_INT0_VECT + 1
|
||||
icall
|
||||
pop r31
|
||||
pop r30
|
||||
reti
|
||||
|
||||
; Frame Delay Time PCD to PICC ends
|
||||
.global CODEC_TIMER_SAMPLING_CCC_VECT
|
||||
CODEC_TIMER_SAMPLING_CCC_VECT:
|
||||
push r30
|
||||
push r31
|
||||
lds r30, isr_func_TCD0_CCC_vect
|
||||
lds r31, isr_func_TCD0_CCC_vect + 1
|
||||
icall
|
||||
pop r31
|
||||
pop r30
|
||||
reti
|
||||
@@ -97,7 +97,7 @@ F_CPU = 27120000
|
||||
F_USB = 48000000
|
||||
TARGET = Chameleon-Mini
|
||||
OPTIMIZATION = s
|
||||
SRC += $(TARGET).c LUFADescriptors.c System.c Configuration.c Random.c Common.c Memory.c MemoryAsm.S Button.c Log.c Settings.c LED.c Map.c AntennaLevel.c
|
||||
SRC += $(TARGET).c LUFADescriptors.c System.c ISRSharing.S Configuration.c Random.c Common.c Memory.c MemoryAsm.S Button.c Log.c Settings.c LED.c Map.c AntennaLevel.c
|
||||
SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Terminal/CommandLine.c
|
||||
SRC += Codec/Codec.c Codec/ISO14443-2A.c Codec/Reader14443-2A.c Codec/SniffISO14443-2A.c Codec/Reader14443-ISR.S
|
||||
SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Reader14443A.c Application/Sniff14443A.c Application/CryptoTDEA.S
|
||||
|
||||
@@ -140,4 +140,3 @@ void SystemInterruptInit(void) {
|
||||
PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
|
||||
sei();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user