IRQ Double Faulting - c++

I have a problem, with the making of my first driver(PIT). The problem is clearly explained in this viedo i recorded earlier: https://www.youtube.com/watch?v=hjvTtVbaics&feature=youtu.be . Let me show my timer driver first:
timer.c++:
#include "timer.h"
/* This will keep track of how many ticks that the system
* has been running for */
typedef void(*regs_func)(struct regs *r);
static int32_t timer_ticks = 0;
extern void install_handler_irq(int irq, regs_func handler);
/* Handles the timer. In this case, it's very simple: We
* increment the 'Timer::timer_ticks' variable every time the
* timer fires. By default, the timer fires 18.222 times
* per second. Why 18.222Hz? Some engineer at IBM must've
* been smoking something funky */
void timer_handler_driver(struct regs *r)
{
/* Increment our 'tick count' */
timer_ticks++;
/* Every 18 clocks (approximately 1 second), we will
* display a message on the screen */
// if (timer_ticks % 18 == 0)
// {
printf("One second has passed\n");
// }
}
Timer::Timer()
{
}
/* This will continuously loop until the given time has
* been reached */
void Timer::timer_wait(int ticks)
{
unsigned long eticks;
eticks = timer_ticks + ticks;
while((unsigned)timer_ticks < eticks);
}
void Timer::install_timer()
{
install_handler_irq(0, timer_handler_driver);
}
/* Sets up the system clock by installing the timer handler
* into IRQ0 */
Timer::~Timer()
{
}
and here is my irq c++ code:
irq.c++:
#include "irq.h"
#define PIC_MASTER_CONTROL 0x20
#define PIC_MASTER_MASK 0x21
#define PIC_SLAVE_CONTROL 0xa0
#define PIC_SLAVE_MASK 0xa1
typedef void(*regs_func)(struct regs *r);
/*Get all irq's*/
extern "C" void irq0(void);
extern "C" void irq1(void);
extern "C" void irq2(void);
extern "C" void irq3(void);
extern "C" void irq4(void);
extern "C" void irq5(void);
extern "C" void irq6(void);
extern "C" void irq7(void);
extern "C" void irq8(void);
extern "C" void irq9(void);
extern "C" void irq10(void);
extern "C" void irq11(void);
extern "C" void irq12(void);
extern "C" void irq13(void);
extern "C" void irq14(void);
extern "C" void irq15(void);
extern void panic(const char* exception);
regs_func irq_routines[16] = {
0,0,0,0,0,0,0,0
,0,0,0,0,0,0,0,0
};
static PORT::Port8Bits p8b_irq;
static SerialPort sp_irq;
//Basically a declaration of IDT_ENTRY in
//idt.c++
struct idt_entry {
uint16_t base_lo;
uint16_t sel; // Kernel segment goes here.
uint8_t always0;
uint8_t flags; // Set using the table.
uint16_t base_hi;
}__attribute__((packed));
//Get the Exact IDT array from idt.c++
extern struct idt_entry idt[256];
static inline void idt_set_gate(uint8_t num, void(*handler)(void), uint16_t sel,
uint8_t flags)
{
idt[num].base_lo = (uintptr_t)handler >> 0 & 0xFFFF;
idt[num].base_hi = (uintptr_t)handler >> 16 & 0xffff;
idt[num].always0 = 0;
idt[num].sel = sel;
idt[num].flags = flags;
}
IRQ::IRQ(){};
IRQ::~IRQ(){};
/* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This
* is a problem in protected mode, because IDT entry 8 is a
* Double Fault! Without remapping, every time IRQ0 fires,
* you get a Double Fault Exception, which is NOT actually
* what's happening. We send commands to the Programmable
* Interrupt Controller (PICs - also called the 8259's) in
* order to make IRQ0 to 15 be remapped to IDT entries 32 to
* 47 */
void IRQ::irq_remap()
{
// ICW1 - begin initialization
p8b_irq.out(0x11,PIC_MASTER_CONTROL);
p8b_irq.out(0x11,PIC_SLAVE_CONTROL);
// Remap interrupts beyond 0x20 because the first 32 are cpu exceptions
p8b_irq.out(0x21,PIC_MASTER_MASK);
p8b_irq.out(0x28,PIC_SLAVE_MASK);
// ICW3 - setup cascading
p8b_irq.out(0x04,PIC_MASTER_MASK);
p8b_irq.out(0x02,PIC_SLAVE_MASK);
// ICW4 - environment info
p8b_irq.out(0x01,PIC_MASTER_MASK);
p8b_irq.out(0x01,PIC_SLAVE_MASK);
// mask interrupts
p8b_irq.out(0,PIC_MASTER_MASK);
p8b_irq.out(0,PIC_SLAVE_MASK);
}
void install_handler_irq(int irq, regs_func handler)
{
printf(" \n Installer IRQ %d \n ", irq);
irq_routines[irq] = handler;
}
void uninstall_handler_irq(int irq)
{
irq_routines[irq] = 0;
}
/* First remap the interrupt controllers, and then we install
* the appropriate ISRs to the correct entries in the IDT. This
* is just like installing the exception handlers */
void IRQ::install_irqs()
{
this->irq_remap();
idt_set_gate(32, irq0, 0x08, 0x8E);
idt_set_gate(33, irq1, 0x08, 0x8E);
idt_set_gate(34, irq2, 0x08, 0x8E);
idt_set_gate(35, irq3, 0x08, 0x8E);
idt_set_gate(36, irq4, 0x08, 0x8E);
idt_set_gate(37, irq5, 0x08, 0x8E);
idt_set_gate(38, irq6, 0x08, 0x8E);
idt_set_gate(39, irq7, 0x08, 0x8E);
idt_set_gate(40, irq8, 0x08, 0x8E);
idt_set_gate(41, irq9, 0x08, 0x8E);
idt_set_gate(42, irq10, 0x08, 0x8E);
idt_set_gate(43, irq11, 0x08, 0x8E);
idt_set_gate(44, irq12, 0x08, 0x8E);
idt_set_gate(45, irq13, 0x08, 0x8E);
idt_set_gate(46, irq14, 0x08, 0x8E);
idt_set_gate(47, irq15, 0x08, 0x8E);
}
/* Each of the IRQ ISRs point to this function, rather than
* the 'fault_handler' in 'isrs.c'. The IRQ Controllers need
* to be told when you are done servicing them, so you need
* to send them an "End of Interrupt" command (0x20). There
* are two 8259 chips: The first exists at 0x20, the second
* exists at 0xA0. If the second controller (an IRQ from 8 to
* 15) gets an interrupt, you need to acknowledge the
* interrupt at BOTH controllers, otherwise, you only send
* an EOI command to the first controller. If you don't send
* an EOI, you won't raise any more IRQs */
extern "C" void irq_handler(struct regs *r)
{
printf("IRQ Being Handled");
}
and my irq.S:
.section .text
.extern irq_handler
.extern test_func
.macro irq number
.global irq\number
irq\number:
cli
pushl $0
pushl $\number
jmp common_handler_irq
.endm
common_handler_irq:
# save registers
pusha
# call C++ Handler
call irq_handler
# restore registers
popa
iret
#TODO FOR LOOP
irq 0
irq 1
irq 2
irq 3
irq 4
irq 5
irq 6
irq 7
irq 8
irq 9
irq 10
irq 11
irq 12
irq 13
irq 14
irq 15
Before I start my github is here, so you can see my whole code: https://github.com/amanuel2/OS_Mirror .So what happenes basically is. As you can see on my timer.c++ if i have the if statements commented it prints One Second Passed and the errors on qemu(double fault), if i dont it dosent print anything and double faults. as you can see by the viedo: [url]https://www.youtube.com/watch?v=hjvTtVbaics&feature=youtu.be[/url]. Help Would Be Appreciated!
EDIT:
Sometimes it decides to just show the error message on qemu , and dosent say One Second Passed at all, or even the Divide by 0 error, and gives me this :
qemu: fatal: Trying to execute code outside RAM or ROM at 0x491019d0
EAX=00000000 EBX=00009500 ECX=00000700 EDX=0010159e
ESI=00000000 EDI=00109000 EBP=00107122 ESP=001031ee
EIP=001019d0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 49000000 0008ffff 00589a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00103114 00000017
IDT= 00102900 000007ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000010 CCD=001031ce CCO=ADDL
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
make: *** [Makefile:56: qemu] Aborted (core dumped)
I have tried debugging this for a while now.
Another problem is that its changing.... Its not a stable error as you can see on viedo: https://www.youtube.com/watch?v=fHQE_vIu_wU&feature=youtu.be

