diff --git a/datasheets/SAM-D5x-E5x-Family-Silicon-Errata-DS80000748K.pdf b/datasheets/SAM-D5x-E5x-Family-Silicon-Errata-DS80000748K.pdf new file mode 100644 index 0000000000000000000000000000000000000000..980b9e41fdec9868de2f9621d598ceb2093ef13c Binary files /dev/null and b/datasheets/SAM-D5x-E5x-Family-Silicon-Errata-DS80000748K.pdf differ diff --git a/firmware/cl-step-controller/src/drivers/step_cl.cpp b/firmware/cl-step-controller/src/drivers/step_cl.cpp index 074442b979dc8af6f88d10ee433a0d3819213607..687eddb5327187d50c877e6f0a00b4849c85fd62 100644 --- a/firmware/cl-step-controller/src/drivers/step_cl.cpp +++ b/firmware/cl-step-controller/src/drivers/step_cl.cpp @@ -46,6 +46,105 @@ void Step_CL::init(void){ //lut = flash_lut.read(); } +// das lut / flash stuff, +// s/o to mechaduino code for this +#define PAGE_SIZE 512 // start_flash_write reports this bit value, use datasheet 25.8.3 to reference +const float __attribute__((__aligned__(PAGE_SIZE))) lut[ENCODER_COUNTS] = {}; + +static const unsigned page_size = PAGE_SIZE; // size of each page in flash mem, read out w/ NVMCTRL->PARAM.bit.PSZ +static const unsigned floats_per_page = page_size / sizeof(float); // count of floats that can be stored in each page +static float page[floats_per_page]; // a temporary page-width of floats, to buffer before writing to flash mem +static unsigned page_f; // the page[page_f - 1] == the last float we wrote +static const void * page_ptr = (const uint8_t *) lut; // ptr to the address in flash memory where we want to write +static unsigned num_pages_written; // counting + +static void start_flash_write(void){ + num_pages_written = 0; + page_f = 0; + sysError("Writing to flash 0x" + String((uintptr_t) page_ptr, HEX)); + sysError("Page size PSZ= " + String(NVMCTRL->PARAM.bit.PSZ)); // datasheet for this + // try with wqw, and auto update? + NVMCTRL->CTRLA.bit.WMODE = NVMCTRL_CTRLA_WMODE_MAN; +} + +static void flash_disable_cache(void){ + NVMCTRL->CTRLA.bit.CACHEDIS0 = 1; + NVMCTRL->CTRLA.bit.CACHEDIS1 = 1; +} + +static void flash_enable_cache(void){ + NVMCTRL->CTRLA.bit.CACHEDIS0 = 0; + NVMCTRL->CTRLA.bit.CACHEDIS1 = 0; +} + +static void flash_erase_page(const volatile void *flash_ptr){ + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr); + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_EB; + //while(!NVMCTRL->INTFLAG.bit.DONE); + while(!NVMCTRL->STATUS.bit.READY); +} + +static inline uint32_t read_unaligned_uint32(const void *data) +{ + union { + uint32_t u32; + uint8_t u8[4]; + } res; + const uint8_t *d = (const uint8_t *)data; + res.u8[0] = d[0]; + res.u8[1] = d[1]; + res.u8[2] = d[2]; + res.u8[3] = d[3]; + return res.u32; +} + +static void flash_write_page(const volatile void *flash_ptr, const void *data, uint32_t size){ + // disable cache, + // sysError("disable cache"); + // flash_disable_cache(); + // erase the page, + sysError("erase"); + flash_erase_page(flash_ptr); + // copy into page buffer (?) + // do page buffer clear + sysError("page buffer clear"); + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr); + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_PBC; + while(!NVMCTRL->STATUS.bit.READY); + // do page buffer write (?) + volatile uint32_t *dst_addr = (volatile uint32_t *)flash_ptr; + const uint8_t *src_addr = (uint8_t*)data; + uint32_t i; + for (i=0; i<(PAGE_SIZE/4) && size; i++) { + *dst_addr = read_unaligned_uint32(src_addr); + src_addr += 4; + dst_addr++; + size--; + } + // do page write (writes to page in ADDR register, from page buffer) + sysError("page write"); + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr); + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_WP; + while(!NVMCTRL->STATUS.bit.READY); + // re-enable cache + // sysError("enable cache"); + // flash_enable_cache(); +} + +static void flash_write_value(float val){ + page[page_f ++] = val; + if(page_f < floats_per_page) return; + // page is full, commit to flash + sysError("will write 0x" + String((uintptr_t) page_ptr, HEX) + " " + String(num_pages_written)); + flash_write_page(page_ptr, page, sizeof(page)); + delay(10); + // reset counters + // page_ptr += sizeof(page); + page_f = 0; + memset(page, 0, sizeof(page)); +} + +// the calib routine boolean Step_CL::calibrate(void){ // (1) first, build a table for 200 full steps w/ encoder averaged values at each step float phase_angle = 0.0F; @@ -102,6 +201,7 @@ boolean Step_CL::calibrate(void){ // (2) build the table, walk all encoder counts... // now to build the actual table... // want to start with the 0 indice, + start_flash_write(); for(uint16_t e = 0; e < ENCODER_COUNTS; e ++){ // find the interval that spans this sample boolean bi = false; @@ -179,26 +279,30 @@ boolean Step_CL::calibrate(void){ float offset = (spot - er0) / intSpan; // find real angle offset at e, modulo for the bad interval float ra = (ra0 + (ra1 - ra0) * offset); - // wrap to 360 degs, - /* - if(ra < 0.0F){ - ra += 360.0F; - } else if (ra > 360.0F){ - ra -= 360.0F; - } - */ // log those - if(bi){ - sysError("e: " + String(e) + " ra: " + String(ra, 4) + " BI"); - // + " span: " + String(intSpan) + " offset: " + String(offset)); - // sysError("i0: " + String(interval) + " " + String(calib_readings[interval]) - // + " i1: " + String(calib_readings[interval + 1]) - // + " BI"); - } else { - sysError("e: " + String(e) + " ra: " + String(ra, 4)); + if(false){ + if(bi){ + sysError("e: " + String(e) + " ra: " + String(ra, 4) + " BI"); + // + " span: " + String(intSpan) + " offset: " + String(offset)); + // sysError("i0: " + String(interval) + " " + String(calib_readings[interval]) + // + " i1: " + String(calib_readings[interval + 1]) + // + " BI"); + } else { + sysError("e: " + String(e) + " ra: " + String(ra, 4)); + } + delay(10); } - delay(10); + // ok, have the real angle (ra) at the encoder tick (e), now write it + flash_write_value(ra); // this just happens in order, we zeroe'd out global counters at the start } // end sweep thru 2^14 pts sysError("calib complete"); return true; // went OK +} + +void Step_CL::print_table(void){ + for(uint16_t e = 0; e < ENCODER_COUNTS; e ++){ + float ra = lut[e]; + sysError("e: " + String(e) + " ra: " + String(ra, 4)); + delay(5); + } } \ No newline at end of file diff --git a/firmware/cl-step-controller/src/drivers/step_cl.h b/firmware/cl-step-controller/src/drivers/step_cl.h index d9c5e629dccd87eaba5f929c3e4a8fa7b8bd5f4c..cdb40f64dd8575c33584d908c759719daca2ee83 100644 --- a/firmware/cl-step-controller/src/drivers/step_cl.h +++ b/firmware/cl-step-controller/src/drivers/step_cl.h @@ -32,6 +32,7 @@ class Step_CL { static Step_CL* getInstance(void); void init(void); boolean calibrate(void); + void print_table(void); //float __attribute__((__aligned__(256))) lut[16384]; // nor does this ! //float lut[16384]; // nor does this work //step_cl_calib_table_t lut; // not even this works ?? too big ?? diff --git a/firmware/cl-step-controller/src/main.cpp b/firmware/cl-step-controller/src/main.cpp index c516ca419f507ae72a7762d26cf481e20aba6166..272f937f4570a48aa8802b415991bb065175a680 100644 --- a/firmware/cl-step-controller/src/main.cpp +++ b/firmware/cl-step-controller/src/main.cpp @@ -151,12 +151,18 @@ void OSAP::handleAppPacket(uint8_t *pck, uint16_t pl, uint16_t ptr, uint16_t seg switch(pck[ptr]){ case AK_RUNCALIB: ptr ++; // walk stepcode - step_cl->calibrate(); reply[rl ++] = AK_RUNCALIB; + if(step_cl->calibrate()){ + reply[rl ++] = AK_OK; + } else { + reply[rl ++] = AK_ERR; + } // do step break; case AK_READCALIB: - ptr ++; // walk readcode + ptr ++; // walk readcode + reply[rl ++] = AK_READCALIB; + step_cl->print_table(); // do work break; default: diff --git a/log/cl-step-control-log.md b/log/cl-step-control-log.md index 9020970c06c69305e613b7e1a7b581d639e30840..2ba5f79b5ace7ca7d33464fe50af2790f39a63f3 100644 --- a/log/cl-step-control-log.md +++ b/log/cl-step-control-log.md @@ -10,6 +10,10 @@ With 2x A4950s on the DAC, AS5047P on the encoder, etc. - haven't tested with '+ve' signed calibrations, i.e. if motor += magnetic step does encoder += tick step. +## Evaluation + +- static holding, watch encoder wobble when torque applied (can see ticks moving around even w/o motor torque being overcome), measure again with closed loop: can we hold *better* than static pointing? + ## 2020 10 06 OK, today am just waking this thing up. Have magnet glued (curing) on the back of the motor now, and one encoder soldered up on an old module-based stepper board - code should be the same. @@ -549,7 +553,7 @@ Yeah this looks all kinds of wrong. Borked, indeed. Will check tomorrow. Errors just before the BI (nan, so our of index somewhere?) and the BI looks close but not quite there. -## 2020 10 08 +## 2020 10 09 Ok, updating the interpolation, seems messy but I think (?) maybe this shot will work - at least for -ve signed samples. @@ -763,4 +767,39 @@ boolean Step_CL::calibrate(void){ } ``` -So next up is writing that to flash so that I can use it. \ No newline at end of file +So next up is writing that to flash so that I can use it. + +Alright! Flash memory. + +Seems like I've most of it written - just copying from mechaduino, but after I write these out, I freeze up the micro. + +Yeah, welp, I think I might have to get into the datasheet and do this au manuel. I've learned that when I declare a const variable, it goes into the flash memory. I think my 'alignment' of that will set it up in pages, so I 'align' it to the page size, which I can read to be 512 bytes... I'll take a minute, see how this goes. Bummer it's Friday, I was pumped to get this up and running this week. + +## 2020 10 13 + +Setting up the NVM Controller today to try to write pages into flash. Not sure why this was crashing before, probably something simple. + +I don't think there's a clock / init I have to do to wake up the flash controller, seems like that would be kind of crazy. Yeah, 25.6.1.1 clarifies this. + +I'm also not sure where the bootloader is in here, and seems likely that I might write it over. + +'addressable on the AHB bus' + +I think I almost get this, need to figure this note about disabling cache.. some erratta... am at 25.6.6 + +Trying with just doing automatic quad word writing, which I think auto increments the page-write pointer, not sure about what happens for the page buffer though. I should check via the mechaduino code and flash storage code... + +Ok this is hella opaque, 25.6.6.2 ... `procedure for manual page writes` + - the block to be written must be erased before the write command is given + - write to the page buffer by addressing the nvm main address space directly (crazy) + - cmd = wp to write the full contents of the page buffer into the nvm at the page pointed to by addr + +I fully don't understand this, but it seems like it should be straightforward. Likely next step is to burn it all down and try again from scratch. I should see if I can write *anything* and move away from this calib-then-write situation, which is probably complicating things. + +#### Aboot Flash + +Have to erase before write, to set back to 1's: flash memory writes by pulling zeroes low, and has to operate in blocks. + +I can also check the UF2 bootloader, which uses flash: + +https://github.com/microsoft/uf2-samdx1/blob/master/src/flash_samd51.c \ No newline at end of file