From 69aaea44a09b1a1a7691a84d537208a0e1f1cd65 Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Fri, 6 Sep 2019 15:42:02 +0200 Subject: [PATCH] machine/atsamd21: Add support for bootloader reset/programming and correct error in receiving endpoint 0 data for CDC Set Line Coding changes, implementing system reset on switch to 1200 baud connection speed with DTR false. Signed-off-by: Ron Evans --- src/device/arm/arm.go | 4 ++ src/machine/machine_atsamd21.go | 82 +++++++++++++++++---------------- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/device/arm/arm.go b/src/device/arm/arm.go index 1c3d4a64..05749ea7 100644 --- a/src/device/arm/arm.go +++ b/src/device/arm/arm.go @@ -164,4 +164,8 @@ func SystemReset() { // SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | // SCB_AIRCR_SYSRESETREQ_Msk); SCB.AIRCR.Set((0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk) + + for { + Asm("wfi") + } } diff --git a/src/machine/machine_atsamd21.go b/src/machine/machine_atsamd21.go index ab623331..0e76b9c5 100644 --- a/src/machine/machine_atsamd21.go +++ b/src/machine/machine_atsamd21.go @@ -1401,15 +1401,15 @@ func handleUSB() { for i = 1; i < uint32(len(endPoints)); i++ { // Check if endpoint has a pending interrupt epFlags := getEPINTFLAG(i) - if epFlags > 0 { + if (epFlags&sam.USB_DEVICE_EPINTFLAG_TRCPT0) > 0 || + (epFlags&sam.USB_DEVICE_EPINTFLAG_TRCPT1) > 0 { switch i { case usb_CDC_ENDPOINT_OUT: - if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT0) > 0 { - handleEndpoint(i) - } - setEPINTFLAG(i, epFlags) - case usb_CDC_ENDPOINT_ACM: + handleEndpoint(i) setEPINTFLAG(i, epFlags) + case usb_CDC_ENDPOINT_IN, usb_CDC_ENDPOINT_ACM: + setEPSTATUSCLR(i, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY) + setEPINTFLAG(i, sam.USB_DEVICE_EPINTFLAG_TRCPT1) } } } @@ -1631,17 +1631,19 @@ func cdcSetup(setup usbSetup) bool { if setup.bRequest == usb_CDC_SET_LINE_CODING || setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE { // auto-reset into the bootloader - if usbLineInfo.dwDTERate == 1200 && (usbLineInfo.lineState&0x01) == 0 { - // TODO: system reset + if usbLineInfo.dwDTERate == 1200 && usbLineInfo.lineState&usb_CDC_LINESTATE_DTR == 0 { + ResetProcessor() } else { // TODO: cancel any reset } + sendZlp(0) } if setup.bRequest == usb_CDC_SEND_BREAK { // TODO: something with this value? // breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; // return false; + sendZlp(0) } return true } @@ -1662,53 +1664,41 @@ func sendUSBPacket(ep uint32, data []byte) { } func receiveUSBControlPacket() []byte { - // set ready to receive data + // address + usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0])))) + + // set byte count to zero + usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) + + // set ready for next data setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY) - // read the data - bytesread := armRecvCtrlOUT(0) - - // return the data - data := make([]byte, 0, bytesread) - copy(data, udd_ep_out_cache_buffer[0][:bytesread]) - return data -} - -func armRecvCtrlOUT(ep uint32) uint32 { - // Set output address to receive data - usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) - - // set multi-packet size which is total expected number of bytes to receive. - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits((8 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos) | - uint32(epPacketSize(64)<> - usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask + // get data + bytesread := uint32((usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.Get() >> + usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) + + data := make([]byte, bytesread) + copy(data, udd_ep_out_cache_buffer[0][:]) + + return data } // sendDescriptor creates and sends the various USB descriptor types that @@ -2083,3 +2073,15 @@ func setEPINTENSET(ep uint32, val uint8) { return } } + +// ResetProcessor should perform a system reset in preperation +// to switch to the bootloader to flash new firmware. +func ResetProcessor() { + arm.DisableInterrupts() + + // Perform magic reset into bootloader, as mentioned in + // https://github.com/arduino/ArduinoCore-samd/issues/197 + *(*uint32)(unsafe.Pointer(uintptr(0x20007FFC))) = 0x07738135 + + arm.SystemReset() +}