First there are minor problems in your remap pic code:
p8b_irq.out(0x21,PIC_MASTER_MASK);
p8b_irq.out(0x28,PIC_SLAVE_MASK);
master -> 0x21(33) ~ 0x28
slave -> 0x28 ~ 0x2f
As you may figure now, you actually intended to map master to 0x20~0x27. But since you have a common IRQ handler it didn't go fatal.
Now for the crash, let's trace how the IRQ is handled:
since you saw a message once, it indicate your IDT is good
the CPU jump to the label irq0 (which followed by cli and two push)
jump to common_handler_irq
pusha
invoke C rountine irq_handler, which basically done nothing.
popa
iret
If you look carefully on the stack, there are two push left and iret will just jump into whatever that value - but not the resume address.
That's how you get "Trying to execute code outside RAM or ROM".
To fix it, adjust the stack accordingly before iret.
PS: also note that irq_handler was not called with proper arguments, *reg is bogus too.

Related

Initializing plog::RollingFileAppender on Windows XP Triggers Access Violation (Null Pointer)

When using [plog][1] on Windows XP. In this case, the code is:
void LogInit(void)
{
static plog::RollingFileAppender<plog::TxtFormatter> fileAppender("log.log");
Using Visual Studio 2019 but the project uses the platform toolset Visual Studio 2017 - Windows XP (v141_XP)
The output assembly is:
; COMDAT _LogInit
_TEXT SEGMENT
_status$1$ = -516 ; size = 4
_appender$66 = -516 ; size = 4
$T65 = -512 ; size = 256
$T64 = -512 ; size = 256
$T62 = -512 ; size = 256
$T60 = -512 ; size = 256
$T58 = -256 ; size = 256
$T57 = -256 ; size = 256
$T41 = -256 ; size = 256
_LogInit PROC ; COMDAT
; 108 : {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 83 e4 f8 and esp, -8 ; fffffff8H
; 109 : static plog::RollingFileAppender<plog::TxtFormatter> fileAppender("log.log");
00006 64 a1 00 00 00
00 mov eax, DWORD PTR fs:__tls_array
0000c 81 ec 04 02 00
00 sub esp, 516 ; 00000204H
00012 8b 0d 00 00 00
00 mov ecx, DWORD PTR __tls_index
00018 53 push ebx
00019 56 push esi
0001a 8b 34 88 mov esi, DWORD PTR [eax+ecx*4]
The null pointer is because EAX (__tls_array) and ECX (__tls_index) area both null. Output from WinDbg:
TGLOBALFLAG: 70
APPLICATION_VERIFIER_FLAGS: 0
CONTEXT: (.ecxr)
eax=00000000 ebx=00000000 ecx=00000000 edx=7c90e4f4 esi=0012f624 edi=00000000
eip=1000366a esp=001afda4 ebp=001affb4 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010216
LogTest!LogInit+0x1a:
1000366a 8b3488 mov esi,dword ptr [eax+ecx*4] ds:0023:00000000=????????
Resetting default scope
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 1000366a (LogTest!LogInit+0x0000001a)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000000
Attempt to read from address 00000000
PROCESS_NAME: notepad.exe
READ_ADDRESS: 00000000
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_CODE_STR: c0000005
EXCEPTION_PARAMETER1: 00000000
EXCEPTION_PARAMETER2: 00000000
FAULTING_LOCAL_VARIABLE_NAME: fileAppender
STACK_TEXT:
001affb4 7c80b713 00000000 00000000 0012f624 LogTest!LogInit+0x1a
001affec 00000000 10003650 00000000 00000000 kernel32!BaseThreadStart+0x37
STACK_COMMAND: ~1s; .ecxr ; kb
FAULTING_SOURCE_LINE: d:\test\logtest.cpp
FAULTING_SOURCE_FILE: d:\test\logtest.cpp
FAULTING_SOURCE_LINE_NUMBER: 109
FAULTING_SOURCE_CODE:
105:
106: // This is an example of an exported function.
107: LogInit_API void LogInit(void)
108: {
> 109: static plog::RollingFileAppender<plog::TxtFormatter> fileAppender(";pg.log");
110: plog::init(plog::info, &fileAppender);
111:
112:
113:
114:
SYMBOL_NAME: LogTest!LogInit+1a
MODULE_NAME: LogTest
IMAGE_NAME: LogTest.dll
FAILURE_BUCKET_ID: NULL_POINTER_READ_c0000005_LogTest.dll!LogInit
OS_VERSION: 5.1.2600.5512
BUILDLAB_STR: xpsp
OSPLATFORM_TYPE: x86
OSNAME: Windows XP
FAILURE_ID_HASH: {0218fa42-bce4-328f-5683-a7e3657927fc}
Followup: MachineOwner
---------
Code for affected class is:
namespace plog
{
template<class Formatter, class Converter = NativeEOLConverter<UTF8Converter> >
class PLOG_LINKAGE_HIDDEN RollingFileAppender : public IAppender
{
public:
RollingFileAppender(const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0)
: m_fileSize()
, m_maxFileSize()
, m_maxFiles(maxFiles)
, m_firstWrite(true)
{
setFileName(fileName);
setMaxFileSize(maxFileSize);
}
#ifdef _WIN32
RollingFileAppender(const char* fileName, size_t maxFileSize = 0, int maxFiles = 0)
: m_fileSize()
, m_maxFileSize()
, m_maxFiles(maxFiles)
, m_firstWrite(true)
{
setFileName(fileName);
setMaxFileSize(maxFileSize);
}
#endif
virtual void write(const Record& record)
{
util::MutexLock lock(m_mutex);
if (m_firstWrite)
{
openLogFile();
m_firstWrite = false;
}
else if (m_maxFiles > 0 && m_fileSize > m_maxFileSize && static_cast<size_t>(-1) != m_fileSize)
{
rollLogFiles();
}
size_t bytesWritten = m_file.write(Converter::convert(Formatter::format(record)));
if (static_cast<size_t>(-1) != bytesWritten)
{
m_fileSize += bytesWritten;
}
}
void setFileName(const util::nchar* fileName)
{
util::MutexLock lock(m_mutex);
util::splitFileName(fileName, m_fileNameNoExt, m_fileExt);
m_file.close();
m_firstWrite = true;
}
#ifdef _WIN32
void setFileName(const char* fileName)
{
setFileName(util::toWide(fileName).c_str());
}
#endif
void setMaxFiles(int maxFiles)
{
m_maxFiles = maxFiles;
}
void setMaxFileSize(size_t maxFileSize)
{
m_maxFileSize = (std::max)(maxFileSize, static_cast<size_t>(1000)); // set a lower limit for the maxFileSize
}
void rollLogFiles()
{
m_file.close();
util::nstring lastFileName = buildFileName(m_maxFiles - 1);
util::File::unlink(lastFileName.c_str());
for (int fileNumber = m_maxFiles - 2; fileNumber >= 0; --fileNumber)
{
util::nstring currentFileName = buildFileName(fileNumber);
util::nstring nextFileName = buildFileName(fileNumber + 1);
util::File::rename(currentFileName.c_str(), nextFileName.c_str());
}
openLogFile();
m_firstWrite = false;
}
private:
void openLogFile()
{
util::nstring fileName = buildFileName();
m_fileSize = m_file.open(fileName.c_str());
if (0 == m_fileSize)
{
size_t bytesWritten = m_file.write(Converter::header(Formatter::header()));
if (static_cast<size_t>(-1) != bytesWritten)
{
m_fileSize += bytesWritten;
}
}
}
util::nstring buildFileName(int fileNumber = 0)
{
util::nostringstream ss;
ss << m_fileNameNoExt;
if (fileNumber > 0)
{
ss << '.' << fileNumber;
}
if (!m_fileExt.empty())
{
ss << '.' << m_fileExt;
}
return ss.str();
}
private:
util::Mutex m_mutex;
util::File m_file;
size_t m_fileSize;
size_t m_maxFileSize;
int m_maxFiles;
util::nstring m_fileExt;
util::nstring m_fileNameNoExt;
bool m_firstWrite;
};
}
Is there code or compiler settings that can be modified to fix/remove the references to __tls_array / __tls_index.
This occurs in both debug & release builds.
[1]: https://github.com/SergiusTheBest/plog
Setting compiler option /Zc:threadSafeInit- removes the references to __tls_array and __tls_index and stops the access violation crash.
Microsoft documentation here mentions:
In the C++11 standard, block scope variables with static or thread
storage duration must be zero-initialized before any other
initialization takes place. Initialization occurs when control first
passes through the declaration of the variable. If an exception is
thrown during initialization, the variable is considered
uninitialized, and initialization is re-attempted the next time
control passes through the declaration. If control enters the
declaration concurrently with initialization, the concurrent execution
blocks while initialization is completed. The behavior is undefined if
control re-enters the declaration recursively during initialization.
By default, Visual Studio starting in Visual Studio 2015 implements
this standard behavior. This behavior may be explicitly specified by
setting the /Zc:threadSafeInit compiler option.
The /Zc:threadSafeInit compiler option is on by default. The
/permissive- option does not affect /Zc:threadSafeInit.
Thread-safe initialization of static local variables relies on code
implemented in the Universal C run-time library (UCRT). To avoid
taking a dependency on the UCRT, or to preserve the non-thread-safe
initialization behavior of versions of Visual Studio prior to Visual
Studio 2015, use the /Zc:threadSafeInit- option. If you know that
thread-safety is not required, use this option to generate slightly
smaller, faster code around static local declarations.
Thread-safe static local variables use thread-local storage (TLS)
internally to provide efficient execution when the static has already
been initialized. The implementation of this feature relies on Windows
operating system support functions in Windows Vista and later
operating systems. Windows XP, Windows Server 2003, and older
operating systems do not have this support, so they do not get the
efficiency advantage. These operating systems also have a lower limit
on the number of TLS sections that can be loaded. Exceeding the TLS
section limit can cause a crash. If this is a problem in your code,
especially in code that must run on older operating systems, use
/Zc:threadSafeInit- to disable the thread-safe initialization code.

Create an Arduino ESP8266 library

I would like to create a Arduino library for an ESP8266or ESP32 microcontroller. I wrote a test library which running on an Arduino Nano board with no problem. Here the library cpp file:
#include "Test.h"
Test::Test(){
}
uint32_t Test::libTest(strcttest* t){
uint32_t w;
w = t->a;
return w;
}
Here's the the header file :
#include <Arduino.h>
typedef struct {
uint32_t a;
uint32_t b;
}strcttest;
class Test
{
public:
Test();
uint32_t libTest(strcttest* t);
private:
};
And last but not least the Arduino ino file:
#include <Test.h>
//Instante Test
Test t;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("Start");
}
void loop() {
// put your main code here, to run repeatedly:
//Create structure
strcttest *tt;
tt->a=1;
tt->b=2;
//Output result
Serial.println (t.libTest(tt));
delay(1000);
}
Every compile fine with an Arduino Nano board as well as with ESP8266/ESP32 boards. When I run it on the Nano Board i get the expected result:
Start
1
1
1
1
1
1
1
1
1
...
When I run it on the ESP8266 board I get the following crash result:
l*⸮⸮⸮⸮CI>⸮⸮⸮HB⸮⸮Start
Exception (28):
epc1=0x402024f8 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000
ctx: cont
sp: 3ffef7d0 end: 3ffef9a0 offset: 01a0
>>>stack>>>
3ffef970: feefeffe 00000000 3ffee950 40201eb4
3ffef980: feefeffe feefeffe 3ffee96c 40202340
3ffef990: feefeffe feefeffe 3ffee980 40100108
<<<stack<<<
7!a!*6⸮⸮⸮Start
Exception (28):
epc1=0x402024f8 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000
ctx: cont
sp: 3ffef7d0 end: 3ffef9a0 offset: 01a0
>>>stack>>>
3ffef970: feefeffe 00000000 3ffee950 40201eb4
3ffef980: feefeffe feefeffe 3ffee96c 40202340
3ffef990: feefeffe feefeffe 3ffee980 40100108
<<<stack<<<
ĜBs⸮`⸮"⸮⸮Start
...
And last but not least on the ESP Development board I receive:
i%M/⸮`⸮i%M7
⸮⸮%Q=qU=\Md⸮aGd<$⸮Start
Guru Meditation Error of type LoadProhibited occurred on core 1. Exception was unhandled.
Register dump:
PC : 0x400dde93 PS : 0x00060030 A0 : 0x800d0570 A1 : 0x3ffc7390
A2 : 0x3ffc1c30 A3 : 0x00000000 A4 : 0x0800001c A5 : 0xffffffff
A6 : 0xffffffff A7 : 0x00060d23 A8 : 0x800832e9 A9 : 0x3ffc7380
A10 : 0x00000003 A11 : 0x00060023 A12 : 0x00060020 A13 : 0x00000003
A14 : 0x00000001 A15 : 0x00000000 SAR : 0x0000001f EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff
Backtrace: 0x400dde93:0x3ffc7390 0x400d0570:0x3ffc73b0 0x400d79b0:0x3ffc73d0
CPU halted.
So my question is: What I am doing wrong. What do i miss. What I haven't understood with Arduino IDE, cpp, pointers, etc.
Sorry I forgot: I use Arduino IDE 1.8.2
strcttest *tt; is your problem. You're not allocating memory for and creating an object of type strcttest - you're merely allocating memory for a pointer to an object of that type. Basically, the code should crash everywhere when your code gets to the line tt->a=1; The fact that it doesn't when run on the Nano is basically dumb luck..
Think of the case where you have a char* variable and then try to copy a string to it - it will crash too, since you dont have any storage space for the string itself - you only have a few bytes allocated that store the address of the string.
The following is a more reasonable implementation of your void loop() function:
void loop() {
// put your main code here, to run repeatedly:
//Create structure
strcttest tt;
tt.a=1;
tt.b=2;
//Output result
Serial.println (t.libTest(&tt));
delay(1000);
}
Another (slower, due to use of new and delete) implementation may look like this:
void loop() {
// put your main code here, to run repeatedly:
//Create structure
strcttest *tt = new strcttest;
tt->a=1;
tt->b=2;
//Output result
Serial.println (t.libTest(tt));
delete tt;
delay(1000);
}
For ESP32 and ESP8266, have a excellent tool to help in crashes situations,
like that You report.
This integrates to Arduino IDE
See it in: https://github.com/me-no-dev/EspExceptionDecoder

How do I discern 2 or more simultaneous IR inputs?

I am trying to create a student response system for a Jeopardy-like game using cheap tv remote controls. They are infrared, NEC protocol. A serial monitor displays button press from students in order they respond.
I'm using a TSOP 4838 receiver connected to an Arduino Uno with a capacitor and so far just the serial monitor that comes with the Arduino IDE software. My code appears below.
All is working well as long as 2 or more students do not press buttons within a half-second of each other. If that happens, I get no output on the serial monitor. I'm hoping there is some change I can make to my sketch or to the IRremote.h or IRremoteInt.h files to discern the signals quicker so my display lists who clicked first.
IRremote.h:
*/
* IRremote v1.1
* By Chris Targett
* November 2011
*
* Based on Ken Shirriff's Version 0.11 of his IR-Remote library August, 2009
* https://github.com/shirriff/Arduino-IRremote
*/
#ifndef IRremote_h
#define IRremote_h
// The following are compile-time library options.
// If you change them, recompile the library.
// If DEBUG is defined, a lot of debugging output will be printed during decoding.
// TEST must be defined for the IRtest unittests to work. It will make some
// methods virtual, which will be slightly slower, which is why it is optional.
// #define DEBUG
// #define TEST
// Results returned from the decoder
class decode_results {
public:
int decode_type; // NEC, SONY, RC5, RC6, DISH, SHARP, SAMSUNG, JVC, UNKNOWN
unsigned long value; // Decoded value
unsigned long address; // address for panasonic codes
int bits; // Number of bits in decoded value
volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks
int rawlen; // Number of records in rawbuf.
};
// Values for decode_type
#define NEC 1
#define SONY 2
#define RC5 3
#define RC6 4
#define DISH 5
#define SHARP 6
#define SAMSUNG 7
#define JVC 8
#define PANASONIC 9
#define UNKNOWN -1
// Decoded value for NEC when a repeat code is received
#define REPEAT 0xffffffff
// main class for receiving IR
class IRrecv
{
public:
IRrecv(int recvpin);
void blink13(int blinkflag);
int decode(decode_results *results);
void enableIRIn();
void resume();
private:
// These are called by decode
int getRClevel(decode_results *results, int *offset, int *used, int t1);
long decodeNEC(decode_results *results);
long decodeSony(decode_results *results);
long decodeSamsung(decode_results *results);
long decodeRC5(decode_results *results);
long decodeRC6(decode_results *results);
long decodeJVC(decode_results *results);
long decodeHash(decode_results *results);
long decodePanasonic(decode_results *results);
int compare(unsigned int oldval, unsigned int newval);
}
;
// Only used for testing; can remove virtual for shorter code
#ifdef TEST
#define VIRTUAL virtual
#else
#define VIRTUAL
#endif
class IRsend
{
public:
IRsend() {}
void sendNEC(unsigned long data, int nbits);
void sendSony(unsigned long data, int nbits);
void sendSamsung(unsigned long data, int nbits);
void sendRaw(unsigned int buf[], int len, int hz);
void sendRC5(unsigned long data, int nbits);
void sendRC6(unsigned long long data, int nbits);
void sendDISH(unsigned long data, int nbits);
void sendSharp(unsigned long data, int nbits);
void sendJVC(unsigned long data, int nbits, int repeat);
void sendPanasonic(unsigned long address, unsigned long data);
// private:
void enableIROut(int khz);
VIRTUAL void mark(int usec);
VIRTUAL void space(int usec);
}
;
// Some useful constants
#define USECPERTICK 50
#define RAWBUF 76
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 100
#endif
Here is the IRremoteInt.h
/*
* IRremote v1.1
* By Chris Targett
* November 2011
*
* Based on Ken Shirriff's Version 0.11 of his IR-Remote library August, 2009
* https://github.com/shirriff/Arduino-IRremote
*/
#ifndef IRremoteint_h
#define IRremoteint_h
#include <Arduino.h>
#define CLKFUDGE 5 // fudge factor for clock interrupt overhead
#define CLK 256 // max value for clock (timer 2)
#define PRESCALE 8 // timer2 clock prescale
#define SYSCLOCK 16000000 // main Arduino clock
#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000) // timer clocks per microsecond
#define ERR 0
#define DECODED 1
#define BLINKLED 13
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// clock timer reset value
#define INIT_TIMER_COUNT2 (CLK - USECPERTICK*CLKSPERUSEC + CLKFUDGE)
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT2
// pulse parameters in usec
#define NEC_HDR_MARK 9000
#define NEC_HDR_SPACE 4500
#define NEC_BIT_MARK 560
#define NEC_ONE_SPACE 1600
#define NEC_ZERO_SPACE 560
#define NEC_RPT_SPACE 2250
#define SONY_HDR_MARK 2400
#define SONY_HDR_SPACE 600
#define SONY_ONE_MARK 1200
#define SONY_ZERO_MARK 600
#define SONY_RPT_LENGTH 45000
#define RC5_T1 889
#define RC5_RPT_LENGTH 46000
#define RC6_HDR_MARK 2666
#define RC6_HDR_SPACE 889
#define RC6_T1 444
#define RC6_RPT_LENGTH 46000
#define SAMSUNG_HDR_MARK 4500
#define SAMSUNG_BITS 32
#define SAMSUNG_HDR_SPACE 4500
#define SAMSUNG_BIT_MARK 560
#define SAMSUNG_ONE_SPACE 1600
#define SAMSUNG_ZERO_SPACE 600
#define SHARP_BIT_MARK 245
#define SHARP_ONE_SPACE 1805
#define SHARP_ZERO_SPACE 795
#define SHARP_GAP 600000
#define SHARP_TOGGLE_MASK 0x3FF
#define SHARP_RPT_SPACE 3000
#define DISH_HDR_MARK 400
#define DISH_HDR_SPACE 6100
#define DISH_BIT_MARK 400
#define DISH_ONE_SPACE 1700
#define DISH_ZERO_SPACE 2800
#define DISH_RPT_SPACE 6200
#define DISH_TOP_BIT 0x8000
#define SHARP_BITS 15
#define DISH_BITS 16
#define JVC_HDR_MARK 8000
#define JVC_HDR_SPACE 4000
#define JVC_BIT_MARK 600
#define JVC_ONE_SPACE 1600
#define JVC_ZERO_SPACE 550
#define JVC_RPT_LENGTH 60000
#define PANASONIC_HDR_MARK 3502
#define PANASONIC_HDR_SPACE 1750
#define PANASONIC_BIT_MARK 502
#define PANASONIC_ONE_SPACE 1244
#define PANASONIC_ZERO_SPACE 370
#define TOLERANCE 25 // percent tolerance in measurements
#define LTOL (1.0 - TOLERANCE/100.)
#define UTOL (1.0 + TOLERANCE/100.)
#define _GAP 5000 // Minimum map between transmissions
#define GAP_TICKS (_GAP/USECPERTICK)
#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))
#ifndef DEBUG
#define MATCH(measured_ticks, desired_us) ((measured_ticks) >= TICKS_LOW(desired_us) && (measured_ticks) <= TICKS_HIGH(desired_us))
#define MATCH_MARK(measured_ticks, desired_us) MATCH(measured_ticks, (desired_us) + MARK_EXCESS)
#define MATCH_SPACE(measured_ticks, desired_us) MATCH((measured_ticks), (desired_us) - MARK_EXCESS)
// Debugging versions are in IRremote.cpp
#endif
// receiver states
#define STATE_IDLE 2
#define STATE_MARK 3
#define STATE_SPACE 4
#define STATE_STOP 5
// information for the interrupt handler
typedef struct {
uint8_t recvpin; // pin for IR data from detector
uint8_t rcvstate; // state machine
uint8_t blinkflag; // TRUE to enable blinking of pin 13 on IR processing
unsigned int timer; // state timer, counts 50uS ticks.
unsigned int rawbuf[RAWBUF]; // raw data
uint8_t rawlen; // counter of entries in rawbuf
}
irparams_t;
// Defined in IRremote.cpp
extern volatile irparams_t irparams;
// IR detector output is active low
#define MARK 0
#define SPACE 1
#define TOPBIT 0x80000000
#define NEC_BITS 32
#define SONY_BITS 12
#define JVC_BITS 32
#define MIN_RC5_SAMPLES 11
#define MIN_RC6_SAMPLES 1
#endif
and here's my sketch:
#include <IRremote.h>
#include <IRremoteInt.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
}
void loop()
{
if (irrecv.decode(&results))
{
if (results.value == 551520375) { //1
Serial.println("Team 1");
}
if (results.value == 551504055) { //2
Serial.println("Team 2");
}
if (results.value == 551536695) { //3
Serial.println("Team 3");
}
if (results.value == 551495895) { //4
Serial.println("Team 4");
}
if (results.value == 551528535) { //5
Serial.println("Team 5");
}
if (results.value == 551512215) { //6
Serial.println("Team 6");
}
if (results.value == 551544855) { //7
Serial.println("Team 7");
}
if (results.value == 551491815) { //8
Serial.println("Team 8");
}
if (results.value == 551524455) { //9
Serial.println("Team 9");
}
if (results.value == 551487735) { //10
Serial.println("Team 10");
}
// Serial.println(results.value);
irrecv.resume(); // Receive the next value
}
}
In short - Not really and not reliably. The problem is that your system is effectively multi-dropped. The receiver is the seeing the sum of both transmitters. Where the modulation and encoded signal are summed up and thus corrupted.
I have IR toy magic wands, for dueling I have a the winner keep transmitting as to JAM the looser latter signal.
You could try to use TWO different modulation frequencies. One remote at 36K and the other at 60K. 38K is typical and there is significant overlap. I have seen 36 and 40 get heard or corrupt 38K. So I would got to the farthest ends of available demodulator chips; being 36K and 60K. However, I suspect you are using provided transmitters which may not be changed. So you will have to find some or build one.
Additionally using pre-built ones, you are at the mercy of its behavior. You stated 1/2 second. That is likely because they are re-transmitting retries and have start delays and pauses beyond that of the NEC frame being sent.
You could also implement RX/TX pairs that are different IR wavelength. However, most purchasable demodulator IC's are on standard wavelength. I also recommend not building a discrete RX when possible, as they integrated RX/Demodulators have Auto GAIN, stuff like that.

BeagleBone Black interrupts through kernel driver

I'm trying to work with interruptions but I get the following error, due to ioread32.
As I have seen in the chapter "25.3.3 Interrupt Features" of "AM335x SitaraTM Processors - Technical Reference Manual"
In order to generate an interrupt request to a host processor upon a defined event (level or logic transition) occurring on a GPIO pin, the GPIO configuration registers have to be programmed as follows:
• Interrupts for the GPIO channel must be enabled in the GPIO_IRQSTATUS_SET_0 and/or GPIO_IRQSTATUS_SET_1 registers.
• The expected event(s) on input GPIO to trigger the interrupt request has to be selected in the GPIO_LEVELDETECT0, GPIO_LEVELDETECT1, GPIO_RISINGDETECT, and GPIO_FALLINGDETECT registers.
[ 1737.604270] Loading hello_interrupts module...
[ 1737.604426] HI: Initialized GPIO #36 to IRQ #164
[ 1737.604478] Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa1ac02c
[ 1737.612611] Internal error: : 1028 [#1] SMP THUMB2
[ 1737.617696] Modules linked in: hello_interrupts(O+) g_multi libcomposite omap_rng mt7601Usta(O) [last unloaded: hello_interrupts]
[ 1737.630128] CPU: 0 Tainted: G O (3.8.13-bone67 #1)
[ 1737.636513] PC is at hello_interrupts_start+0x8b/0x123 [hello_interrupts]
[ 1737.643717] LR is at _raw_read_unlock+0x7/0x8
[ 1737.648340] pc : [<bf8f508c>] lr : [<c04cfaf7>] psr: 80000033
[ 1737.648340] sp : df3fde60 ip : 00000034 fp : c006a001
[ 1737.660481] r10: 00000001 r9 : de594200 r8 : bf8f5001
[ 1737.666011] r7 : 00000000 r6 : bf8f30b8 r5 : 00000000 r4 : fa1ac000
[ 1737.672920] r3 : 48000000 r2 : 00000000 r1 : 481adfff r0 : fa1ac000
[ 1737.679839] Flags: Nzcv IRQs on FIQs on Mode SVC_32 ISA Thumb Segment user
[ 1737.687569] Control: 50c5387d Table: 9f740019 DAC: 00000015
[ 1737.693655] Process insmod (pid: 3040, stack limit = 0xdf3fc240)
[ 1737.700025] Stack: (0xdf3fde60 to 0xdf3fe000)
[ 1737.704659] de60: bf8f30b8 00000000 00400100 df3fc000 c08b5740 c000867f 00000000 de5c3640
[ 1737.713323] de80: 00000000 00000000 00400100 bf8f326c bf8f3260 00000001 bf8f32a8 00000001
[ 1737.721988] dea0: c006a001 c006bd31 bf8f326c 00007fff c0069101 e0dd7000 e0dd6fff bf8f3260
[ 1737.730655] dec0: 00000000 b6f7dd50 df3fc000 bf8f33b4 e0dd6691 c02520d0 6e72656b 00006c65
[ 1737.739320] dee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1737.747993] df00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1737.756662] df20: 00000000 00000000 00000000 c0790a68 20000033 000016a8 b6fa2000 b6f7dd50
[ 1737.765331] df40: 00000080 c000c9e4 df3fc000 00000000 00000000 c006c26f e0dd5000 000016a8
[ 1737.774000] df60: e0dd5ae0 e0dd599f e0dd64c8 000003c8 000004c8 00000000 00000000 00000000
[ 1737.782670] df80: 0000001c 0000001d 00000014 00000012 00000010 00000000 00000000 b6fc0088
[ 1737.791339] dfa0: b6fc0d00 c000c841 00000000 b6fc0088 b6fa2000 000016a8 b6f7dd50 00000002
[ 1737.800008] dfc0: 00000000 b6fc0088 b6fc0d00 00000080 00000000 b6f7dd50 000016a8 00000000
[ 1737.808671] dfe0: 00000000 beb7969c b6f77b07 b6f01fd4 80000010 b6fa2000 c0c92420 c0c92440
[ 1737.817378] [<bf8f508c>] (hello_interrupts_start+0x8b/0x123 [hello_interrupts]) from [<c000867f>] (do_one_initcall+0x1f/0xf4)
[ 1737.829367] [<c000867f>] (do_one_initcall+0x1f/0xf4) from [<c006bd31>] (load_module+0x10d5/0x15b0)
[ 1737.838872] [<c006bd31>] (load_module+0x10d5/0x15b0) from [<c006c26f>] (sys_init_module+0x63/0x88)
[ 1737.848379] [<c006c26f>] (sys_init_module+0x63/0x88) from [<c000c841>] (ret_fast_syscall+0x1/0x46)
[ 1737.857867] Code: 4825 f3d4 debb e036 (6ac5) f3bf
[ 1737.884765] ---[ end trace cbd53ac03b070f86 ]---
This is my code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
MODULE_AUTHOR("MGE");
MODULE_DESCRIPTION("A sample driver using interrupts");
MODULE_LICENSE("GPL");
// GPIO Bank 2
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)
// GPIO memory-mapped register addresses.
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define PIN_A_GPIO 36
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A"
static irqreturn_t irq_handler_pin_a (int irq, void *dev_id) {
printk (KERN_INFO "Hello from irq_handler_pin_a...\n");
return IRQ_HANDLED;
}
static int __init hello_interrupts_start (void) {
int retval, irq, regval;
void __iomem *mem;
printk (KERN_INFO "Loading hello_interrupts module...\n");
/**
* Request the GPIO lines for the IRQ channels.
*/
retval = gpio_request_one(PIN_A_GPIO, PIN_A_FLAGS, PIN_A_LABEL);
if (retval) {
printk (KERN_ERR "HI: Error: Failed to request GPIO pin#%i for IRQ (error %i)\n", PIN_A_GPIO, retval);
// return -retval;
}
irq = gpio_to_irq (PIN_A_GPIO);
if (irq < 0) {
printk (KERN_ERR "HI: ERROR: Failed to obtain IRQ number for GPIO #%i (error %i)\n", PIN_A_GPIO, irq);
// return -irq;
}
retval = request_irq (irq, irq_handler_pin_a, 0 /*IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING*/, PIN_A_LABEL, NULL);
irq_set_irq_type (irq, IRQ_TYPE_EDGE_BOTH);
if (retval) {
printk (KERN_ERR "HI: ERROR: The requested IRQ line#%i from GPIO#%i (error %i)\n", irq, PIN_A_GPIO, retval);
// return -retval;
}
else {
printk (KERN_INFO "HI: Initialized GPIO #%i to IRQ #%i\n", PIN_A_GPIO, irq);
}
/**
* Setup the IRQ registers with the appropriate values.
*/
mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
if(!mem) {
printk (KERN_ERR "HI: ERROR: Failed to remap memory for GPIO Bank 2 IRQ pin configuration.\n");
return 0;
}
// Enable the IRQ ability for GPIO_66.
regval = ioread32 (mem + GPIO_IRQSTATUS_0);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
regval = ioread32 (mem + GPIO_IRQSTATUS_1);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
// Set GPIO_66 for rising and falling edge detection.
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32(regval, mem + GPIO_RISINGDETECT);
regval = ioread32 (mem + GPIO_FALLINGDETECT);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_FALLINGDETECT);
// Release the mapped memory.
iounmap (mem);
return 0;
}
static void __exit hello_interrupts_end(void) {
printk ("HI: Releasing IRQ resources...\n");
free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
gpio_free (PIN_A_GPIO);
printk (KERN_INFO "Goodbye hello_interrupts!\n");
}
module_init (hello_interrupts_start);
module_exit (hello_interrupts_end);
Any idea?
Thanks
The problem was that the GPIO2 module clocks was disabled.
"8.1.12.1.30 CM_PER_GPIO2_CLKCTRL Register (offset = B0h) [reset = 30000h]" of "AM335x SitaraTM Processors - Technical Reference Manual"
Bits 1-0:
Control the way mandatory clocks are managed.
0x0 = DISABLED : Module is disable by SW. Any OCP access to module results in an error, except if resulting from a module wakeup (asynchronous wakeup).
0x1 = RESERVED_1 : Reserved
0x2 = ENABLE : Module is explicitly enabled. Interface clock (if not used for functions) may be gated according to the clock domain state. Functional clocks are guarantied to stay present. As long as in this configuration, power domain sleep transition cannot happen.
0x3 = RESERVED : Reserved
For the above code to work, the GPIO2 clock has to be enabled using the CM_PER_GPIO2_CLKCTRL register and a GPIO pin from GPIO2 has to be choosen. In the code above, GPIO 36 was used, which is on GPIO1 (and anyway used by the internal flash). The following code enables the GPIO2 clock and uses GPIO 68 (which is on header P9 pin 10 btw):
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
MODULE_AUTHOR("MGE");
MODULE_DESCRIPTION("A sample driver using interrupts");
MODULE_LICENSE("GPL");
// GPIO Bank 2
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)
// CM_PER (Clock Module Peripheral Registers
#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE 0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0
// GPIO memory-mapped register addresses.
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define PIN_A_GPIO 68 // is on P9 pin 10
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A"
static irqreturn_t irq_handler_pin_a (int irq, void *dev_id) {
printk (KERN_INFO "Hello from irq_handler_pin_a...\n");
return IRQ_HANDLED;
}
static int __init hello_interrupts_start (void) {
int retval, irq, regval;
void __iomem *mem;
void __iomem *cm_per;
printk (KERN_INFO "Loading hello_interrupts module...\n");
/**
* Request the GPIO lines for the IRQ channels.
*/
retval = gpio_request_one(PIN_A_GPIO, PIN_A_FLAGS, PIN_A_LABEL);
if (retval) {
printk (KERN_ERR "HI: Error: Failed to request GPIO pin#%i for IRQ (error %i)\n", PIN_A_GPIO, retval);
// return -retval;
}
irq = gpio_to_irq (PIN_A_GPIO);
if (irq < 0) {
printk (KERN_ERR "HI: ERROR: Failed to obtain IRQ number for GPIO #%i (error %i)\n", PIN_A_GPIO, irq);
// return -irq;
}
retval = request_irq (irq, irq_handler_pin_a, 0 /*IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING*/, PIN_A_LABEL, NULL);
irq_set_irq_type (irq, IRQ_TYPE_EDGE_BOTH);
if (retval) {
printk (KERN_ERR "HI: ERROR: The requested IRQ line#%i from GPIO#%i (error %i)\n", irq, PIN_A_GPIO, retval);
// return -retval;
}
else {
printk (KERN_INFO "HI: Initialized GPIO #%i to IRQ #%i\n", PIN_A_GPIO, irq);
}
/*
Enable GPIO2 clock
*/
cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
if(!cm_per) {
printk (KERN_ERR "HI: ERROR: Failed to remap memory for CM_PER.\n");
return 0;
}
iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
iounmap(cm_per);
/**
* Setup the IRQ registers with the appropriate values.
*/
mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
if(!mem) {
printk (KERN_ERR "HI: ERROR: Failed to remap memory for GPIO Bank 2 IRQ pin configuration.\n");
return 0;
}
// Enable the IRQ ability for GPIO_66.
regval = ioread32 (mem + GPIO_IRQSTATUS_0);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
regval = ioread32 (mem + GPIO_IRQSTATUS_1);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
// Set GPIO_66 for rising and falling edge detection.
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32(regval, mem + GPIO_RISINGDETECT);
regval = ioread32 (mem + GPIO_FALLINGDETECT);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_FALLINGDETECT);
// Release the mapped memory.
iounmap (mem);
return 0;
}
static void __exit hello_interrupts_end(void) {
printk ("HI: Releasing IRQ resources...\n");
free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
gpio_free (PIN_A_GPIO);
printk (KERN_INFO "Goodbye hello_interrupts!\n");
}
module_init (hello_interrupts_start);
module_exit (hello_interrupts_end);

Unresolved externals error - Visual C++ using FTD2XX.h

I am fairly new to C++ programming, so please bear with me. I am writing a small application in visual studio that would be used to communicate with an FTDI module (UM232H high speed USB module). FTDI provides the D2XX drivers for this module and is readily available on their website. Right now the program I have is very simple. It is calling a function called FT_Open (ftd2xx.h) to simply open the device and top check to see if the device is connected to the computer.
However right now I keep getting the error LNK2019, unresolved external symbol. Now I did read through the application note provide by Visual Studio website but I still can not seem to resolve my error. I think I am making a silly mistake and would like some guidance from you guys, if you guys could help me out.
I have provide my code as well as the header file (ftd2xx.h) that was provide from the FTDI website.
Main Program:
// ConsoleApplication2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "ftd2xx.h"
#include <iostream>
using namespace std;
FT_HANDLE ftHandle;
FT_STATUS ftStatus;
int main(){
ftStatus = FT_Open(0,&ftHandle);
if (ftStatus == FT_OK) {
cout << "hello world";
// FT_Open OK, use ftHandle to access device
}
else {
// FT_Open failed
}
return 0;
}
ftd2xx.h:
#include "windows.h"
/*#include <stdarg.h>
#include <windef.h>
#include <winnt.h>
#include <winbase.h>*/
/*++
Copyright © 2001-2011 Future Technology Devices International Limited
THIS SOFTWARE IS PROVIDED BY FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
FTDI DRIVERS MAY BE USED ONLY IN CONJUNCTION WITH PRODUCTS BASED ON FTDI PARTS.
FTDI DRIVERS MAY BE DISTRIBUTED IN ANY FORM AS LONG AS LICENSE INFORMATION IS NOT MODIFIED.
IF A CUSTOM VENDOR ID AND/OR PRODUCT ID OR DESCRIPTION STRING ARE USED, IT IS THE
RESPONSIBILITY OF THE PRODUCT MANUFACTURER TO MAINTAIN ANY CHANGES AND SUBSEQUENT WHQL
RE-CERTIFICATION AS A RESULT OF MAKING THESE CHANGES.
Module Name:
ftd2xx.h
Abstract:
Native USB device driver for FTDI FT232x, FT245x, FT2232x and FT4232x devices
FTD2XX library definitions
Environment:
kernel & user mode
--*/
#ifndef FTD2XX_H
#define FTD2XX_H
// The following ifdef block is the standard way of creating macros
// which make exporting from a DLL simpler. All files within this DLL
// are compiled with the FTD2XX_EXPORTS symbol defined on the command line.
// This symbol should not be defined on any project that uses this DLL.
// This way any other project whose source files include this file see
// FTD2XX_API functions as being imported from a DLL, whereas this DLL
// sees symbols defined with this macro as being exported.
#ifdef FTD2XX_EXPORTS
#define FTD2XX_API __declspec(dllexport)
#else
#define FTD2XX_API __declspec(dllimport)
#endif
typedef PVOID FT_HANDLE;
typedef ULONG FT_STATUS;
//
// Device status
//
enum {
FT_OK,
FT_INVALID_HANDLE,
FT_DEVICE_NOT_FOUND,
FT_DEVICE_NOT_OPENED,
FT_IO_ERROR,
FT_INSUFFICIENT_RESOURCES,
FT_INVALID_PARAMETER,
FT_INVALID_BAUD_RATE,
FT_DEVICE_NOT_OPENED_FOR_ERASE,
FT_DEVICE_NOT_OPENED_FOR_WRITE,
FT_FAILED_TO_WRITE_DEVICE,
FT_EEPROM_READ_FAILED,
FT_EEPROM_WRITE_FAILED,
FT_EEPROM_ERASE_FAILED,
FT_EEPROM_NOT_PRESENT,
FT_EEPROM_NOT_PROGRAMMED,
FT_INVALID_ARGS,
FT_NOT_SUPPORTED,
FT_OTHER_ERROR,
FT_DEVICE_LIST_NOT_READY,
};
#define FT_SUCCESS(status) ((status) == FT_OK)
//
// FT_OpenEx Flags
//
#define FT_OPEN_BY_SERIAL_NUMBER 1
#define FT_OPEN_BY_DESCRIPTION 2
#define FT_OPEN_BY_LOCATION 4
//
// FT_ListDevices Flags (used in conjunction with FT_OpenEx Flags
//
#define FT_LIST_NUMBER_ONLY 0x80000000
#define FT_LIST_BY_INDEX 0x40000000
#define FT_LIST_ALL 0x20000000
#define FT_LIST_MASK (FT_LIST_NUMBER_ONLY|FT_LIST_BY_INDEX|FT_LIST_ALL)
//
// Baud Rates
//
#define FT_BAUD_300 300
#define FT_BAUD_600 600
#define FT_BAUD_1200 1200
#define FT_BAUD_2400 2400
#define FT_BAUD_4800 4800
#define FT_BAUD_9600 9600
#define FT_BAUD_14400 14400
#define FT_BAUD_19200 19200
#define FT_BAUD_38400 38400
#define FT_BAUD_57600 57600
#define FT_BAUD_115200 115200
#define FT_BAUD_230400 230400
#define FT_BAUD_460800 460800
#define FT_BAUD_921600 921600
//
// Word Lengths
//
#define FT_BITS_8 (UCHAR) 8
#define FT_BITS_7 (UCHAR) 7
//
// Stop Bits
//
#define FT_STOP_BITS_1 (UCHAR) 0
#define FT_STOP_BITS_2 (UCHAR) 2
//
// Parity
//
#define FT_PARITY_NONE (UCHAR) 0
#define FT_PARITY_ODD (UCHAR) 1
#define FT_PARITY_EVEN (UCHAR) 2
#define FT_PARITY_MARK (UCHAR) 3
#define FT_PARITY_SPACE (UCHAR) 4
//
// Flow Control
//
#define FT_FLOW_NONE 0x0000
#define FT_FLOW_RTS_CTS 0x0100
#define FT_FLOW_DTR_DSR 0x0200
#define FT_FLOW_XON_XOFF 0x0400
//
// Purge rx and tx buffers
//
#define FT_PURGE_RX 1
#define FT_PURGE_TX 2
//
// Events
//
typedef void (*PFT_EVENT_HANDLER)(DWORD,DWORD);
#define FT_EVENT_RXCHAR 1
#define FT_EVENT_MODEM_STATUS 2
#define FT_EVENT_LINE_STATUS 4
//
// Timeouts
//
#define FT_DEFAULT_RX_TIMEOUT 300
#define FT_DEFAULT_TX_TIMEOUT 300
//
// Device types
//
typedef ULONG FT_DEVICE;
enum {
FT_DEVICE_BM,
FT_DEVICE_AM,
FT_DEVICE_100AX,
FT_DEVICE_UNKNOWN,
FT_DEVICE_2232C,
FT_DEVICE_232R,
FT_DEVICE_2232H,
FT_DEVICE_4232H,
FT_DEVICE_232H,
FT_DEVICE_X_SERIES
};
//
// Bit Modes
//
#define FT_BITMODE_RESET 0x00
#define FT_BITMODE_ASYNC_BITBANG 0x01
#define FT_BITMODE_MPSSE 0x02
#define FT_BITMODE_SYNC_BITBANG 0x04
#define FT_BITMODE_MCU_HOST 0x08
#define FT_BITMODE_FAST_SERIAL 0x10
#define FT_BITMODE_CBUS_BITBANG 0x20
#define FT_BITMODE_SYNC_FIFO 0x40
//
// FT232R CBUS Options EEPROM values
//
#define FT_232R_CBUS_TXDEN 0x00 // Tx Data Enable
#define FT_232R_CBUS_PWRON 0x01 // Power On
#define FT_232R_CBUS_RXLED 0x02 // Rx LED
#define FT_232R_CBUS_TXLED 0x03 // Tx LED
#define FT_232R_CBUS_TXRXLED 0x04 // Tx and Rx LED
#define FT_232R_CBUS_SLEEP 0x05 // Sleep
#define FT_232R_CBUS_CLK48 0x06 // 48MHz clock
#define FT_232R_CBUS_CLK24 0x07 // 24MHz clock
#define FT_232R_CBUS_CLK12 0x08 // 12MHz clock
#define FT_232R_CBUS_CLK6 0x09 // 6MHz clock
#define FT_232R_CBUS_IOMODE 0x0A // IO Mode for CBUS bit-bang
#define FT_232R_CBUS_BITBANG_WR 0x0B // Bit-bang write strobe
#define FT_232R_CBUS_BITBANG_RD 0x0C // Bit-bang read strobe
//
// FT232H CBUS Options EEPROM values
//
#define FT_232H_CBUS_TRISTATE 0x00 // Tristate
#define FT_232H_CBUS_TXLED 0x01 // Tx LED
#define FT_232H_CBUS_RXLED 0x02 // Rx LED
#define FT_232H_CBUS_TXRXLED 0x03 // Tx and Rx LED
#define FT_232H_CBUS_PWREN 0x04 // Power Enable
#define FT_232H_CBUS_SLEEP 0x05 // Sleep
#define FT_232H_CBUS_DRIVE_0 0x06 // Drive pin to logic 0
#define FT_232H_CBUS_DRIVE_1 0x07 // Drive pin to logic 1
#define FT_232H_CBUS_IOMODE 0x08 // IO Mode for CBUS bit-bang
#define FT_232H_CBUS_TXDEN 0x09 // Tx Data Enable
#define FT_232H_CBUS_CLK30 0x0A // 30MHz clock
#define FT_232H_CBUS_CLK15 0x0B // 15MHz clock
#define FT_232H_CBUS_CLK7_5 0x0C // 7.5MHz clock
//
// FT X Series CBUS Options EEPROM values
//
#define FT_X_SERIES_CBUS_TRISTATE 0x00 // Tristate
#define FT_X_SERIES_CBUS_RXLED 0x01 // Tx LED
#define FT_X_SERIES_CBUS_TXLED 0x02 // Rx LED
#define FT_X_SERIES_CBUS_TXRXLED 0x03 // Tx and Rx LED
#define FT_X_SERIES_CBUS_PWREN 0x04 // Power Enable
#define FT_X_SERIES_CBUS_SLEEP 0x05 // Sleep
#define FT_X_SERIES_CBUS_DRIVE_0 0x06 // Drive pin to logic 0
#define FT_X_SERIES_CBUS_DRIVE_1 0x07 // Drive pin to logic 1
#define FT_X_SERIES_CBUS_IOMODE 0x08 // IO Mode for CBUS bit-bang
#define FT_X_SERIES_CBUS_TXDEN 0x09 // Tx Data Enable
#define FT_X_SERIES_CBUS_CLK24 0x0A // 24MHz clock
#define FT_X_SERIES_CBUS_CLK12 0x0B // 12MHz clock
#define FT_X_SERIES_CBUS_CLK6 0x0C // 6MHz clock
#define FT_X_SERIES_CBUS_BCD_CHARGER 0x0D // Battery charger detected
#define FT_X_SERIES_CBUS_BCD_CHARGER_N 0x0E // Battery charger detected inverted
#define FT_X_SERIES_CBUS_I2C_TXE 0x0F // I2C Tx empty
#define FT_X_SERIES_CBUS_I2C_RXF 0x10 // I2C Rx full
#define FT_X_SERIES_CBUS_VBUS_SENSE 0x11 // Detect VBUS
#define FT_X_SERIES_CBUS_BITBANG_WR 0x12 // Bit-bang write strobe
#define FT_X_SERIES_CBUS_BITBANG_RD 0x13 // Bit-bang read strobe
#define FT_X_SERIES_CBUS_TIMESTAMP 0x14 // Toggle output when a USB SOF token is received
#define FT_X_SERIES_CBUS_KEEP_AWAKE 0x15 //
// Driver types
#define FT_DRIVER_TYPE_D2XX 0
#define FT_DRIVER_TYPE_VCP 1
#ifdef __cplusplus
extern "C" {
#endif
FTD2XX_API
FT_STATUS WINAPI FT_Open(
int deviceNumber,
FT_HANDLE *pHandle
);
--Rest of the of the header file was omitted because of the limit to the number of characters I could write.
Sorry for the large amount of code I provided here, I just wanted to be sure that I provided everything that I possibly could. Let me know if I would need to provide the rest of the header file.
Maybe it is bit later for an answer.
I got same error with old outdated ftd2xx.lib file.
Afetr adding new ftd2xx.lib, ftd2xx.dll and ftd2xx.h files, cleaning and rebuilding the project a problem was solved.
Have you made sure to include the .lib your compiler will need to link against? Along with any header files, they probably provided a .lib and/or .dll.
If you use the static version of the .lib, you will have to define FTD2XX_STATIC to the preprocessor, as explained in the documentation (chapter 2.4 of Instructions on Including the D2XX
Driver in a VS Express Project).