@@ -42,11 +42,6 @@ extern struct rst_info resetInfo;
42
42
#ifndef PUYA_SUPPORT
43
43
#define PUYA_SUPPORT 1
44
44
#endif
45
- #ifndef PUYA_BUFFER_SIZE
46
- // Good alternative for buffer size is: SPI_FLASH_SEC_SIZE (= 4k)
47
- // Always use a multiple of flash page size (256 bytes)
48
- #define PUYA_BUFFER_SIZE 256
49
- #endif
50
45
51
46
/* *
52
47
* User-defined Literals
@@ -668,11 +663,14 @@ static SpiFlashOpResult spi_flash_write_puya(uint32_t offset, uint32_t *data, si
668
663
if (data == nullptr ) {
669
664
return SPI_FLASH_RESULT_ERR;
670
665
}
666
+ if (size % 4 != 0 ) {
667
+ return SPI_FLASH_RESULT_ERR;
668
+ }
671
669
// PUYA flash chips need to read existing data, update in memory and write modified data again.
672
670
static uint32_t *flash_write_puya_buf = nullptr ;
673
671
674
672
if (flash_write_puya_buf == nullptr ) {
675
- flash_write_puya_buf = (uint32_t *) malloc (PUYA_BUFFER_SIZE );
673
+ flash_write_puya_buf = (uint32_t *) malloc (FLASH_PAGE_SIZE );
676
674
// No need to ever free this, since the flash chip will never change at runtime.
677
675
if (flash_write_puya_buf == nullptr ) {
678
676
// Memory could not be allocated.
@@ -686,45 +684,261 @@ static SpiFlashOpResult spi_flash_write_puya(uint32_t offset, uint32_t *data, si
686
684
uint32_t pos = offset;
687
685
while (bytesLeft > 0 && rc == SPI_FLASH_RESULT_OK) {
688
686
size_t bytesNow = bytesLeft;
689
- if (bytesNow > PUYA_BUFFER_SIZE ) {
690
- bytesNow = PUYA_BUFFER_SIZE ;
691
- bytesLeft -= PUYA_BUFFER_SIZE ;
687
+ if (bytesNow > FLASH_PAGE_SIZE ) {
688
+ bytesNow = FLASH_PAGE_SIZE ;
689
+ bytesLeft -= FLASH_PAGE_SIZE ;
692
690
} else {
693
691
bytesLeft = 0 ;
694
692
}
695
- size_t bytesAligned = (bytesNow + 3 ) & ~3 ;
696
- rc = spi_flash_read (pos, flash_write_puya_buf, bytesAligned);
693
+ rc = spi_flash_read (pos, flash_write_puya_buf, bytesNow);
697
694
if (rc != SPI_FLASH_RESULT_OK) {
698
695
return rc;
699
696
}
700
- for (size_t i = 0 ; i < bytesAligned / 4 ; ++i) {
697
+ for (size_t i = 0 ; i < bytesNow / 4 ; ++i) {
701
698
flash_write_puya_buf[i] &= *ptr;
702
699
++ptr;
703
700
}
704
- rc = spi_flash_write (pos, flash_write_puya_buf, bytesAligned );
701
+ rc = spi_flash_write (pos, flash_write_puya_buf, bytesNow );
705
702
pos += bytesNow;
706
703
}
707
704
return rc;
708
705
}
709
706
#endif
710
707
711
- bool EspClass::flashWrite (uint32_t offset, uint32_t *data, size_t size) {
708
+ bool EspClass::flashReplaceBlock (uint32_t address, const uint8_t *value, uint32_t byteCount) {
709
+ uint32_t alignedAddress = (address & ~3 );
710
+ uint32_t alignmentOffset = address - alignedAddress;
711
+
712
+ if (alignedAddress != ((address + byteCount - 1 ) & ~3 )) {
713
+ // Only one 4 byte block is supported
714
+ return false ;
715
+ }
716
+ #if PUYA_SUPPORT
717
+ if (getFlashChipVendorId () == SPI_FLASH_VENDOR_PUYA) {
718
+ uint8_t tempData[4 ] __attribute__ ((aligned (4 )));
719
+ if (spi_flash_read (alignedAddress, (uint32_t *)tempData, 4 ) != SPI_FLASH_RESULT_OK) {
720
+ return false ;
721
+ }
722
+ for (size_t i = 0 ; i < byteCount; i++) {
723
+ tempData[i + alignmentOffset] &= value[i];
724
+ }
725
+ if (spi_flash_write (alignedAddress, (uint32_t *)tempData, 4 ) != SPI_FLASH_RESULT_OK) {
726
+ return false ;
727
+ }
728
+ }
729
+ else
730
+ #endif // PUYA_SUPPORT
731
+ {
732
+ uint32_t tempData;
733
+ if (spi_flash_read (alignedAddress, &tempData, 4 ) != SPI_FLASH_RESULT_OK) {
734
+ return false ;
735
+ }
736
+ memcpy ((uint8_t *)&tempData + alignmentOffset, value, byteCount);
737
+ if (spi_flash_write (alignedAddress, &tempData, 4 ) != SPI_FLASH_RESULT_OK) {
738
+ return false ;
739
+ }
740
+ }
741
+ return true ;
742
+ }
743
+
744
+ size_t EspClass::flashWriteUnalignedMemory (uint32_t address, const uint8_t *data, size_t size) {
745
+ size_t sizeLeft = (size & ~3 );
746
+ size_t currentOffset = 0 ;
747
+ // Memory is unaligned, so we need to copy it to an aligned buffer
748
+ uint32_t alignedData[FLASH_PAGE_SIZE / sizeof (uint32_t )] __attribute__ ((aligned (4 )));
749
+ // Handle page boundary
750
+ bool pageBreak = ((address % 4 ) != 0 ) && ((address / FLASH_PAGE_SIZE) != ((address + sizeLeft - 1 ) / FLASH_PAGE_SIZE));
751
+
752
+ if (pageBreak) {
753
+ size_t byteCount = 4 - (address % 4 );
754
+
755
+ if (!flashReplaceBlock (address, data, byteCount)) {
756
+ return 0 ;
757
+ }
758
+ // We will now have aligned address, so we can cross page boundaries
759
+ currentOffset += byteCount;
760
+ // Realign size to 4
761
+ sizeLeft = (size - byteCount) & ~3 ;
762
+ }
763
+
764
+ while (sizeLeft) {
765
+ size_t willCopy = std::min (sizeLeft, sizeof (alignedData));
766
+ memcpy (alignedData, data + currentOffset, willCopy);
767
+ // We now have address, data and size aligned to 4 bytes, so we can use aligned write
768
+ if (!flashWrite (address + currentOffset, alignedData, willCopy))
769
+ {
770
+ return 0 ;
771
+ }
772
+ sizeLeft -= willCopy;
773
+ currentOffset += willCopy;
774
+ }
775
+
776
+ return currentOffset;
777
+ }
778
+
779
+ bool EspClass::flashWritePageBreak (uint32_t address, const uint8_t *data, size_t size) {
780
+ if (size > 4 ) {
781
+ return false ;
782
+ }
783
+ size_t pageLeft = FLASH_PAGE_SIZE - (address % FLASH_PAGE_SIZE);
784
+ size_t offset = 0 ;
785
+ size_t sizeLeft = size;
786
+ if (pageLeft > 3 ) {
787
+ return false ;
788
+ }
789
+
790
+ if (!flashReplaceBlock (address, data, pageLeft)) {
791
+ return false ;
792
+ }
793
+ offset += pageLeft;
794
+ sizeLeft -= pageLeft;
795
+ // We replaced last 4-byte block of the page, now we write the remainder in next page
796
+ if (!flashReplaceBlock (address + offset, data + offset, sizeLeft)) {
797
+ return false ;
798
+ }
799
+ return true ;
800
+ }
801
+
802
+ bool EspClass::flashWrite (uint32_t address, const uint32_t *data, size_t size) {
712
803
SpiFlashOpResult rc = SPI_FLASH_RESULT_OK;
804
+ bool pageBreak = ((address % 4 ) != 0 && (address / FLASH_PAGE_SIZE) != ((address + size - 1 ) / FLASH_PAGE_SIZE));
805
+
806
+ if ((uintptr_t )data % 4 != 0 || size % 4 != 0 || pageBreak) {
807
+ return false ;
808
+ }
713
809
#if PUYA_SUPPORT
714
810
if (getFlashChipVendorId () == SPI_FLASH_VENDOR_PUYA) {
715
- rc = spi_flash_write_puya (offset, data, size);
811
+ rc = spi_flash_write_puya (address, const_cast < uint32_t *>( data) , size);
716
812
}
717
813
else
718
- #endif
814
+ #endif // PUYA_SUPPORT
719
815
{
720
- rc = spi_flash_write (offset, data, size);
816
+ rc = spi_flash_write (address, const_cast < uint32_t *>( data) , size);
721
817
}
722
818
return rc == SPI_FLASH_RESULT_OK;
723
819
}
724
820
725
- bool EspClass::flashRead (uint32_t offset, uint32_t *data, size_t size) {
726
- auto rc = spi_flash_read (offset, (uint32_t *) data, size);
727
- return rc == SPI_FLASH_RESULT_OK;
821
+ bool EspClass::flashWrite (uint32_t address, const uint8_t *data, size_t size) {
822
+ if (size == 0 ) {
823
+ return true ;
824
+ }
825
+
826
+ size_t sizeLeft = size & ~3 ;
827
+ size_t currentOffset = 0 ;
828
+
829
+ if (sizeLeft) {
830
+ if ((uintptr_t )data % 4 != 0 ) {
831
+ size_t written = flashWriteUnalignedMemory (address, data, size);
832
+ if (!written) {
833
+ return false ;
834
+ }
835
+ currentOffset += written;
836
+ sizeLeft -= written;
837
+ } else {
838
+ bool pageBreak = ((address % 4 ) != 0 && (address / FLASH_PAGE_SIZE) != ((address + sizeLeft - 1 ) / FLASH_PAGE_SIZE));
839
+
840
+ if (pageBreak) {
841
+ while (sizeLeft) {
842
+ // We cannot cross page boundary, but the write must be 4 byte aligned,
843
+ // so this is the maximum amount we can write
844
+ size_t pageBoundary = (FLASH_PAGE_SIZE - ((address + currentOffset) % FLASH_PAGE_SIZE)) & ~3 ;
845
+
846
+ if (sizeLeft > pageBoundary) {
847
+ // Aligned write up to page boundary
848
+ if (!flashWrite (address + currentOffset, (uint32_t *)(data + currentOffset), pageBoundary)) {
849
+ return false ;
850
+ }
851
+ currentOffset += pageBoundary;
852
+ sizeLeft -= pageBoundary;
853
+ // Cross the page boundary
854
+ if (!flashWritePageBreak (address + currentOffset, data + currentOffset, 4 )) {
855
+ return false ;
856
+ }
857
+ currentOffset += 4 ;
858
+ sizeLeft -= 4 ;
859
+ } else {
860
+ // We do not cross page boundary
861
+ if (!flashWrite (address + currentOffset, (uint32_t *)(data + currentOffset), sizeLeft)) {
862
+ return false ;
863
+ }
864
+ currentOffset += sizeLeft;
865
+ sizeLeft = 0 ;
866
+ }
867
+ }
868
+ } else {
869
+ // Pointer is properly aligned and write does not cross page boundary,
870
+ // so use aligned write
871
+ if (!flashWrite (address, (uint32_t *)data, sizeLeft)) {
872
+ return false ;
873
+ }
874
+ currentOffset = sizeLeft;
875
+ sizeLeft = 0 ;
876
+ }
877
+ }
878
+ }
879
+ sizeLeft = size - currentOffset;
880
+ if (sizeLeft > 0 ) {
881
+ // Size was not aligned, so we have some bytes left to write, we also need to recheck for
882
+ // page boundary crossing
883
+ bool pageBreak = ((address % 4 ) != 0 && (address / FLASH_PAGE_SIZE) != ((address + sizeLeft - 1 ) / FLASH_PAGE_SIZE));
884
+
885
+ if (pageBreak) {
886
+ // Cross the page boundary
887
+ if (!flashWritePageBreak (address + currentOffset, data + currentOffset, sizeLeft)) {
888
+ return false ;
889
+ }
890
+ } else {
891
+ // Just write partial block
892
+ flashReplaceBlock (address + currentOffset, data + currentOffset, sizeLeft);
893
+ }
894
+ }
895
+
896
+ return true ;
897
+ }
898
+
899
+ bool EspClass::flashRead (uint32_t address, uint8_t *data, size_t size) {
900
+ size_t sizeAligned = size & ~3 ;
901
+ size_t currentOffset = 0 ;
902
+
903
+ if ((uintptr_t )data % 4 != 0 ) {
904
+ uint32_t alignedData[FLASH_PAGE_SIZE / sizeof (uint32_t )] __attribute__ ((aligned (4 )));
905
+ size_t sizeLeft = sizeAligned;
906
+
907
+ while (sizeLeft) {
908
+ size_t willCopy = std::min (sizeLeft, sizeof (alignedData));
909
+ // We read to our aligned buffer and then copy to data
910
+ if (!flashRead (address + currentOffset, alignedData, willCopy))
911
+ {
912
+ return false ;
913
+ }
914
+ memcpy (data + currentOffset, alignedData, willCopy);
915
+ sizeLeft -= willCopy;
916
+ currentOffset += willCopy;
917
+ }
918
+ } else {
919
+ // Pointer is properly aligned, so use aligned read
920
+ if (!flashRead (address, (uint32_t *)data, sizeAligned)) {
921
+ return false ;
922
+ }
923
+ currentOffset = sizeAligned;
924
+ }
925
+
926
+ if (currentOffset < size) {
927
+ uint32_t tempData;
928
+ if (spi_flash_read (address + currentOffset, &tempData, 4 ) != SPI_FLASH_RESULT_OK) {
929
+ return false ;
930
+ }
931
+ memcpy ((uint8_t *)data + currentOffset, &tempData, size - currentOffset);
932
+ }
933
+
934
+ return true ;
935
+ }
936
+
937
+ bool EspClass::flashRead (uint32_t address, uint32_t *data, size_t size) {
938
+ if ((uintptr_t )data % 4 != 0 || size % 4 != 0 ) {
939
+ return false ;
940
+ }
941
+ return (spi_flash_read (address, data, size) == SPI_FLASH_RESULT_OK);
728
942
}
729
943
730
944
String EspClass::getSketchMD5 ()
0 commit comments