📄 usartavr.c
字号:
/* * Store the character and increment and the ring buffer pointer. */ *rbf->rbf_head++ = ch; if (rbf->rbf_head == rbf->rbf_last) { rbf->rbf_head = rbf->rbf_start; } /* Update the ring buffer counter. */ rbf->rbf_cnt = cnt;#ifdef NUTTRACER TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_UART_RXCOMPL);#endif#ifdef UART_READMULTIBYTE } while ( inb(UCSRnA) & _BV(RXC) ); // byte in buffer? // Eventually post event to wake thread if (postEvent) NutEventPostFromIrq(&rbf->rbf_que);#endif}/*! * \brief Carefully enable USART hardware functions. * * Always enabale transmitter and receiver, even on read-only or * write-only mode. So we can support software flow control. */static void AvrUsartEnable(void){ NutEnterCritical(); outb(UCSRnB, _BV(RXCIE) | _BV(UDRIE) | _BV(RXEN) | _BV(TXEN));#ifdef UART_HDX_BIT if (hdx_control) { /* Enable transmit complete interrupt. */ sbi(UCSRnB, TXCIE); }#endif NutExitCritical();}/*! * \brief Carefully disable USART hardware functions. */static void AvrUsartDisable(void){ /* * Disable USART interrupts. */ NutEnterCritical(); cbi(UCSRnB, RXCIE); cbi(UCSRnB, TXCIE); cbi(UCSRnB, UDRIE); NutExitCritical(); /* * Allow incoming or outgoing character to finish. */ NutDelay(10); /* * Disable USART transmit and receive. */ cbi(UCSRnB, RXEN); cbi(UCSRnB, TXEN);}/*! * \brief Query the USART hardware for the selected speed. * * This function is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return The currently selected baudrate. */static u_long AvrUsartGetSpeed(void){ u_long fct; u_short sv = (u_short) inb(UBRRnL);#ifdef __AVR_ENHANCED__ sv |= ((u_short) inb(UBRRnH) << 8); /* Synchronous mode. */ if (bit_is_set(UCSRnC, UMSEL)) { fct = 2UL; } /* Double rate mode. */ else if (bit_is_set(UCSRnA, U2X)) { fct = 8UL; } /* Normal mode. */ else { fct = 16UL; }#else fct = 16UL;#endif return NutGetCpuClock() / (fct * ((u_long) sv + 1UL));}/*! * \brief Set the USART hardware bit rate. * * This function is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \param rate Number of bits per second. * * \return 0 on success, -1 otherwise. */static int AvrUsartSetSpeed(u_long rate){ u_short sv; AvrUsartDisable(); /* * Modified Robert Hildebrand's refined calculation. */#ifdef __AVR_ENHANCED__ if (bit_is_clear(UCSRnC, UMSEL)) { if (bit_is_set(UCSRnA, U2X)) { rate <<= 2; } else { rate <<= 3; } }#else rate <<= 3;#endif sv = (u_short) ((NutGetCpuClock() / rate + 1UL) / 2UL) - 1; outb(UBRRnL, (u_char) sv);#ifdef __AVR_ENHANCED__ outb(UBRRnH, (u_char) (sv >> 8));#endif AvrUsartEnable(); return 0;}/*! * \brief Query the USART hardware for the number of data bits. * * This function is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return The number of data bits set. */static u_char AvrUsartGetDataBits(void){ if (bit_is_set(UCSRnB, UCSZ2)) { return 9; }#ifdef __AVR_ENHANCED__ if (bit_is_set(UCSRnC, UCSZ1)) { if (bit_is_set(UCSRnC, UCSZ0)) { return 8; } else { return 7; } } else if (bit_is_set(UCSRnC, UCSZ0)) { return 6; } return 5;#else return 8;#endif}/*! * \brief Set the USART hardware to the number of data bits. * * This function is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return 0 on success, -1 otherwise. */static int AvrUsartSetDataBits(u_char bits){ AvrUsartDisable(); cbi(UCSRnB, UCSZ2);#ifdef __AVR_ENHANCED__ cbi(UCSRnC, UCSZ0); cbi(UCSRnC, UCSZ1); switch (bits) { case 6: sbi(UCSRnC, UCSZ0); break; case 9: sbi(UCSRnB, UCSZ2); case 8: sbi(UCSRnC, UCSZ0); case 7: sbi(UCSRnC, UCSZ1); break; }#else if(bits == 9) { sbi(UCSRnB, UCSZ2); }#endif AvrUsartEnable(); /* * Verify the result. */ if (AvrUsartGetDataBits() != bits) { return -1; } return 0;}/*! * \brief Query the USART hardware for the parity mode. * * This routine is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return Parity mode, either 0 (disabled), 1 (odd) or 2 (even). */static u_char AvrUsartGetParity(void){#ifdef __AVR_ENHANCED__ if (bit_is_set(UCSRnC, UPM1)) { if (bit_is_set(UCSRnC, UPM0)) { return 1; } else { return 2; } }#endif return 0;}/*! * \brief Set the USART hardware to the specified parity mode. * * This routine is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \param mode 0 (disabled), 1 (odd) or 2 (even) * * \return 0 on success, -1 otherwise. */static int AvrUsartSetParity(u_char mode){#ifdef __AVR_ENHANCED__ AvrUsartDisable(); switch (mode) { case 0: cbi(UCSRnC, UPM0); cbi(UCSRnC, UPM1); break; case 1: sbi(UCSRnC, UPM0); sbi(UCSRnC, UPM1); break; case 2: cbi(UCSRnC, UPM0); sbi(UCSRnC, UPM1); break; } AvrUsartEnable();#endif /* * Verify the result. */ if (AvrUsartGetParity() != mode) { return -1; } return 0;}/*! * \brief Query the USART hardware for the number of stop bits. * * This routine is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return The number of stop bits set, either 1 or 2. */static u_char AvrUsartGetStopBits(void){#ifdef __AVR_ENHANCED__ if (bit_is_set(UCSRnC, USBS)) { return 2; }#endif return 1;}/*! * \brief Set the USART hardware to the number of stop bits. * * This routine is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return 0 on success, -1 otherwise. */static int AvrUsartSetStopBits(u_char bits){#ifdef __AVR_ENHANCED__ AvrUsartDisable(); if (bits == 1) { cbi(UCSRnC, USBS); } else if (bits == 2) { sbi(UCSRnC, USBS); } AvrUsartEnable();#endif /* * Verify the result. */ if (AvrUsartGetStopBits() != bits) { return -1; } return 0;}/*! * \brief Query the USART hardware status. * * \return Status flags. */static u_long AvrUsartGetStatus(void){ u_long rc = 0; /* * Set receiver error flags. */ if ((rx_errors & _BV(FE)) != 0) { rc |= UART_FRAMINGERROR; } if ((rx_errors & _BV(DOR)) != 0) { rc |= UART_OVERRUNERROR; }#ifdef __AVR_ENHANCED__ if ((rx_errors & _BV(UPE)) != 0) { rc |= UART_PARITYERROR; }#endif /* * Determine software handshake status. The flow control status may * change during interrupt, but this doesn't really hurt us. */ if (flow_control) { if (flow_control & XOFF_SENT) { rc |= UART_RXDISABLED; } if (flow_control & XOFF_RCVD) { rc |= UART_TXDISABLED; } }#ifdef UART_RTS_BIT /* * Determine hardware handshake control status. */ if (bit_is_set(UART_RTS_PORT, UART_RTS_BIT)) { rc |= UART_RTSDISABLED; if (rts_control) { rc |= UART_RXDISABLED; } } else { rc |= UART_RTSENABLED; }#endif#ifdef UART_CTS_BIT /* * Determine hardware handshake sense status. */ if (bit_is_set(UART_CTS_PIN, UART_CTS_BIT)) { rc |= UART_CTSDISABLED; if (cts_sense) { rc |= UART_RXDISABLED; } } else { rc |= UART_CTSENABLED; }#endif /* * If transmitter and receiver haven't been detected disabled by any * of the checks above, then they are probably enabled. */ if ((rc & UART_RXDISABLED) == 0) { rc |= UART_RXENABLED; } if ((rc & UART_TXDISABLED) == 0) { rc |= UART_TXENABLED; } /* * Process multidrop setting. */ if (tx_aframe) { rc |= UART_TXADDRFRAME; } else { rc |= UART_TXNORMFRAME; }#ifdef __AVR_ENHANCED__ if (bit_is_set(UCSRnA, MPCM)) { rc |= UART_RXADDRFRAME; } else { rc |= UART_RXNORMFRAME; }#else rc |= UART_RXNORMFRAME;#endif return rc;}/*! * \brief Set the USART hardware status. * * \param flags Status flags. * * \return 0 on success, -1 otherwise. */static int AvrUsartSetStatus(u_long flags){ /* * Process software handshake control. */ if (flow_control) { /* Access to the flow control status must be atomic. */ NutEnterCritical(); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -