Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

low-level DMA serial #25

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion inc/SAMDDAC.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class SAMDDAC : public CodalComponent, public DmaComponent, public DataSink
/**
* Interrupt callback when playback of DMA buffer has completed
*/
virtual void dmaTransferComplete(DmaCode c);
virtual void dmaTransferComplete(DmaInstance *dma, DmaCode c) override;
};

#endif
4 changes: 3 additions & 1 deletion inc/SAMDDMAC.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ enum DmaBeatSize
BeatWord
};

class DmaInstance;

class DmaComponent
{
public:
virtual void dmaTransferComplete(DmaCode c);
virtual void dmaTransferComplete(DmaInstance *dma, DmaCode c) = 0;
};

static inline int sercom_trigger_src(int sercomIdx, bool tx)
Expand Down
2 changes: 1 addition & 1 deletion inc/SAMDPDM.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class SAMD21PDM : public CodalComponent, public DmaComponent, public DataSource
/**
* Interrupt callback when playback of DMA buffer has completed
*/
virtual void dmaTransferComplete(DmaCode c);
virtual void dmaTransferComplete(DmaInstance *dma, DmaCode c) override;

/**
* Enable this component
Expand Down
2 changes: 1 addition & 1 deletion inc/ZSPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class ZSPI : public codal::SPI, public codal::DmaComponent
void init();

public:
virtual void dmaTransferComplete(DmaCode);
virtual void dmaTransferComplete(DmaInstance *, DmaCode) override;

/**
* Initialize SPI instance with given pins.
Expand Down
23 changes: 10 additions & 13 deletions inc/ZSingleWireSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ namespace codal
struct ::_usart_async_device USART_INSTANCE;
DmaInstance* usart_tx_dma;
DmaInstance* usart_rx_dma;
uint32_t pinmux;
Pin *rx;
uint8_t pinmux;
uint8_t instance_number;
uint8_t pad;
uint8_t rx_pinmux;
uint8_t rx_pad;

protected:
virtual void configureRxInterrupt(int enable);
Expand All @@ -38,20 +41,14 @@ namespace codal
public:

/**
* This constructor is really ugly, but there isn't currently a nice representation of a model of the device
* i.e. a resource manager?
* Create a new instance of single wire serial.
*
* @param p the pin instance to use for output
* @param p the pin instance to use for output (and input if no rx given)
*
* @param instance the sercom instance that is compatible with p.
*
* @param instance_number the index into the sercom array (SERCOM0 == index 0)
*
* @param pinmux the pinmux settings for p, i.e. PA08 has pinmux settings PINMUX_PB08D_SERCOM4_PAD0 for sercom four
*
* @param pad the pad that the pin is routed through i.e. PA08 uses PAD0 of SERCOM4 (see data sheet).
* @param rx the pin instance to use for input
*
**/
ZSingleWireSerial(Pin& p);
ZSingleWireSerial(Pin& p, Pin *rx = NULL);

virtual int putc(char c);
virtual int getc();
Expand All @@ -73,7 +70,7 @@ namespace codal

virtual int sendBreak();

void dmaTransferComplete(DmaCode c) override;
void dmaTransferComplete(DmaInstance *dma, DmaCode c) override;
};
}

Expand Down
5 changes: 0 additions & 5 deletions src/DmaFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,6 @@ extern "C" void DMAC_4_Handler(void)
}
#endif

/**
* Base implementation of a DMA callback
*/
void DmaComponent::dmaTransferComplete(DmaCode) {}

DmaControllerInstance::DmaControllerInstance()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this just leads to trouble and everyone implements it anyways

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it should have been left at an abstract interface.

{
uint32_t ptr = (uint32_t)descriptorsBuffer;
Expand Down
11 changes: 9 additions & 2 deletions src/DmaInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void DmaInstance::trigger(DmaCode c)
disable();

if (this->cb)
this->cb->dmaTransferComplete(c);
this->cb->dmaTransferComplete(this, c);
}


