size_t HardwareSerial::write(uint8_t c) { _written = true; // If the buffer and the data register is empty, just write the byte // to the data register and be done. This shortcut helps // significantly improve the effective datarate at high (> // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) { #ifdef __HWSERIAL9BIT if(bit_is_set(*_ucsrb, UCSZ02)) { // Uart is configured for 9 bit mode cbi(*_ucsrb, TXB80); // 9th bit clear } #endif *_udr = c; sbi(*_ucsra, TXC0); return 1; } tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; // If the output buffer is full, there's nothing for it other than to // wait for the interrupt handler to empty it a bit while (i == _tx_buffer_tail) { if (bit_is_clear(SREG, SREG_I)) { // Interrupts are disabled, so we'll have to poll the data // register empty flag ourselves. If it is set, pretend an // interrupt has happened and call the handler to free up // space for us. if(bit_is_set(*_ucsra, UDRE0)) _tx_udr_empty_irq(); } else { // nop, the interrupt handler will free up space for us } } _tx_buffer[_tx_buffer_head] = c; #ifdef __HWSERIAL9BIT __HWSERIAL9BIT_bitClear(_tx_9bit, _tx_buffer_head); #endif // __HWSERIAL9BIT _tx_buffer_head = i; sbi(*_ucsrb, UDRIE0); return 1; }
void MarlinSerial::flushTX(void) { // TX // If we have never written a byte, no need to flush. This special // case is needed since there is no way to force the TXC (transmit // complete) bit to 1 during initialization if (!_written) return; while (TEST(M_UCSRxB, M_UDRIEx) || !TEST(M_UCSRxA, M_TXCx)) { if (!TEST(SREG, SREG_I) && TEST(M_UCSRxB, M_UDRIEx)) // Interrupts are globally disabled, but the DR empty // interrupt should be enabled, so poll the DR empty flag to // prevent deadlock if (TEST(M_UCSRxA, M_UDREx)) _tx_udr_empty_irq(); } // If we get here, nothing is queued anymore (DRIE is disabled) and // the hardware finished tranmission (TXC is set). }
void HardwareSerial::flush() { // If we have never written a byte, no need to flush. This special // case is needed since there is no way to force the TXC (transmit // complete) bit to 1 during initialization if (!_written) return; while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) { if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0)) // Interrupts are globally disabled, but the DR empty // interrupt should be enabled, so poll the DR empty flag to // prevent deadlock if (bit_is_set(*_ucsra, UDRE0)) _tx_udr_empty_irq(); } // If we get here, nothing is queued anymore (DRIE is disabled) and // the hardware finished tranmission (TXC is set). }
void MarlinSerial::write(const uint8_t c) { _written = true; CRITICAL_SECTION_START; bool emty = (tx_buffer.head == tx_buffer.tail); CRITICAL_SECTION_END; // If the buffer and the data register is empty, just write the byte // to the data register and be done. This shortcut helps // significantly improve the effective datarate at high (> // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. if (emty && TEST(M_UCSRxA, M_UDREx)) { CRITICAL_SECTION_START; M_UDRx = c; SBI(M_UCSRxA, M_TXCx); CRITICAL_SECTION_END; return; } const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1); // If the output buffer is full, there's nothing for it other than to // wait for the interrupt handler to empty it a bit while (i == tx_buffer.tail) { if (!TEST(SREG, SREG_I)) { // Interrupts are disabled, so we'll have to poll the data // register empty flag ourselves. If it is set, pretend an // interrupt has happened and call the handler to free up // space for us. if (TEST(M_UCSRxA, M_UDREx)) _tx_udr_empty_irq(); } else { // nop, the interrupt handler will free up space for us } } tx_buffer.buffer[tx_buffer.head] = c; { CRITICAL_SECTION_START; tx_buffer.head = i; SBI(M_UCSRxB, M_UDRIEx); CRITICAL_SECTION_END; } return; }
void MarlinSerial<Cfg>::flushTX(void) { if (Cfg::TX_SIZE == 0) { // No bytes written, no need to flush. This special case is needed since there's // no way to force the TXC (transmit complete) bit to 1 during initialization. if (!_written) return; // Wait until everything was transmitted while (!B_TXC) sw_barrier(); // At this point nothing is queued anymore (DRIE is disabled) and // the hardware finished transmission (TXC is set). } else { // No bytes written, no need to flush. This special case is needed since there's // no way to force the TXC (transmit complete) bit to 1 during initialization. if (!_written) return; // If global interrupts are disabled (as the result of being called from an ISR)... if (!ISRS_ENABLED()) { // Wait until everything was transmitted - We must do polling, as interrupts are disabled while (tx_buffer.head != tx_buffer.tail || !B_TXC) { // If there is more space, send an extra character if (B_UDRE) _tx_udr_empty_irq(); sw_barrier(); } } else { // Wait until everything was transmitted while (tx_buffer.head != tx_buffer.tail || !B_TXC) sw_barrier(); } // At this point nothing is queued anymore (DRIE is disabled) and // the hardware finished transmission (TXC is set). } }
int8_t serialWrite(uint8_t c) { // If the buffer and the data register is empty, just write the byte // to the data register and be done. This shortcut helps // significantly improve the effective datarate at high (> // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(_ucsra, UDRE0)) { _udr = c; sbi(_ucsra, TXC0); return 1; } tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; // If the output buffer is full, there's nothing for it other than to // wait for the interrupt handler to empty it a bit while (i == _tx_buffer_tail) { if (bit_is_clear(SREG, SREG_I)) { // Interrupts are disabled, so we'll have to poll the data // register empty flag ourselves. If it is set, pretend an // interrupt has happened and call the handler to free up // space for us. if(bit_is_set(_ucsra, UDRE0)) _tx_udr_empty_irq(); } else { // nop, the interrupt handler will free up space for us } } _tx_buffer[_tx_buffer_head] = c; _tx_buffer_head = i; sbi(_ucsrb, UDRIE0); _written = 1; return 1; }