X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f Newsgroups: comp.os.msdos.djgpp Date: Fri, 15 May 2009 04:37:54 GMT From: "A. Wik" Subject: Re: An interrupt drived uart program dead In-Reply-To: Message-ID: References: Organization: DOS Research Labs Mail-To-News-Contact: abuse AT dizum DOT com To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp Reply-To: djgpp AT delorie DOT com Errors-To: nobody AT delorie DOT com X-Mailing-List: djgpp AT delorie DOT com X-Unsubscribes-To: listserv AT delorie DOT com Precedence: bulk On Thu, 14 May 2009, [ISO-2022-JP] ¾®¸ÑÀç wrote: > I wrote a program under djgpp to drive PC UART. the program is > interrupt-drived. When run the program, the data has sent, but then > the PC halt. I can't find any bug in the program. So ask for help. > below is the program code. > > #include > #include > #include > #include > #include > #include > > #define LOCK_VARIABLE(x) _go32_dpmi_lock_data((void *)&x,(long) > sizeof(x)); > #define LOCK_FUNCTION(x) _go32_dpmi_lock_code(x,(long)sizeof(x)); The smallest object you can lock with DPMI lock is a page, which on the x86 is never smaller than 4096 bytes in size (the VAX, which has the smallest pages as far as I know, uses 512). I don't know how these _go32.*lock*() routines react if you specify sizes that aren't a multiple of 4096, so you might want to verify that. Anyway, looking further down, you don't seem to be calling the locking routines mentioned above. If you're working under an environment that does page swapping, demand paging, etc. you should lock all code and data needed at interrupt time (including the stack). Based on the code below, I presume that you're working in a plain DOS environment with a non-paging DPMI host, in which case the above locking issue is unlikely to be of relevance. > const unsigned int baseAddress = 0x3f8; > const byte commIrq = 0x04; > const byte commIntr = 0x0c; > bool txIdle = true; > > _go32_dpmi_seginfo OldISR, NewISR; > byte oldIMR; > > void commISR(); I'm not certain that the above is sufficient to declare an interrupt handler. You may have to add some attribute that informs the compiler not to make any assumptions about the values of different registers upon entry to the procedure, and furthermore, to comply with all requirements applicable to an interrupt handler, such as saving and restoring all registers modified. Stacks may have to be switched as well. Perhaps the DJGPP routines (_go32_dpmi.* etc.) that you use to install the handler also makes the necessary arrangements, so that you don't have to worry, but you need to verify that. Furthermore, it is important to instruct the compiler not to make certain optimisations, such as reordering statements that interact with the hardware, as that may produce unpredictable results. > > _go32_dpmi_get_protected_mode_interrupt_vector(commIntr, &OldISR); > NewISR.pm_offset = (int)commISR; > NewISR.pm_selector = _go32_my_cs(); > _go32_dpmi_allocate_iret_wrapper(&NewISR); > _go32_dpmi_set_protected_mode_interrupt_vector(commIntr, &NewISR); > > oldIMR = inportb(0x21); > byte newIMR = oldIMR & (~(0x01 << 4)); > outportb(0x21, newIMR); > } I'm assuming that you're familiar with the runtime enviroment in which your code runs. It is possible for a DPMI host or other system code to reprogram interrupt controller so that the IRQ no longer go to the same vectors normally assumed. This is another matter you may have to investigate. > > > #define QUEUE_CAPABILITY 16 > byte writeQueue[QUEUE_CAPABILITY]; > uint16_t queueHead = 0, queueTail = 0; > uint16_t queueSize = 0; > > int asyWriteComm() > { > for(int count = 0; count < QUEUE_CAPABILITY; count ++) > { > writeQueue[queueTail] = 'a' + count; > queueTail = (queueTail + 1) % QUEUE_CAPABILITY; > queueSize ++; > } > > byte data = writeQueue[queueHead]; [...] > > void commISR() > { [...] > byte data = writeQueue[queueHead]; > queueHead = (queueHead + 1) % QUEUE_CAPABILITY; > queueSize --; > outportb(baseAddress + OFFSET_THR, data); > txIdle = false; You may have to declare these data structures you're accessing from the interrupt handler and from normal code "volatile" to inform the compiler not to make certain assumptions that may be hazardous in the context of asynchronous, real-time events. Also, regarding the loop: do { } while(queueSize != 0); It may be a good idea to look into the HLT instruction or the DPMI idle call, in order to reduce heat generation and power consumption. HLT causes the processor to halt until it receives an interrupt. One other thing: the interrupt may have to be acknowledged (e.g. a Specific EOI for the IRQ in question, or the more popular non-specific EOI). Either your handler or the wrappers installed by DJGPP/DPMI will have to acknowledge, or you may receive no further interrupts (including any unrelated interrupts with lower priority). There are some exceptions, such as the rarely used automatic EOI mode of the PIC (I think Plan9 uses it). (And of course, there's the IO-APIC.) -aw