Expand Down Expand Up @@ -107,7 +107,7 @@ void DmaInstance::transfer(const void *src_addr, void *dst_addr, uint32_t len)
descriptor.SRCADDR.reg = (uint32_t)src_addr + len;
if (dst_addr)
descriptor.DSTADDR.reg = (uint32_t)dst_addr + len;

enable();

target_enable_irq();
Expand All @@ -124,6 +124,13 @@ int DmaInstance::getBytesTransferred()
#else
DMAC_ACTIVE_Type active;
active.reg = DMAC->ACTIVE.reg;
// datasheet (22.8.13) says BTCNT is only valid if ABUSY
// However, the chip doesn't seem to flush BTCNT to write back descriptor when it
// clears ABUSY, so if there are no other active channels, the write back will contain
// an old value indefinetely, while ABUSY is cleared.
// However, it is also possible that BTCNT contains the count from the previous
// transfer, before ABUSY is ever set.
// So this number may be flat wrong.
if (active.bit.ID == channel_number)
btcnt = active.bit.BTCNT;
else
Expand Down
2 changes: 1 addition & 1 deletion src/SAMDDAC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ extern void debug_flip();
/**
* Base implementation of a DMA callback
*/
void SAMDDAC::dmaTransferComplete(DmaCode c)
void SAMDDAC::dmaTransferComplete(DmaInstance *, DmaCode)
{
if (dataReady == 0)
{
Expand Down
2 changes: 1 addition & 1 deletion src/SAMDPDM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ void SAMD21PDM::decimate(Event)
pdmDataBuffer = NULL;
}

void SAMD21PDM::dmaTransferComplete(DmaCode c)
void SAMD21PDM::dmaTransferComplete(DmaInstance *, DmaCode c)
{
if (c == DMA_ERROR)
while(1) DMESG("POO!!!");
Expand Down
2 changes: 1 addition & 1 deletion src/ZSPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ namespace codal

#define ZERO(f) memset(&f, 0, sizeof(f))

void ZSPI::dmaTransferComplete(DmaCode)
void ZSPI::dmaTransferComplete(DmaInstance *, DmaCode)
{
LOG("SPI complete D=%p", doneHandler);

Expand Down
59 changes: 47 additions & 12 deletions src/ZSingleWireSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static void error_callback(struct _usart_async_device *device)
{
// flag any error to the dma handler.
if (sws_instance)
sws_instance->dmaTransferComplete(DMA_ERROR);
sws_instance->dmaTransferComplete(NULL, DMA_ERROR);
}

static void tx_callback(struct _usart_async_device *)
Expand All @@ -40,34 +40,34 @@ static void rx_callback(struct _usart_async_device *, uint8_t)
{
}

void ZSingleWireSerial::dmaTransferComplete(DmaCode errCode)
void ZSingleWireSerial::dmaTransferComplete(DmaInstance *dma, DmaCode errCode)
{
uint16_t mode = 0;

if (errCode == DMA_COMPLETE)
{
if (status & TX_CONFIGURED)
if (dma == usart_tx_dma && (status & TX_CONFIGURED))
mode = SWS_EVT_DATA_SENT;

if (status & RX_CONFIGURED)
if (dma == usart_rx_dma && (status & RX_CONFIGURED))
mode = SWS_EVT_DATA_RECEIVED;
}
else
mode = SWS_EVT_ERROR;

Event evt(this->id, mode, CREATE_ONLY);

// if we have a cb member function, we invoke
// otherwise fire the event for any listeners.
if (this->cb)
this->cb(mode);
else
Event(this->id, mode);
}

void ZSingleWireSerial::configureRxInterrupt(int enable)
{
}

ZSingleWireSerial::ZSingleWireSerial(Pin& p) : DMASingleWireSerial(p)
ZSingleWireSerial::ZSingleWireSerial(Pin& p, Pin *rx) : DMASingleWireSerial(p), rx(rx)
{
const mcu_pin_obj_t* single_wire_pin = samd_peripherals_get_pin(p.name);

Expand Down Expand Up @@ -100,6 +100,23 @@ ZSingleWireSerial::ZSingleWireSerial(Pin& p) : DMASingleWireSerial(p)
else
target_panic(DEVICE_HARDWARE_CONFIGURATION_ERROR);

if (rx) {
const mcu_pin_obj_t* rx_pin = samd_peripherals_get_pin(rx->name);
if (rx_pin->sercom[0].index == this->instance_number)
{
this->rx_pad = rx_pin->sercom[0].pad;
this->rx_pinmux = MUX_C; // c
}

else if (rx_pin->sercom[1].index == this->instance_number)
{
this->rx_pad = rx_pin->sercom[1].pad;
this->rx_pinmux = MUX_D; // d
}
else
target_panic(DEVICE_HARDWARE_CONFIGURATION_ERROR);
}

Sercom* instance = sercom_insts[this->instance_number];
DMESG("SWS pad %d, idx %d, fn: %d", 0, this->instance_number, this->pinmux);

Expand Down Expand Up @@ -129,10 +146,10 @@ ZSingleWireSerial::ZSingleWireSerial(Pin& p) : DMASingleWireSerial(p)
usart_tx_dma->configure(sercom_trigger_src(this->instance_number, true), BeatByte, NULL, (volatile void*)&CURRENT_USART->USART.DATA.reg);
usart_rx_dma->configure(sercom_trigger_src(this->instance_number, false), BeatByte, (volatile void*)&CURRENT_USART->USART.DATA.reg, NULL);

setBaud(115200);

status = 0;

setBaud(115200);

#ifdef SAMD21
NVIC_SetPriority(SERCOM0_IRQn,1);
NVIC_SetPriority(SERCOM1_IRQn,1);
Expand All @@ -143,16 +160,30 @@ ZSingleWireSerial::ZSingleWireSerial(Pin& p) : DMASingleWireSerial(p)
#else
// SAMD51 has many more IRQs for SERCOMs
#endif

}

int ZSingleWireSerial::setBaud(uint32_t baud)
{
if (rx)
{
configureRx(0);
configureTx(0);
}

#ifdef SERCOM_100MHZ_CLOCK
CURRENT_USART->USART.BAUD.reg = 65536 - ((uint64_t)65536 * 16 * baud) / 100000000;
#else
CURRENT_USART->USART.BAUD.reg = 65536 - ((uint64_t)65536 * 16 * baud) / CONF_GCLK_SERCOM0_CORE_FREQUENCY;;
#endif
this->baud = baud;

if (rx)
{
configureRx(1);
configureTx(1);
}

return DEVICE_OK;
}

Expand Down Expand Up @@ -227,7 +258,10 @@ int ZSingleWireSerial::configureRx(int enable)
{
if (enable && !(status & RX_CONFIGURED))
{
gpio_set_pin_function(p.name, this->pinmux);
if (rx)
gpio_set_pin_function(rx->name, this->rx_pinmux);
else
gpio_set_pin_function(p.name, this->pinmux);

CURRENT_USART->USART.CTRLA.bit.ENABLE = 0;
while(CURRENT_USART->USART.SYNCBUSY.bit.ENABLE);
Expand All @@ -236,7 +270,7 @@ int ZSingleWireSerial::configureRx(int enable)
CURRENT_USART->USART.CTRLA.bit.DORD = 1;
#endif
CURRENT_USART->USART.CTRLA.bit.SAMPR = 0;
CURRENT_USART->USART.CTRLA.bit.RXPO = this->pad;
CURRENT_USART->USART.CTRLA.bit.RXPO = rx ? this->rx_pad : this->pad;
CURRENT_USART->USART.CTRLB.bit.CHSIZE = 0; // 8 BIT

CURRENT_USART->USART.CTRLA.bit.ENABLE = 1;
Expand Down Expand Up @@ -345,7 +379,8 @@ int ZSingleWireSerial::abortDMA()
if (!(status & (RX_CONFIGURED | TX_CONFIGURED)))
return DEVICE_INVALID_PARAMETER;

usart_tx_dma->abort();
if (!rx)
usart_tx_dma->abort();
usart_rx_dma->abort();

// abort dma transfer
Expand Down